Skip to content

Commit

Permalink
support swap and route (#63)
Browse files Browse the repository at this point in the history
  • Loading branch information
shunjizhan committed Jun 14, 2024
1 parent 9581f30 commit c9b6723
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 8 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "acala-wormhole-relayer",
"version": "1.7.0-1",
"version": "1.8.0-0",
"description": "",
"main": "lib/index.js",
"types": "lib/index.d.ts",
Expand All @@ -22,7 +22,7 @@
},
"dependencies": {
"@acala-network/api": "~6.0.4",
"@acala-network/asset-router": "~1.0.17",
"@acala-network/asset-router": "~1.0.18-1",
"@acala-network/bodhi": "~2.7.13",
"@acala-network/contracts": "^4.5.0",
"@acala-network/eth-providers": "~2.7.14",
Expand Down
95 changes: 95 additions & 0 deletions src/api/swapAndRoute.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { ACA } from '@acala-network/contracts/utils/AcalaTokens';
import { ERC20__factory } from '@certusone/wormhole-sdk/lib/cjs/ethers-contracts';
import { SwapAndStakeEuphratesFactory__factory } from '@acala-network/asset-router/dist/typechain-types';
import { constants } from 'ethers';

import { EUPHRATES_ADDR, EUPHRATES_POOLS, RELAYER_ADDR } from '../consts';
import {
Mainnet,
RouteError,
SwapAndRouteParams,
_populateRelayTx,
_populateRouteTx,
getChainConfig,
getMainnetChainId,
} from '../utils';

const DEFAULT_SWAP_AND_ROUTE_PARAMS = {
maker: RELAYER_ADDR,
targetToken: ACA,
euphrates: EUPHRATES_ADDR,
};

const prepareSwapAndRoute = async (chain: Mainnet) => {
const chainId = getMainnetChainId(chain);
const chainConfig = await getChainConfig(chainId);
const { feeAddr, swapAndStakeFactoryAddr, wallet } = chainConfig;

const factory = SwapAndStakeEuphratesFactory__factory
.connect(swapAndStakeFactoryAddr!, wallet);

return { factory, feeAddr };
};

export const shouldSwapAndRoute = async (params: SwapAndRouteParams) => {
try {
const { factory, feeAddr } = await prepareSwapAndRoute(Mainnet.Acala);
if (!EUPHRATES_POOLS.includes(params.poolId)) {
throw new RouteError(`euphrates poolId ${params.poolId} is not supported`, params);
}

const insts = {
...DEFAULT_SWAP_AND_ROUTE_PARAMS,
...params,
};

/* ---------- TODO: remove this check later after approved max ---------- */
const { targetAmount } = params;
if (targetAmount) {
const aca = ERC20__factory.connect(ACA, factory.signer);
const allowance = await aca.allowance(insts.maker, factory.address);
if (allowance.lt(targetAmount)) {
await (await aca.approve(factory.address, constants.MaxUint256)).wait();
}
}
/* ----------------------------------------------------------------------- */

const routerAddr = await factory.callStatic.deploySwapAndStakeEuphratesRouter(
feeAddr,
insts,
params.targetAmount ?? 0,
);

return {
shouldRoute: true,
routerAddr,
};
} catch (err) {
return {
shouldRoute: false,
msg: err.message,
};
}
};

export const swapAndRoute = async (params: SwapAndRouteParams) => {
if (params.token === undefined) {
throw new RouteError('<token> param is required for swap and route', params);
}

const insts = {
...DEFAULT_SWAP_AND_ROUTE_PARAMS,
...params,
};

const { factory, feeAddr } = await prepareSwapAndRoute(Mainnet.Acala);
const tx = await factory.deploySwapAndStakeEuphratesRouterAndRoute(
feeAddr,
insts,
params.token,
params.targetAmount ?? 0,
);
const receipt = await tx.wait();

return receipt.transactionHash;
};
6 changes: 4 additions & 2 deletions src/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,13 @@ export const TESTNET_MODE_WARNING = `
`;

export const EUPHRATES_ADDR = '0x7Fe92EC600F15cD25253b421bc151c51b0276b7D';
export const EUPHRATES_POOLS = ['0', '1', '2', '3'];
export const EUPHRATES_POOLS = ['0', '1', '2', '3', '7'];

export const RELAYER_ADDR = '0x8B5C2F71eFa2d88A20E0e1c8EDFeA3767B2ab230';

export const SECOND = 1000;
export const MINUTE = 60 * SECOND;
export const HOUR = 60 * MINUTE;
export const DAY = 24 * HOUR;

export const VERSION = '1.7.0-1';
export const VERSION = '1.8.0-0';
10 changes: 10 additions & 0 deletions src/middlewares/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ import {
logger,
NoRouteError,
routeStatusSchema,
swapAndRouteSchema,
} from '../utils';
import { shouldSwapAndRoute, swapAndRoute } from '../api/swapAndRoute';

interface RouterConfig {
schema?: Schema;
Expand Down Expand Up @@ -55,6 +57,10 @@ const ROUTER_CONFIGS: {
schema: routeEuphratesSchema,
handler: shouldRouteEuphrates,
},
'/shouldSwapAndRoute': {
schema: swapAndRouteSchema,
handler: shouldSwapAndRoute,
},
'/health': {
handler: healthCheck,
},
Expand Down Expand Up @@ -96,6 +102,10 @@ const ROUTER_CONFIGS: {
schema: routeEuphratesSchema,
handler: routeEuphrates,
},
'/swapAndRoute': {
schema: swapAndRouteSchema,
handler: swapAndRoute,
},
},
};

Expand Down
1 change: 1 addition & 0 deletions src/utils/configureEnv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export type ChainConfig = {
homaFactoryAddr?: string;
accountHelperAddr?: string;
euphratesFactoryAddr?: string;
swapAndStakeFactoryAddr?: string;
isTestnet: boolean;
};

Expand Down
18 changes: 18 additions & 0 deletions src/utils/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ export interface RouteParamsEuphrates {
token?: string; // token to route, not required for `shouldRoute`
}

export interface SwapAndRouteParams {
poolId: string; // euphrates pool id
recipient: string; // dest evm address
supplyAmount: string; // swap tokenIn amount
token?: string; // token to route, not required for `shouldRoute`
targetToken?: string; // swap tokenOut address, default: ACA address
targetAmount?: string; // swap tokenOut amount (with erc20 decimals)
}

export interface RelayAndRouteParams extends RouteParamsXcm {
signedVAA: string;
}
Expand Down Expand Up @@ -82,6 +91,15 @@ export const routeEuphratesSchema: ObjectSchema<RouteParamsEuphrates> = object({
token: string(),
});

export const swapAndRouteSchema: ObjectSchema<SwapAndRouteParams> = object({
poolId: string().required(),
recipient: string().required(),
supplyAmount: string().required(),
token: string(),
targetToken: string(),
targetAmount: string(),
});

export const routeStatusSchema: ObjectSchema<routeStatusParams> = object({
id: string(),
destAddr: string(),
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
"@acala-network/api-derive" "6.0.4"
"@acala-network/types" "6.0.4"

"@acala-network/asset-router@~1.0.17":
version "1.0.17"
resolved "https://registry.yarnpkg.com/@acala-network/asset-router/-/asset-router-1.0.17.tgz#46d6badafc3a7955e309ecc894f01f3461eb05cb"
integrity sha512-FfkGNEEH7xJ1UxOt/L42RnOrhol8mp3j8x1z1qtUh+B0ezkUIeQNkzhoHq8UlysZ5PiYw3MtfYUJV2BQLy2jPA==
"@acala-network/asset-router@~1.0.18-1":
version "1.0.18-1"
resolved "https://registry.yarnpkg.com/@acala-network/asset-router/-/asset-router-1.0.18-1.tgz#f31920c99dc29c5143e544f667a362bd5d797b89"
integrity sha512-xGTna87yObxvR0ISXXULPvkTCGJ5W53ewad2P3Y7EmjAsxct7tPq9+8nxpthDQ1dLfcj2Hcxr3nMUgmreR/vDA==
dependencies:
"@acala-network/contracts" "^4.5.0"
"@acala-network/eth-providers" "^2.7.13"
Expand Down

0 comments on commit c9b6723

Please sign in to comment.