-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f0b5ac2
commit 1c5665a
Showing
5 changed files
with
171 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -105,4 +105,5 @@ dist | |
.tern-port | ||
|
||
|
||
src/scripts/.env | ||
**/.env | ||
db.* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
import { ADDRESSES } from '@acala-network/asset-router/dist/consts'; | ||
import { AcalaJsonRpcProvider } from '@acala-network/eth-providers'; | ||
import { DOT, LCDOT_13 as LCDOT, LDOT } from '@acala-network/contracts/utils/AcalaTokens'; | ||
import { ERC20__factory } from '@certusone/wormhole-sdk/lib/cjs/ethers-contracts'; | ||
import { FeeRegistry__factory } from '@acala-network/asset-router/dist/typechain-types'; | ||
import { IHoma__factory } from '@acala-network/contracts/typechain'; | ||
import { ONE_ACA, almostEq, toHuman } from '@acala-network/asset-router/dist/utils'; | ||
import { Wallet } from 'ethers'; | ||
import { describe, expect, it } from 'vitest'; | ||
import { formatEther, parseEther, parseUnits } from 'ethers/lib/utils'; | ||
|
||
import { ETH_RPC, EUPHRATES_ADDR, EUPHRATES_POOLS } from '../consts'; | ||
import { HOMA } from '@acala-network/contracts/utils/Predeploy'; | ||
import { | ||
TEST_ADDR_RELAYER, | ||
TEST_ADDR_USER, | ||
TEST_KEY, | ||
} from './testConsts'; | ||
import { | ||
routeEuphrates, | ||
shouldRouteEuphrates, | ||
transferToRouter, | ||
} from './testUtils'; | ||
|
||
const providerAcalaFork = new AcalaJsonRpcProvider(ETH_RPC.LOCAL); | ||
const relayerAcalaFork = new Wallet(TEST_KEY.RELAYER, providerAcalaFork); // 0xe3234f433914d4cfCF846491EC5a7831ab9f0bb3 | ||
const userAcalaFork = new Wallet(TEST_KEY.USER, providerAcalaFork); // 0x0085560b24769dAC4ed057F1B2ae40746AA9aAb6 | ||
|
||
// [inToken, outToken] | ||
const WTDOT = '0xe1bd4306a178f86a9214c39abcd53d021bedb0f9'; | ||
const EUPHRAETS_POOL_INFO = { | ||
0: [LCDOT, LDOT], | ||
1: [LCDOT, WTDOT], | ||
2: [DOT, LDOT], | ||
3: [DOT, WTDOT], | ||
}; | ||
|
||
describe('/routeEuphrates', () => { | ||
const DOT_DECIMALS = 10; | ||
const homa = IHoma__factory.connect(HOMA, providerAcalaFork); | ||
const fee = FeeRegistry__factory.connect(ADDRESSES.ACALA_TESTNET.feeAddr, providerAcalaFork); | ||
const stakeAmount = 6; | ||
const parsedStakeAmount = parseUnits(String(stakeAmount), DOT_DECIMALS); | ||
let routerAddr: string; | ||
|
||
const fetchTokenBalances = async (pooId: string) => { | ||
if (!routerAddr) throw new Error('routerAddr not set'); | ||
|
||
const [inTokenAddr, outTokenAddr] = EUPHRAETS_POOL_INFO[pooId]; | ||
const inToken = ERC20__factory.connect(inTokenAddr, providerAcalaFork); | ||
const outToken = ERC20__factory.connect(outTokenAddr, providerAcalaFork); | ||
|
||
const [ | ||
userBalIn, | ||
relayerBalIn, | ||
routerBalIn, | ||
userBalOut, | ||
routerBalOut, | ||
euphratesBalOut, | ||
] = await Promise.all([ | ||
inToken.balanceOf(TEST_ADDR_USER), | ||
inToken.balanceOf(TEST_ADDR_RELAYER), | ||
inToken.balanceOf(routerAddr), | ||
outToken.balanceOf(TEST_ADDR_USER), | ||
outToken.balanceOf(routerAddr), | ||
outToken.balanceOf(EUPHRATES_ADDR), | ||
]); | ||
|
||
console.log({ | ||
userBalIn: toHuman(userBalIn, DOT_DECIMALS), | ||
relayerBalIn: toHuman(relayerBalIn, DOT_DECIMALS), | ||
routerBalIn: toHuman(routerBalIn, DOT_DECIMALS), | ||
userBalOut: toHuman(userBalOut, DOT_DECIMALS), | ||
routerBalOut: toHuman(routerBalOut, DOT_DECIMALS), | ||
euphratesBalOut: toHuman(euphratesBalOut, DOT_DECIMALS), | ||
}); | ||
|
||
return { | ||
userBalIn, | ||
relayerBalIn, | ||
routerBalIn, | ||
userBalOut, | ||
routerBalOut, | ||
euphratesBalOut, | ||
}; | ||
}; | ||
|
||
const testEuphratesRouter = async (poolId: string) => { | ||
const [inTokenAddr] = EUPHRAETS_POOL_INFO[poolId]; | ||
|
||
const relayerBal = await relayerAcalaFork.getBalance(); | ||
expect(relayerBal.gt(parseEther('10'))).to.be.true; | ||
|
||
const routeArgs = { | ||
recipient: userAcalaFork.address, | ||
poolId, | ||
}; | ||
const res = await shouldRouteEuphrates(routeArgs); | ||
({ routerAddr } = res.data); | ||
|
||
// make sure user has enough DOT to transfer to router | ||
const bal = await fetchTokenBalances(poolId); | ||
if (bal.userBalIn.lt(parsedStakeAmount)) { | ||
if (bal.relayerBalIn.lt(parsedStakeAmount)) { | ||
throw new Error(`both relayer and user do not have enough ${inTokenAddr} to transfer to router!`); | ||
} | ||
|
||
console.log('refilling dot for user ...'); | ||
const inToken = ERC20__factory.connect(inTokenAddr, relayerAcalaFork); | ||
await (await inToken.transfer(TEST_ADDR_USER, parsedStakeAmount)).wait(); | ||
} | ||
|
||
const bal0 = await fetchTokenBalances(poolId); | ||
|
||
console.log('transferring token to router ...'); | ||
await transferToRouter(routerAddr, userAcalaFork, inTokenAddr, stakeAmount); | ||
|
||
console.log('routing ...'); | ||
const routeRes = await routeEuphrates({ | ||
...routeArgs, | ||
token: inTokenAddr, | ||
}); | ||
const txHash = routeRes.data; | ||
console.log(`route finished! txHash: ${txHash}`); | ||
|
||
const bal1 = await fetchTokenBalances(poolId); | ||
|
||
// router should be destroyed | ||
const routerCode = await providerAcalaFork.getCode(routerAddr); | ||
expect(routerCode).to.eq('0x'); | ||
expect(bal1.routerBalIn.toNumber()).to.eq(0); | ||
|
||
// euphrate contract should receive Liquid Token | ||
const routingFee = await fee.getFee(inTokenAddr); | ||
const liquidTokenReceived = bal1.euphratesBalOut.sub(bal0.euphratesBalOut); | ||
|
||
if (['0', '2'].includes(poolId)) { | ||
// 10{18} DOT => ? LDOT | ||
const exchangeRate = parseEther( | ||
(1 / Number(formatEther(await homa.getExchangeRate()))).toString() | ||
); | ||
const liquidTokenExpected = parsedStakeAmount.sub(routingFee).mul(exchangeRate).div(ONE_ACA); | ||
expect(almostEq(liquidTokenExpected, liquidTokenReceived)).to.be.true; | ||
} else { | ||
// calculating exact tdot is out of scope of this test | ||
expect(liquidTokenReceived.toBigInt()).toBeGreaterThan(0); | ||
} | ||
expect(bal0.userBalIn.sub(bal1.userBalIn).toBigInt()).to.eq(parsedStakeAmount.toBigInt()); | ||
|
||
// relayer should receive DOT/LCDOT fee | ||
expect(bal1.relayerBalIn.sub(bal0.relayerBalIn).toBigInt()).to.eq(routingFee.toBigInt()); | ||
}; | ||
|
||
it('worked for all pools', async () => { | ||
for (const poolId of EUPHRATES_POOLS) { | ||
await testEuphratesRouter(poolId); | ||
} | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,17 +17,16 @@ | |
"@acala-network/api-derive" "6.0.4" | ||
"@acala-network/types" "6.0.4" | ||
|
||
"@acala-network/[email protected]-1": | ||
version "1.0.13-1" | ||
resolved "https://registry.yarnpkg.com/@acala-network/asset-router/-/asset-router-1.0.13-1.tgz#a5da78315335ce24cb289019f9ba8ac6af28423e" | ||
integrity sha512-zi2j3Nijn94DlgTu+NilHcb+6mWEIzInm+Gy66OmfQQAYbjG2X7gg45O5oyBPs6kClHrSf459zeAYMtobWb/Sg== | ||
"@acala-network/[email protected]": | ||
version "1.0.13" | ||
resolved "https://registry.yarnpkg.com/@acala-network/asset-router/-/asset-router-1.0.13.tgz#0ad0e8ce8bd462a7291a6bf8f951bd24f83ea0e4" | ||
integrity sha512-J0W5MSVKYIz/cgx9KVCqe9NLkg+FdRrAl6BqCZzZkj8JPcQhUlxgW7TP/s3yYr/5MXk3wDb69z/f2cBWGjhbxw== | ||
dependencies: | ||
"@acala-network/contracts" "^4.5.0" | ||
"@acala-network/eth-providers" "^2.7.13" | ||
"@certusone/wormhole-sdk" "^0.9.11" | ||
"@ethersproject/abi" "^5.7.0" | ||
"@ethersproject/providers" "^5.7.0" | ||
"@openzeppelin/contracts" "^5.0.1" | ||
"@polkadot/util-crypto" "^12.5.1" | ||
ethers "^5.7.0" | ||
|
||
|
@@ -1293,11 +1292,6 @@ | |
resolved "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.18.1.tgz#8e47caf57a84b1dcc1722b2025693348cdf443b4" | ||
integrity sha512-+NLGHr6VZwcgE/2lw8zDIufOCGnzsA5CbQIMleXZTrgkBd0TanCX+MiDYJ1TOS4KL/Tqk0nFRxawnaYr6pkZkA== | ||
|
||
"@openzeppelin/contracts@^5.0.1": | ||
version "5.0.1" | ||
resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-5.0.1.tgz#93da90fc209a0a4ff09c1deb037fbb35e4020890" | ||
integrity sha512-yQJaT5HDp9hYOOp4jTYxMsR02gdFZFXhewX5HW9Jo4fsqSVqqyIO/xTHdWDaKX5a3pv1txmf076Lziz+sO7L1w== | ||
|
||
"@polka/url@^1.0.0-next.20": | ||
version "1.0.0-next.21" | ||
resolved "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" | ||
|