Pnuttaste/Interchain-message/test/RubicCrossChainV3.spec.ts
Mista J df8039f494 new file: Interchain-message/.env.example
new file:   Interchain-message/.eslintrc.js
	new file:   Interchain-message/.gitignore
	new file:   Interchain-message/.prettierrc
	new file:   Interchain-message/.solhint.json
	new file:   Interchain-message/.solhintignore
	new file:   Interchain-message/contracts/interfaces/IBridge.sol
	new file:   Interchain-message/contracts/interfaces/IMessageBus.sol
	new file:   Interchain-message/contracts/interfaces/IMessageReceiverApp.sol
	new file:   Interchain-message/contracts/interfaces/IUniswapRouterV3.sol
	new file:   Interchain-message/contracts/interfaces/IWETH.sol
	new file:   Interchain-message/contracts/message/apps/BridgeSwap.sol
	new file:   Interchain-message/contracts/message/apps/RubicRouterV2.sol
	new file:   Interchain-message/contracts/message/apps/RubicRouterV2ETH.sol
	new file:   Interchain-message/contracts/message/apps/SwapBase.sol
	new file:   Interchain-message/contracts/message/apps/TransferSwapInch.sol
	new file:   Interchain-message/contracts/message/apps/TransferSwapV2.sol
	new file:   Interchain-message/contracts/message/apps/TransferSwapV3.sol
	new file:   Interchain-message/contracts/message/framework/MessageReceiverApp.sol
	new file:   Interchain-message/contracts/message/framework/MessageSenderApp.sol
	new file:   Interchain-message/contracts/message/libraries/MessageSenderLib.sol
	new file:   Interchain-message/contracts/message/libraries/MsgDataTypes.sol
	new file:   Interchain-message/contracts/test/MessageBusSender.sol
	new file:   Interchain-message/contracts/test/TestERC20.sol
	new file:   Interchain-message/contracts/test/TestMessages.sol
	new file:   Interchain-message/contracts/test/WETH9.sol
	new file:   Interchain-message/deployments/Readme.md
	new file:   Interchain-message/executor/config/cbridge.toml
	new file:   Interchain-message/executor/config/executor.toml
	new file:   Interchain-message/executor/eth-ks/signer.json
	new file:   Interchain-message/hardhat.config.ts
	new file:   Interchain-message/package-lock.json
	new file:   Interchain-message/package.json
	new file:   Interchain-message/reports/contract_sizes.txt
	new file:   Interchain-message/reports/gas_usage/summary.txt
	new file:   Interchain-message/scripts/deploy/deploy.js
	new file:   Interchain-message/scripts/deploy/deployAVAX.ts
	new file:   Interchain-message/scripts/deploy/deployArbitrum.ts
	new file:   Interchain-message/scripts/deploy/deployAurora.ts
	new file:   Interchain-message/scripts/deploy/deployBSC.ts
	new file:   Interchain-message/scripts/deploy/deployEth.ts
	new file:   Interchain-message/scripts/deploy/deployFantom.ts
	new file:   Interchain-message/scripts/deploy/deployPoly.ts
	new file:   Interchain-message/scripts/privateKey.js
	new file:   Interchain-message/scripts/sendTx/avaxToFantomBridge.js
	new file:   Interchain-message/scripts/sendTx/avaxToFantomNativeV2.js
	new file:   Interchain-message/test/RubicCrossChainBridge.spec.ts
	new file:   Interchain-message/test/RubicCrossChainV2.spec.ts
	new file:   Interchain-message/test/RubicCrossChainV3.spec.ts
	new file:   Interchain-message/test/RubicFallback.spec.ts
	new file:   Interchain-message/test/RubicSettings.spec.ts
	new file:   Interchain-message/test/shared/consts.ts
	new file:   Interchain-message/test/shared/fixtures.ts
	new file:   Interchain-message/test/shared/utils.ts
	new file:   Interchain-message/tsconfig.json
	deleted:    Rubic-Inter-chain-Message-develop.zip
	deleted:    proxy-instant-trades-master.zip
	deleted:    rubic-app-master.zip
	deleted:    rubic-sdk-master.zip
2024-07-09 17:32:00 -04:00

548 lines
21 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { ethers, network, waffle } from 'hardhat';
import { swapContractFixtureInFork } from './shared/fixtures';
import { Wallet } from '@ethersproject/wallet';
import { RubicRouterV2, TestERC20, TestMessages, WETH9 } from '../typechain';
import { expect } from 'chai';
import {
DEADLINE,
DST_CHAIN_ID,
DEFAULT_AMOUNT_IN,
VERSION_V2,
VERSION_V3,
ZERO_ADDRESS,
DEFAULT_AMOUNT_OUT_MIN,
EXECUTOR_ADDRESS,
INTEGRATOR,
MESSAGE_BUS_FEE
} from './shared/consts';
import { BigNumber as BN, BigNumberish, ContractTransaction, BytesLike } from 'ethers';
import { calcCryptoFees, calcTokenFees } from 'rubic-bridge-base/lib';
// import { getRouterV3 } from './shared/utils';
const hre = require('hardhat');
const createFixtureLoader = waffle.createFixtureLoader;
const envConfig = require('dotenv').config();
const {
ROUTERS_POLYGON: TEST_ROUTERS,
NATIVE_POLYGON: TEST_NATIVE,
BUS_POLYGON_MAIN: TEST_BUS
} = envConfig.parsed || {};
describe('RubicCrossChainV3', () => {
let wallet: Wallet, other: Wallet;
let swapToken: TestERC20;
let transitToken: TestERC20;
let swapMain: RubicRouterV2;
let router: string;
let routerV3: string;
let wnative: WETH9;
let testMessagesContract: TestMessages;
let loadFixture: ReturnType<typeof createFixtureLoader>;
// async function toBytes32(address): Promise<string> {
// return '0x000000000000000000000000' + address.slice(2, address.length);
// }
async function encodePath(tokens): Promise<string> {
return tokens[0] + '000bb8' + tokens[1].slice(2);
}
// function encodePathReverse(tokens){
// const zeros = '0'.repeat(24)
// return (tokens[1] + '000bb8' + tokens[0].slice(2))
// }
async function callTransferWithSwapV3Native(
amountOutMinimum: BigNumberish,
srcPathBytes: BytesLike,
{
receiver = null,
amountIn = DEFAULT_AMOUNT_IN,
dstChainID = DST_CHAIN_ID,
srcDEX = routerV3,
nativeIn = null,
integrator = INTEGRATOR,
nativeOut = true
} = {}
): Promise<ContractTransaction> {
const { totalCryptoFee } = await calcCryptoFees({
bridge: swapMain,
integrator,
dstChainID
});
return swapMain.transferWithSwapV3Native(
receiver === null ? wallet.address : receiver,
amountIn,
dstChainID,
{
dex: srcDEX,
path: srcPathBytes,
deadline: DEADLINE,
amountOutMinimum
},
{
dex: routerV3,
nativeOut: nativeOut,
receiverEOA: other.address,
integrator: integrator,
version: VERSION_V2,
path: [wnative.address, transitToken.address],
pathV3: '0x',
deadline: DEADLINE,
amountOutMinimum: DEFAULT_AMOUNT_OUT_MIN
},
'10000',
{
value:
nativeIn === null ? amountIn.add(totalCryptoFee).add(MESSAGE_BUS_FEE) : nativeIn
}
);
}
async function callTransferWithSwapV3(
amountOutMinimum: BigNumberish,
srcPathBytes: BytesLike,
{
receiver = null,
amountIn = DEFAULT_AMOUNT_IN,
dstChainID = DST_CHAIN_ID,
srcDEX = routerV3,
nativeIn = null,
integrator = INTEGRATOR,
nativeOut = true
} = {}
): Promise<ContractTransaction> {
const { totalCryptoFee } = await calcCryptoFees({
bridge: swapMain,
integrator,
dstChainID
});
return swapMain.transferWithSwapV3(
receiver === null ? wallet.address : receiver,
amountIn,
dstChainID,
{
dex: srcDEX,
path: srcPathBytes,
deadline: DEADLINE,
amountOutMinimum
},
{
dex: router,
nativeOut: nativeOut,
receiverEOA: other.address,
integrator: integrator,
version: VERSION_V2,
path: [wnative.address, transitToken.address],
pathV3: '0x',
deadline: DEADLINE,
amountOutMinimum: DEFAULT_AMOUNT_OUT_MIN
},
'10000',
{ value: nativeIn === null ? totalCryptoFee.add(MESSAGE_BUS_FEE) : nativeIn }
);
}
// async function getAmountOutMinV3(
// amountIn = DEFAULT_AMOUNT_IN,
// path = [swapToken.address, transitToken.address]
// ): Promise<BN> {
// const _path = pack(['address', 'uint24', 'address'], [path[0], FeeAmount.LOW, path[1]]);
// return quoter.callStatic.quoteExactInput(_path, amountIn);
// }
async function getMessage(
messagesContract: TestMessages,
_nonce: BigNumberish,
dstChainId: BigNumberish,
{
dex = routerV3,
receiverEOA = other.address,
integrator = ethers.constants.AddressZero,
version = VERSION_V3,
path = [wnative.address, transitToken.address],
pathV3 = '0x',
deadline = DEADLINE,
amountOutMinimum = DEFAULT_AMOUNT_OUT_MIN,
_receiver = wallet.address,
nativeOut = true
} = {}
): Promise<string> {
return messagesContract.getMessage(
{
dex,
receiverEOA,
nativeOut,
integrator,
version,
path,
pathV3,
deadline,
amountOutMinimum
},
_nonce,
dstChainId
);
}
// async function getID(
// messagesContract: TestMessages,
// _nonce: BigNumberish,
// {
// dex = routerV3,
// receiverEOA = other.address,
// integrator = INTEGRATOR,
// version = VERSION_V3,
// path = [wnative.address, transitToken.address],
// pathV3 = '0x',
// deadline = DEADLINE,
// amountOutMinimum = DEFAULT_AMOUNT_OUT_MIN,
// _receiver = wallet.address,
// nativeOut = true,
// _srcChainId = chainId,
// _dstChainId = DST_CHAIN_ID
// } = {}
// ): Promise<string> {
// return messagesContract.getID(
// _srcChainId,
// _dstChainId,
// {
// dex,
// nativeOut,
// receiverEOA,
// integrator,
// version,
// path,
// pathV3,
// deadline,
// amountOutMinimum
// },
// _nonce
// );
// }
before('create fixture loader', async () => {
[wallet, other] = await (ethers as any).getSigners();
loadFixture = createFixtureLoader([wallet, other]);
});
beforeEach('deploy fixture', async () => {
({ swapMain, swapToken, transitToken, wnative, router, routerV3, testMessagesContract } =
await loadFixture(swapContractFixtureInFork));
});
it('constructor initializes', async () => {
expect(await swapMain.nativeWrap()).to.eq(TEST_NATIVE);
expect(await swapMain.messageBus()).to.eq(TEST_BUS);
const routers = TEST_ROUTERS.split(',');
expect(await swapMain.getAvailableRouters()).to.deep.eq(routers);
});
describe('#WithSwapTests', () => {
describe('#transferWithSwapV3Native', () => {
it('Should swap native and transfer through Celer', async () => {
//const ID = await getID(testMessagesContract, (await swapMain.nonce()).add('1'));
await swapMain.setMaxTokenAmount(
transitToken.address,
ethers.utils.parseEther('1000')
);
const path = await encodePath([wnative.address, transitToken.address]);
const _amountIn = ethers.BigNumber.from('20000000000000000000');
await expect(
callTransferWithSwapV3Native(0, path, {
amountIn: _amountIn
})
).to.emit(swapMain, 'CrossChainRequestSent');
//.withArgs(ID, DST_CHAIN_ID, _amountIn, wnative.address);
});
it('Should fail transfer through Celer', async () => {
await swapMain.setMaxTokenAmount(
transitToken.address,
ethers.utils.parseEther('1000')
);
const path = await encodePath([wnative.address, transitToken.address]);
await expect(callTransferWithSwapV3Native(0, path)).to.be.revertedWith(
'amount too small'
);
});
});
describe('#transferWithSwapV3', () => {
it('Should swap transitToken and transfer through Сeler', async () => {
await swapToken.approve(swapMain.address, ethers.constants.MaxUint256);
await swapMain.setMaxTokenAmount(
transitToken.address,
ethers.utils.parseEther('1000')
);
// const ID = await getID(testMessagesContract, (await swapMain.nonce()).add('1'));
const path = await encodePath([swapToken.address, transitToken.address]);
await expect(callTransferWithSwapV3(0, path)).to.emit(
swapMain,
'CrossChainRequestSent'
);
// .withArgs(ID, DST_CHAIN_ID, DEFAULT_AMOUNT_IN, swapToken.address);
});
});
describe('#executeMessageWithTransfer', () => {
beforeEach('setup for target executions', async () => {
// transfer 1000 USDC
await transitToken.transfer(swapMain.address, ethers.BigNumber.from('1000000000'));
});
describe('target swap should emit correct event', async () => {
let nonce: BN;
let message: string;
beforeEach('setup before swap', async () => {
nonce = (await swapMain.nonce()).add('1');
const pathV3 = await encodePath([transitToken.address, swapToken.address]);
message = await getMessage(testMessagesContract, nonce, DST_CHAIN_ID, {
path: [ZERO_ADDRESS],
pathV3: pathV3,
amountOutMinimum: ethers.BigNumber.from('0')
});
});
it('should successfully swap V3 with rubic fee', async () => {
await hre.network.provider.request({
method: 'hardhat_impersonateAccount',
params: [TEST_BUS]
});
const bus = await ethers.getSigner(TEST_BUS);
await network.provider.send('hardhat_setBalance', [
bus.address,
'0x152D02C7E14AF6800000' // 100000 eth
]);
const _swapMain = swapMain.connect(bus);
//let tokenBalanceBefore = await transitToken.balanceOf(swapMain.address);
await expect(
_swapMain.executeMessageWithTransfer(
ethers.constants.AddressZero,
transitToken.address,
ethers.BigNumber.from('1000000000'),
DST_CHAIN_ID,
message,
EXECUTOR_ADDRESS
)
).to.emit(swapMain, 'CrossChainProcessed');
let tokenBalanceAfter = await transitToken.balanceOf(swapMain.address);
// take only platform comission in transit token
const { feeAmount } = await calcTokenFees({
bridge: swapMain,
amountWithFee: ethers.BigNumber.from('1000000000')
});
// take only platform comission in transit token
await expect(tokenBalanceAfter).to.be.eq(feeAmount);
});
it('should fail swap V3 with rubic fee and transfer tokens', async () => {
await hre.network.provider.request({
method: 'hardhat_impersonateAccount',
params: [TEST_BUS]
});
const bus = await ethers.getSigner(TEST_BUS);
await network.provider.send('hardhat_setBalance', [
bus.address,
'0x152D02C7E14AF6800000' // 100000 eth
]);
const _swapMain = swapMain.connect(bus);
const pathV3 = await encodePath([transitToken.address, wnative.address]);
message = await getMessage(testMessagesContract, nonce, DST_CHAIN_ID, {
path: [ZERO_ADDRESS],
pathV3: pathV3,
amountOutMinimum: ethers.BigNumber.from('2000000000000000000') // 2 eth for 1000$ is minOut, too much
});
//let tokenBalanceBefore = await transitToken.balanceOf(swapMain.address);
await expect(
_swapMain.executeMessageWithTransfer(
ethers.constants.AddressZero,
transitToken.address,
ethers.BigNumber.from('1000000000'),
DST_CHAIN_ID,
message,
EXECUTOR_ADDRESS
)
).to.emit(swapMain, 'CrossChainProcessed');
let tokenBalanceAfter = await transitToken.balanceOf(swapMain.address);
const { RubicFee, feeAmount } = await calcTokenFees({
bridge: swapMain,
amountWithFee: ethers.BigNumber.from('1000000000')
//integrator: INTEGRATOR,
});
// take only platform comission in transit token
await expect(tokenBalanceAfter).to.be.eq(feeAmount);
const collectedFee1 = await swapMain.availableRubicTokenFee(
transitToken.address
);
await expect(collectedFee1).to.be.eq(RubicFee);
const integratorCollectedFee1 = await swapMain.availableIntegratorTokenFee(
transitToken.address,
INTEGRATOR
);
await expect(Number(integratorCollectedFee1)).to.be.eq(0);
});
describe('target swap should take integrator & rubic fee', async () => {
beforeEach('set integrator and rubic fee', async () => {
await swapMain.setIntegratorInfo(INTEGRATOR, {
isIntegrator: true,
tokenFee: '3000',
RubicTokenShare: '400000',
RubicFixedCryptoShare: '800000',
fixedFeeAmount: ethers.utils.parseEther('2')
});
const pathV3 = await encodePath([transitToken.address, swapToken.address]);
message = await getMessage(testMessagesContract, nonce, DST_CHAIN_ID, {
path: [ZERO_ADDRESS],
integrator: INTEGRATOR,
pathV3: pathV3,
amountOutMinimum: ethers.BigNumber.from('0')
});
});
it('should successfully swap V3 with rubic & integrator fee', async () => {
await hre.network.provider.request({
method: 'hardhat_impersonateAccount',
params: [TEST_BUS]
});
const bus = await ethers.getSigner(TEST_BUS);
await network.provider.send('hardhat_setBalance', [
bus.address,
'0x152D02C7E14AF6800000'
]);
const _swapMain = swapMain.connect(bus);
//let tokenBalanceBefore = await transitToken.balanceOf(swapMain.address);
await expect(
_swapMain.executeMessageWithTransfer(
ethers.constants.AddressZero,
transitToken.address,
ethers.BigNumber.from('1000000000'),
DST_CHAIN_ID,
message,
EXECUTOR_ADDRESS
)
).to.emit(swapMain, 'CrossChainProcessed');
const tokenBalanceAfter = await transitToken.balanceOf(swapMain.address);
const collectedFee1 = await swapMain.availableRubicTokenFee(
transitToken.address
);
const integratorCollectedFee1 = await swapMain.availableIntegratorTokenFee(
transitToken.address,
INTEGRATOR
);
const { integratorFee, RubicFee, feeAmount } = await calcTokenFees({
bridge: swapMain,
amountWithFee: ethers.BigNumber.from('1000000000'),
integrator: INTEGRATOR
});
await expect(integratorCollectedFee1).to.be.eq(integratorFee);
// take platform comission in transit token
await expect(collectedFee1).to.be.eq(RubicFee);
await expect(tokenBalanceAfter).to.be.eq(feeAmount);
});
it('should fail swap V3 with rubic & integrator fee', async () => {
await hre.network.provider.request({
method: 'hardhat_impersonateAccount',
params: [TEST_BUS]
});
const bus = await ethers.getSigner(TEST_BUS);
await network.provider.send('hardhat_setBalance', [
bus.address,
'0x152D02C7E14AF6800000' // 100000 eth
]);
const _swapMain = swapMain.connect(bus);
//let tokenBalanceBefore = await transitToken.balanceOf(swapMain.address);
const pathV3 = await encodePath([transitToken.address, swapToken.address]);
message = await getMessage(testMessagesContract, nonce, DST_CHAIN_ID, {
path: [ZERO_ADDRESS],
integrator: INTEGRATOR,
pathV3: pathV3,
amountOutMinimum: ethers.BigNumber.from('20000000000000000000') // 20 eth for 1000$ is min out
});
await expect(
_swapMain.executeMessageWithTransfer(
ethers.constants.AddressZero,
transitToken.address,
ethers.BigNumber.from('1000000000'),
DST_CHAIN_ID,
message,
EXECUTOR_ADDRESS
)
).to.emit(swapMain, 'CrossChainProcessed');
const tokenBalanceAfter = await transitToken.balanceOf(swapMain.address);
const collectedFee1 = await swapMain.availableRubicTokenFee(
transitToken.address
);
const integratorCollectedFee1 = await swapMain.availableIntegratorTokenFee(
transitToken.address,
INTEGRATOR
);
const { integratorFee, RubicFee, feeAmount } = await calcTokenFees({
bridge: swapMain,
amountWithFee: ethers.BigNumber.from('1000000000'),
integrator: INTEGRATOR
});
await expect(integratorCollectedFee1).to.be.eq(integratorFee);
// take platform comission in transit token
await expect(collectedFee1).to.be.eq(RubicFee);
await expect(tokenBalanceAfter).to.be.eq(feeAmount);
});
});
});
});
});
});