Pnuttaste/Interchain-message/test/RubicCrossChainBridge.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

479 lines
18 KiB
TypeScript
Raw Permalink 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 { calcCryptoFees, calcTokenFees } from 'rubic-bridge-base/lib';
import { expect } from 'chai';
import {
DEADLINE,
DST_CHAIN_ID,
DEFAULT_AMOUNT_IN,
VERSION_V2,
ZERO_ADDRESS,
DEFAULT_AMOUNT_OUT_MIN,
EXECUTOR_ADDRESS,
INTEGRATOR,
DEFAULT_AMOUNT_IN_USDC,
MESSAGE_BUS_FEE
} from './shared/consts';
import { BigNumber as BN, BigNumberish, ContractTransaction } from 'ethers';
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('RubicCrossChainBridge', () => {
let wallet: Wallet, other: Wallet;
//let swapToken: TestERC20;
let transitToken: TestERC20;
let swapMain: RubicRouterV2;
let router: string;
let wnative: WETH9;
//let chainId: number;
let testMessagesContract: TestMessages;
let loadFixture: ReturnType<typeof createFixtureLoader>;
async function callbridgeWithSwapNative({
receiver = null,
amountIn = DEFAULT_AMOUNT_IN,
dstChainID = DST_CHAIN_ID,
srcBridgeToken = wnative.address,
nativeIn = null,
integrator = ZERO_ADDRESS,
nativeOut = true
} = {}): Promise<ContractTransaction> {
const { totalCryptoFee } = await calcCryptoFees({
bridge: swapMain,
integrator,
dstChainID
});
return swapMain.bridgeWithSwapNative(
receiver === null ? wallet.address : receiver,
amountIn,
dstChainID,
srcBridgeToken,
{
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 ? amountIn.add(totalCryptoFee).add(MESSAGE_BUS_FEE) : nativeIn
}
);
}
async function callbridgeWithSwap({
receiver = null,
amountIn = DEFAULT_AMOUNT_IN,
dstChainID = DST_CHAIN_ID,
srcBridgeToken = transitToken.address,
nativeIn = null,
nativeOut = true,
integrator = ZERO_ADDRESS
} = {}): Promise<ContractTransaction> {
const { totalCryptoFee } = await calcCryptoFees({
bridge: swapMain,
integrator,
dstChainID
});
return swapMain.bridgeWithSwap(
receiver === null ? wallet.address : receiver,
amountIn,
dstChainID,
srcBridgeToken,
{
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 getMessage(
messagesContract: TestMessages,
_nonce: BigNumberish,
dstChainId: BigNumberish,
{
dex = router,
receiverEOA = other.address,
integrator = ethers.constants.AddressZero,
version = VERSION_V2,
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,
nativeOut,
receiverEOA,
integrator,
version,
path,
pathV3,
deadline,
amountOutMinimum
},
_nonce,
dstChainId
);
}
// async function getID(
// messagesContract: TestMessages,
// _nonce: BigNumberish,
// {
// dex = router,
// integrator = ZERO_ADDRESS,
// version = VERSION,
// 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(
// _receiver,
// _srcChainId,
// _dstChainId,
// {
// dex,
// nativeOut,
// integrator,
// version,
// path,
// pathV3,
// deadline,
// amountOutMinimum
// },
// _nonce
// );
// }
before('create fixture loader', async () => {
[wallet, other] = await (ethers as any).getSigners();
loadFixture = createFixtureLoader([wallet, other]);
//chainId = (await ethers.provider.getNetwork()).chainId;
});
beforeEach('deploy fixture', async () => {
({ swapMain, transitToken, wnative, router, 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('#WithBridgeTests', () => {
describe('#bridgeWithSwapNative', () => {
it('Should bridge native and transfer through Celer', async () => {
await swapMain.setMaxTokenAmount(wnative.address, ethers.utils.parseEther('1000'));
//const ID = await getID(testMessagesContract, (await swapMain.nonce()).add('1'));
await expect(callbridgeWithSwapNative()).to.emit(swapMain, 'CrossChainRequestSent');
//.withArgs(ID, DST_CHAIN_ID, DEFAULT_AMOUNT_IN, wnative.address);
});
});
describe('#bridgeWithSwap', () => {
it('Should fail transfering with big amount', async () => {
await transitToken.approve(swapMain.address, ethers.constants.MaxUint256);
await swapMain.setMaxTokenAmount(
transitToken.address,
ethers.utils.parseEther('1000')
);
await expect(callbridgeWithSwap()).to.be.revertedWith('amount too large');
});
it('Should fail transfering with small amount', async () => {
await transitToken.approve(swapMain.address, ethers.constants.MaxUint256);
await swapMain.setMaxTokenAmount(
transitToken.address,
ethers.utils.parseEther('1000')
);
await expect(
callbridgeWithSwap({
amountIn: ethers.BigNumber.from('10000000')
})
).to.be.revertedWith('amount too small');
});
it('Should bridge transitToken and transfer through Сeler', async () => {
await transitToken.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'));
await expect(
callbridgeWithSwap({
amountIn: DEFAULT_AMOUNT_IN_USDC
})
).to.emit(swapMain, 'CrossChainRequestSent');
//.withArgs(ID, DST_CHAIN_ID, DEFAULT_AMOUNT_IN_USDC, transitToken.address);
});
});
describe('#executeMessageWithTransfer', () => {
beforeEach('setup for target executions', async () => {
// transfer 1000 USDC
await transitToken.transfer(swapMain.address, ethers.BigNumber.from('1000000000'));
});
describe('target bridge should emit correct event', async () => {
let nonce: BN;
let message: string;
beforeEach('setup before bridge', async () => {
nonce = (await swapMain.nonce()).add('1');
message = await getMessage(testMessagesContract, nonce, DST_CHAIN_ID, {
dex: ZERO_ADDRESS,
version: 2, // bridge version
path: [transitToken.address],
amountOutMinimum: ethers.BigNumber.from('0') // not used
});
});
it('should successfully bridge token 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')
});
await expect(Number(tokenBalanceAfter)).to.be.eq(feeAmount);
});
it('should successfully bridge native 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 abiCoder = ethers.utils.defaultAbiCoder;
const storageBalancePositionWeth = ethers.utils.keccak256(
abiCoder.encode(['address'], [bus.address]) +
abiCoder.encode(['uint256'], [3]).slice(2, 66)
);
await network.provider.send('hardhat_setStorageAt', [
wnative.address,
storageBalancePositionWeth,
abiCoder.encode(['uint256'], [ethers.utils.parseEther('100000')])
]);
await wnative
.connect(bus)
.transfer(swapMain.address, ethers.utils.parseEther('1'));
const _swapMain = swapMain.connect(bus);
message = await getMessage(testMessagesContract, nonce, DST_CHAIN_ID, {
dex: ZERO_ADDRESS,
version: 2, // bridge version
path: [wnative.address],
amountOutMinimum: ethers.BigNumber.from('0') // not used
});
//let tokenBalanceBefore = await wnative.balanceOf(swapMain.address);
await expect(
_swapMain.executeMessageWithTransfer(
ethers.constants.AddressZero,
wnative.address,
ethers.utils.parseEther('1'), // 1 ether
DST_CHAIN_ID,
message,
EXECUTOR_ADDRESS
)
).to.emit(swapMain, 'CrossChainProcessed');
let tokenBalanceAfter = await wnative.balanceOf(swapMain.address);
const { feeAmount } = await calcTokenFees({
bridge: swapMain,
amountWithFee: ethers.utils.parseEther('1')
});
await expect(tokenBalanceAfter).to.be.eq(feeAmount);
});
it('should fail bridge with incorrect path', 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);
message = await getMessage(testMessagesContract, nonce, DST_CHAIN_ID, {
dex: ZERO_ADDRESS,
version: 2, // bridge version
path: [transitToken.address, wnative.address],
amountOutMinimum: ethers.BigNumber.from('0') // not used
});
await expect(
_swapMain.executeMessageWithTransfer(
ethers.constants.AddressZero,
transitToken.address,
ethers.BigNumber.from('1000000000'),
DST_CHAIN_ID,
message,
EXECUTOR_ADDRESS
)
).to.be.revertedWith('dst bridge expected');
});
describe('target bridge 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')
}); // 0.3 %
message = await getMessage(testMessagesContract, nonce, DST_CHAIN_ID, {
dex: ZERO_ADDRESS,
integrator: INTEGRATOR,
version: 2, // bridge version
path: [transitToken.address],
amountOutMinimum: ethers.BigNumber.from('0') // not used
});
});
it('should successfully bridge transitToken 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);
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);
});
});
});
});
});
});