Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Amped Finance #43

Open
wants to merge 26 commits into
base: main
Choose a base branch
from

Conversation

AmpedFinance
Copy link

@AmpedFinance AmpedFinance commented Jan 25, 2025

Amped Finance Integration

Description

Implementation of Amped Finance perpetual swaps and AMM exchange integration:

Core Features

✅ Liquidity Operations

  • Add/Remove liquidity (Single token operations)
  • ALP token management
  • Liquidity pool balance tracking

✅ Leveraged Trading

  • Long position management
  • Position size/leverage validation

✅ Information Services

  • Real-time position tracking
  • Liquidity pool analytics
  • Return estimation calculators

✅ Risk Management

  • Slippage protection (0.3% default)
  • Leverage limits enforcement
  • Position size validation

Technical Improvements

Enhanced error handling with contextual messages
Robust input validation for financial operations
Type-safe implementations for core operations
Gas-optimized transaction building
Comprehensive response formatting

Supported Networks

Sonic (Mainnet)

Test Results

All core test suites passing (6/6):

  • ✅ Liquidity Operations
  • ✅ Position Management
  • ✅ Trading Validation
  • ✅ Risk Parameters
  • ✅ Information Queries
  • ✅ Error Handling

Implementation Details

Modular architecture with separated concerns:

  • Liquidity management module
  • Perpetual trading engine
  • Risk management system

Features

  • Leveraged perpetual trading (up to 11x)
  • Single-asset liquidity provisioning
  • Real-time position monitoring
  • ALP token redemption
  • Collateral management
  • Risk parameter enforcement
  • Position P&L calculations

Next Steps

  • Limit orders implementation
  • Trigger orders for TP and SL
  • Partial close of open positions

References
Amped Finance
Protocol Type: Decentralized Perpetual Exchange
Twitter: @AmpedFinance
Documentation: https://amped.gitbook.io/amped/

@AmpedFinance AmpedFinance changed the title feat: [WIP] Amped Finance integration feat: Amped Finance integration Feb 2, 2025
@AmpedFinance AmpedFinance changed the title feat: Amped Finance integration feat: Amped Finance Feb 2, 2025
* @returns Transaction result
*/
export async function example({ chainName, account, amount }: Props, { notify, getProvider }: FunctionOptions): Promise<FunctionReturn> {
// Validate chain
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, but we need remove example from prod

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point, deleted

},
],
required: ['chainName', 'account', 'tokenIn'],
parameters: {
Copy link
Contributor

@OoXooOx OoXooOx Feb 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#36 (comment) you can't omit optional args

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, yes I think these were treated as optional as we default them to a null value if not provided
I have included each of these arguments as required now

}) as bigint;

await notify(`Native price: ${nativePrice.toString()}`);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pls change this. notify(Native price: ${nativePrice.toString()}); for notify(Native price from Amped Finance: ${nativePrice.toString()});

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok


// Price is in 1e30, balance in 1e18, result should be in USD
const nativeBalanceUsd = (Number(nativeBalanceBigInt) * Number(nativePrice)) / 1e48;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you have problem here. JavaScript Number (IEEE 754) cannot accurately represent values beyond 2^53 - 1 (~9 quadrillion). Consider use bigint

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated accordingly

const nativeBalanceUsd = (Number(nativeBalanceBigInt) * Number(nativePrice)) / 1e48;

await notify(`Native balance USD: ${nativeBalanceUsd}`);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same. change notify

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

abi: ERC20,
functionName: 'balanceOf',
args: [account],
}) as bigint;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use multicall or await Promise.all

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, updated to use Promise.all

}) as bigint;

// Price is in 1e30, balance in token decimals, result should be in USD
const balanceUsd = (Number(balance) * Number(price)) / (Math.pow(10, token.decimals) * 1e30);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same problem

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved

*/
export async function addLiquidity(
{ chainName, account, tokenSymbol, amount, percentOfBalance = 25, minUsdg = '0', minGlp = '0' }: Props,
{ getProvider, notify, sendTransactions }: FunctionOptions,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not really good way by default without any warning ask 25% of balance from user. Suggest change percentOfBalance from optional to required and ask user input proper amount.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I think this was implemented this way for testing purposes.
We have now asked that the user provide either a % of the token balance or an exact amount

// Warn if price impact is high
if (priceImpact > 1) {
await notify(`Warning: High price impact (${priceImpact.toFixed(2)}%). Consider reducing the amount.`);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thx for adding necessary checks. Rest, almost all don't do this.

const provider = getProvider(chainId);

// Check token approval if not native token
if (tokenIn !== CONTRACT_ADDRESSES[NETWORKS.SONIC].NATIVE_TOKEN) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you treat wrapped as native, so actually you NEED approve in that case too. Isn't it?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You make a good point, I was implementing NATIVE as wrapped native. I have separated the two tokens now.

adding S as liquidity as native token is fine
adding wS will check for approval before adding to the pool

await notify('Checking token approval...');

// Check current allowance for RewardRouterV2
const allowance = await provider.readContract({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just use checkApprove function. This function check allowance and add to transaction array tx for approve and return transaction array for your function for further fill.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, have done this

await notify(`Approval transaction submitted. Waiting for confirmation...`);

// Wait for approval to be confirmed before proceeding
await provider.waitForTransactionReceipt({ hash: approvalTx.data[0].hash });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you definitely don't need do this waitForTransactionReceipt

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

// Prepare transaction data
const txData: TransactionParams = {
target: CONTRACT_ADDRESSES[NETWORKS.SONIC].REWARD_ROUTER,
value: tokenIn === CONTRACT_ADDRESSES[NETWORKS.SONIC].NATIVE_TOKEN ? parsedAmount : 0n,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you need work with native you can use const NATIVE_ADDRESS: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE". Are you sure that you don't have here problem for sending msg.value?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the native address to handle separately now


// Send transaction
await notify('Executing transaction...');
const txResult = await sendTransactions({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const result: TransactionReturn = await sendTransactions({ chainId, account, transactions });
const stakeData = result.data[result.data.length - 1];
if (result.isMultisig) {
return toResult(stakeData.message);
}
// Get transaction receipt and parse Transfer event
if (!stakeData.hash) return toResult(`Staked ${formatEther(amountInWei)} WAGMI to sWAGMI on ${chainName}, but failed to receive tx hash. ${stakeData.message}`);
const receipt = await provider.getTransactionReceipt({ hash: stakeData.hash });
const transferEvents = parseEventLogs({
logs: receipt.logs,
abi: sWagmiAbi,
eventName: 'Transfer',
});
const stakeEvent = transferEvents.find((log) => log.args.from === zeroAddress);
if (!stakeEvent?.args?.value) {
return toResult(`Staked ${formatEther(amountInWei)} WAGMI to sWAGMI on ${chainName}, but couldn't verify received sWAGMI amount. ${stakeData.message}`);
}
const stakedAmount = formatEther(stakeEvent.args.value);
return toResult(`Staked ${formatEther(amountInWei)} WAGMI and received ${stakedAmount} sWAGMI on ${chainName}. ${stakeData.message}`);
check this for work with events

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have implemented this


try {
const publicClient = getProvider(chainId);
const amountInWei = parseUnits(amount, 18);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider check amountInWei > 0n

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants