Skip to content

Commit

Permalink
Merge branch 'alpha'
Browse files Browse the repository at this point in the history
  • Loading branch information
AntonKozAllB committed Jul 18, 2024
2 parents 691f69f + 9694eae commit c9cab20
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 57 deletions.
1 change: 1 addition & 0 deletions src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ describe("SDK", () => {
cctpTransmitterProgramId: "",
cctpTokenMessengerMinter: "",
},
cachePoolInfoChainSec: 20,
};
beforeEach(() => {
sdk = new AllbridgeCoreSdk(testNodeUrls, testConfig);
Expand Down
1 change: 1 addition & 0 deletions src/configs/mainnet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const mainnet: AllbridgeCoreSdkOptions = {
cctpTokenMessengerMinter: "CCTPiPYPc6AsJuwueEnWgSgucamXDZwBd53dQ11YiKX3",
cctpDomains: { ETH: 0, AVA: 1, OPT: 2, ARB: 3, SOL: 5, BAS: 6, POL: 7 },
},
cachePoolInfoChainSec: 20,
};

/**
Expand Down
1 change: 1 addition & 0 deletions src/configs/testnet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const testnet: AllbridgeCoreSdkOptions = {
cctpTokenMessengerMinter: "CCTPiPYPc6AsJuwueEnWgSgucamXDZwBd53dQ11YiKX3",
cctpDomains: { SPL: 0, ARB: 3, AMO: 7 },
},
cachePoolInfoChainSec: 20,
};

/**
Expand Down
6 changes: 6 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ export interface AllbridgeCoreSdkOptions {
*/
tronJsonRpc?: string;
cctpParams: CctpParams;
/**
* The number of seconds that pool information taken from the chain will be cached.
*
* @type {number}
*/
cachePoolInfoChainSec: number;
}

/**
Expand Down
123 changes: 87 additions & 36 deletions src/services/bridge/sol/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import { RawTransaction, TransactionResponse } from "../../models";
import { SwapAndBridgeSolData, SwapAndBridgeSolDataCctpData } from "../../models/sol";
import { Bridge as BridgeType, IDL as bridgeIdl } from "../../models/sol/types/bridge";
import { CctpBridge as CctpBridgeType, IDL as cctpBridgeIdl } from "../../models/sol/types/cctp_bridge";
import { GasOracle as GasOracleType, IDL as gasOracleIdl } from "../../models/sol/types/gas_oracle";
import { getMessage, getTokenAccountData, getVUsdAmount } from "../../utils/sol";
import {
getAssociatedAccount,
Expand Down Expand Up @@ -74,6 +73,8 @@ export type CctpDomains = {

const COMPUTE_UNIT_LIMIT = 1000000;

const JUP_ADD_INDEX = 1.1;

export class SolanaBridgeService extends ChainBridgeService {
chainType: ChainType.SOLANA = ChainType.SOLANA;
jupiterService: JupiterService;
Expand Down Expand Up @@ -188,39 +189,23 @@ export class SolanaBridgeService extends ChainBridgeService {
let jupTx;
if (isJupiterForStableCoin) {
try {
let amountToSwap = Big(solTxSendParams.fee);
if (solTxSendParams.extraGas) {
amountToSwap = amountToSwap.plus(solTxSendParams.extraGas);
}

solTxSendParams = await this.convertStableCoinFeeAndExtraGasToNativeCurrency(
params.sourceToken.decimals,
solTxSendParams
);

const { tx } = await this.jupiterService.getJupiterSwapTx(
params.fromAccountAddress,
params.sourceToken.tokenAddress,
amountToSwap.toFixed(0)
);
const { tx, solTxSendUpdatedParams } = await this.processJup(solTxSendParams, params, true);
jupTx = tx;
solTxSendParams.amount = Big(solTxSendParams.amount).minus(amountToSwap).toFixed(0);
if (Big(solTxSendParams.amount).lte(0)) {
throw new AmountNotEnoughError(
`Amount not enough to pay fee, ${convertIntAmountToFloat(
Big(solTxSendParams.amount).minus(1).neg(),
params.sourceToken.decimals
).toFixed()} stables is missing`
);
}
solTxSendParams = { ...solTxSendParams, ...solTxSendUpdatedParams };
} catch (e) {
if (e instanceof SdkRootError) {
throw e;
try {
const { tx, solTxSendUpdatedParams } = await this.processJup(solTxSendParams, params, false);
jupTx = tx;
solTxSendParams = { ...solTxSendParams, ...solTxSendUpdatedParams };
} catch (e) {
if (e instanceof SdkRootError) {
throw e;
}
if (e instanceof Error && e.message) {
throw new JupiterError(`Some error occurred during creation Jupiter swap transaction. ${e.message}`);
}
throw new JupiterError("Some error occurred during creation Jupiter swap transaction");
}
if (e instanceof Error && e.message) {
throw new JupiterError(`Some error occurred during creation Jupiter swap transaction. ${e.message}`);
}
throw new JupiterError("Some error occurred during creation Jupiter swap transaction");
}
}

Expand Down Expand Up @@ -266,6 +251,67 @@ export class SolanaBridgeService extends ChainBridgeService {
return swapAndBridgeTx;
}

private async processJup(
solTxSendParams: SolTxSendParams,
params: SendParams,
exactOut: boolean
): Promise<{
tx: VersionedTransaction;
solTxSendUpdatedParams: {
amount: string;
fee: string;
extraGas?: string;
gasFeePaymentMethod: FeePaymentMethod;
};
}> {
const { fee, extraGas, gasFeePaymentMethod } = await this.convertStableCoinFeeAndExtraGasToNativeCurrency(
params.sourceToken.decimals,
solTxSendParams
);

let amountToProcess = exactOut ? Big(fee) : Big(solTxSendParams.fee);
if (extraGas) {
amountToProcess = amountToProcess.plus(extraGas);
}
if (!exactOut) {
amountToProcess = amountToProcess.mul(JUP_ADD_INDEX);
}

const { tx, amountIn } = await this.jupiterService.getJupiterSwapTx(
params.fromAccountAddress,
params.sourceToken.tokenAddress,
amountToProcess.toFixed(0),
exactOut
);

let newAmount: string;
if (exactOut) {
if (!amountIn) {
throw new JupiterError("Cannot get inAmount");
}
newAmount = Big(solTxSendParams.amount).minus(amountIn).toFixed(0);
} else {
newAmount = Big(solTxSendParams.amount).minus(amountToProcess).toFixed(0);
}
if (Big(newAmount).lte(0)) {
throw new AmountNotEnoughError(
`Amount not enough to pay fee, ${convertIntAmountToFloat(
Big(newAmount).minus(1).neg(),
params.sourceToken.decimals
).toFixed()} stables is missing`
);
}
return {
tx: tx,
solTxSendUpdatedParams: {
amount: newAmount,
fee: fee,
extraGas: extraGas,
gasFeePaymentMethod: gasFeePaymentMethod,
},
};
}

private addPoolAddress(params: SendParams, txSendParams: TxSendParams): SolTxSendParams {
return {
...txSendParams,
Expand All @@ -276,7 +322,7 @@ export class SolanaBridgeService extends ChainBridgeService {
async convertStableCoinFeeAndExtraGasToNativeCurrency(
tokenDecimals: number,
solTxSendParams: SolTxSendParams
): Promise<SolTxSendParams> {
): Promise<{ fee: string; extraGas?: string; gasFeePaymentMethod: FeePaymentMethod }> {
if (solTxSendParams.gasFeePaymentMethod == FeePaymentMethod.WITH_STABLECOIN) {
const sourceNativeTokenPrice = (
await this.api.getReceiveTransactionCost({
Expand All @@ -285,19 +331,24 @@ export class SolanaBridgeService extends ChainBridgeService {
messenger: solTxSendParams.messenger,
})
).sourceNativeTokenPrice;
solTxSendParams.fee = Big(solTxSendParams.fee)
const fee = Big(solTxSendParams.fee)
.div(sourceNativeTokenPrice)
.mul(Big(10).pow(ChainDecimalsByType[ChainType.SOLANA] - tokenDecimals))
.toFixed(0);
let extraGas;
if (solTxSendParams.extraGas) {
solTxSendParams.extraGas = Big(solTxSendParams.extraGas)
extraGas = Big(solTxSendParams.extraGas)
.div(sourceNativeTokenPrice)
.mul(Big(10).pow(ChainDecimalsByType[ChainType.SOLANA] - tokenDecimals))
.toFixed(0);
}
solTxSendParams.gasFeePaymentMethod = FeePaymentMethod.WITH_NATIVE_CURRENCY;
return { fee, extraGas, gasFeePaymentMethod: FeePaymentMethod.WITH_NATIVE_CURRENCY };
}
return solTxSendParams;
return {
fee: solTxSendParams.fee,
extraGas: solTxSendParams.extraGas,
gasFeePaymentMethod: FeePaymentMethod.WITH_NATIVE_CURRENCY,
};
}

private getExtraGasInstruction(
Expand Down
31 changes: 20 additions & 11 deletions src/services/bridge/sol/jupiter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,16 @@ export class JupiterService {
async getJupiterSwapTx(
userAddress: string,
stableTokenAddress: string,
amount: string
): Promise<{ tx: VersionedTransaction }> {
amount: string,
exactOut: boolean
): Promise<{ tx: VersionedTransaction; amountIn?: string }> {
let quoteResponse: any;
try {
const swapMode = exactOut ? "ExactOut" : "ExactIn";
quoteResponse = await axios.get(`${this.jupiterUrl}/quote?inputMint=${stableTokenAddress}
&outputMint=${NATIVE_MINT.toString()}
&amount=${amount}
&swapMode=${swapMode}
&slippageBps=100
&onlyDirectRoutes=true`);
} catch (err) {
Expand All @@ -32,16 +35,20 @@ export class JupiterService {
throw new JupiterError("Cannot get route");
}

let inAmount;
if (exactOut && quoteResponse?.data?.inAmount) {
inAmount = quoteResponse.data.inAmount;
} else if (exactOut) {
throw new JupiterError("Cannot get inAmount");
}

let transactionResponse: any;
try {
transactionResponse = await axios.post(
`${this.jupiterUrl}/swap`,
JSON.stringify({
quoteResponse: quoteResponse.data,
userPublicKey: userAddress,
wrapAndUnwrapSol: true,
})
);
transactionResponse = await axios.post(`${this.jupiterUrl}/swap`, {
quoteResponse: quoteResponse.data,
userPublicKey: userAddress,
wrapAndUnwrapSol: true,
});
} catch (err) {
if (err instanceof AxiosError && err.response && err.response.data && err.response.data.error) {
throw new JupiterError(err.response.data.error);
Expand All @@ -57,7 +64,9 @@ export class JupiterService {
}

const swapTransactionBuf = Buffer.from(swapTransaction, "base64");
return { tx: VersionedTransaction.deserialize(swapTransactionBuf) };
const tx = VersionedTransaction.deserialize(swapTransactionBuf);

return exactOut ? { tx, amountIn: inAmount } : { tx };
}

async amendJupiterWithSdkTx(
Expand Down
31 changes: 21 additions & 10 deletions src/services/liquidity-pool/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Big } from "big.js";
import Cache from "timed-cache";
// @ts-expect-error import tron
import TronWeb from "tronweb";
import Web3 from "web3";
Expand All @@ -7,7 +8,7 @@ import { chainProperties, ChainSymbol, ChainType } from "../../chains";
import { AllbridgeCoreClient } from "../../client/core-api";
import { AllbridgeCoreClientPoolInfoCaching } from "../../client/core-api/core-client-pool-info-caching";
import { AllbridgeCoreSdkOptions } from "../../index";
import { PoolInfo, TokenWithChainDetails } from "../../tokens-info";
import { PoolInfo, PoolKeyObject, TokenWithChainDetails } from "../../tokens-info";
import { convertIntAmountToFloat, fromSystemPrecision } from "../../utils/calculation";
import { SYSTEM_PRECISION } from "../../utils/calculation/constants";
import { validateAmountDecimals, validateAmountGtZero } from "../../utils/utils";
Expand Down Expand Up @@ -113,6 +114,7 @@ export interface LiquidityPoolService {

export class DefaultLiquidityPoolService implements LiquidityPoolService {
public rawTxBuilder: RawPoolTransactionBuilder;
private cache: Cache<PoolInfo>;

constructor(
private api: AllbridgeCoreClientPoolInfoCaching,
Expand All @@ -121,6 +123,8 @@ export class DefaultLiquidityPoolService implements LiquidityPoolService {
private tokenService: TokenService
) {
this.rawTxBuilder = new DefaultRawPoolTransactionBuilder(api, nodeRpcUrlsConfig, this.params, tokenService);
const ttl = params.cachePoolInfoChainSec > 0 ? params.cachePoolInfoChainSec * 1000 : 20 * 1000;
this.cache = new Cache<PoolInfo>({ defaultTtl: ttl });
}

async getAllowance(a: Provider | GetAllowanceParams, b?: GetAllowanceParams): Promise<string> {
Expand Down Expand Up @@ -190,15 +194,22 @@ export class DefaultLiquidityPoolService implements LiquidityPoolService {
}

async getPoolInfoFromChain(token: TokenWithChainDetails, provider?: Provider): Promise<PoolInfo> {
const poolInfo = await getChainPoolService(
token.chainSymbol,
this.api,
this.nodeRpcUrlsConfig,
this.params,
provider
).getPoolInfoFromChain(token);
this.api.cachePut({ chainSymbol: token.chainSymbol, poolAddress: token.poolAddress }, poolInfo);
return poolInfo;
const poolKey: PoolKeyObject = { chainSymbol: token.chainSymbol, poolAddress: token.poolAddress };
const fromCache = this.cache.get(poolKey);
if (fromCache) {
return fromCache;
} else {
const poolInfo = await getChainPoolService(
token.chainSymbol,
this.api,
this.nodeRpcUrlsConfig,
this.params,
provider
).getPoolInfoFromChain(token);
this.cache.put(poolKey, poolInfo);
this.api.cachePut({ chainSymbol: token.chainSymbol, poolAddress: token.poolAddress }, poolInfo);
return poolInfo;
}
}
}

Expand Down

0 comments on commit c9cab20

Please sign in to comment.