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
This commit is contained in:
		
							parent
							
								
									670beacbea
								
							
						
					
					
						commit
						df8039f494
					
				
							
								
								
									
										22
									
								
								Interchain-message/.env.example
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								Interchain-message/.env.example
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
ETHERSCAN_API_KEY=39
 | 
			
		||||
BSCSCAN_API_KEY=SV
 | 
			
		||||
POLYGONSCAN_API_KEY=CK
 | 
			
		||||
AVALANCHE_API_KEY=XD
 | 
			
		||||
FANTOMSCAN_API_KEY=NV
 | 
			
		||||
MNEMONIC=32432
 | 
			
		||||
INFURA_ID_PROJECT=b4
 | 
			
		||||
 | 
			
		||||
REPORT_GAS=true
 | 
			
		||||
 | 
			
		||||
ROUTERS_POLYGON=0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff,0xE592427A0AEce92De3Edee1F18E0157C05861564,0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506,0xC0788A3aD43d79aa53B09c2EaCc313A787d1d607,0x1111111254fb6c44bAC0beD2854e76F90643097d,0x89D6B81A1Ef25894620D05ba843d83B0A296239e
 | 
			
		||||
NATIVE_POLYGON=0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270
 | 
			
		||||
TRANSIT_POLYGON=0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174
 | 
			
		||||
BUS_POLYGON=0x265B25e22bcd7f10a5bD6E6410F10537Cc7567e8
 | 
			
		||||
BUS_POLYGON_MAIN=0xaFDb9C40C7144022811F034EE07Ce2E110093fe6
 | 
			
		||||
SWAP_TOKEN_POLYGON=0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619
 | 
			
		||||
 | 
			
		||||
ROUTERS_BSC_TESTNET=0x9Ac64Cc6e4415144C455BD8E4837Fea55603e5c3
 | 
			
		||||
NATIVE_BSC_TESTNET=0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd
 | 
			
		||||
TRANSIT_BSC_TESTNET=0x7d43AABC515C356145049227CeE54B608342c0ad
 | 
			
		||||
SWAP_TOKEN_BSC_TESTNET=0x5471ea8f739dd37E9B81Be9c5c77754D8AA953E4
 | 
			
		||||
BUS_BSC_TESTNET=0xAd204986D6cB67A5Bc76a3CB8974823F43Cb9AAA
 | 
			
		||||
							
								
								
									
										94
									
								
								Interchain-message/.eslintrc.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								Interchain-message/.eslintrc.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,94 @@
 | 
			
		|||
module.exports = {
 | 
			
		||||
    root: true,
 | 
			
		||||
    overrides: [
 | 
			
		||||
        {
 | 
			
		||||
            files: ['test/**/*.ts', 'scripts/**/*.ts'],
 | 
			
		||||
            parser: '@typescript-eslint/parser',
 | 
			
		||||
            parserOptions: {
 | 
			
		||||
                project: './tsconfig.json',
 | 
			
		||||
                tsconfigRootDir: __dirname,
 | 
			
		||||
                createDefaultProgram: true
 | 
			
		||||
            },
 | 
			
		||||
            plugins: [
 | 
			
		||||
                '@typescript-eslint',
 | 
			
		||||
                'unused-imports',
 | 
			
		||||
                'import'
 | 
			
		||||
            ],
 | 
			
		||||
            extends: [
 | 
			
		||||
                'airbnb-typescript/base',
 | 
			
		||||
                'plugin:prettier/recommended',
 | 
			
		||||
                'prettier'
 | 
			
		||||
            ],
 | 
			
		||||
            rules: {
 | 
			
		||||
                'import/prefer-default-export': 'off',
 | 
			
		||||
                '@typescript-eslint/no-useless-constructor': 'off',
 | 
			
		||||
                'no-plusplus': 'off',
 | 
			
		||||
                'class-method-use-this': 'off',
 | 
			
		||||
                'no-underscore-dangle': 'off',
 | 
			
		||||
                'no-inferrable-types': 'off',
 | 
			
		||||
                '@typescript-eslint/no-unused-vars': [
 | 
			
		||||
                    'error',
 | 
			
		||||
                    {
 | 
			
		||||
                        vars: 'all',
 | 
			
		||||
                        args: 'all',
 | 
			
		||||
                        ignoreRestSiblings: false,
 | 
			
		||||
                        argsIgnorePattern: '^_'
 | 
			
		||||
                    }
 | 
			
		||||
                ],
 | 
			
		||||
                '@typescript-eslint/no-inferrable-types': 'off',
 | 
			
		||||
                'class-methods-use-this': 'off',
 | 
			
		||||
                complexity: ['error', 20],
 | 
			
		||||
                eqeqeq: ['error', 'always'],
 | 
			
		||||
                'no-magic-numbers': 'off',
 | 
			
		||||
                '@typescript-eslint/no-magic-numbers': [
 | 
			
		||||
                    'warn',
 | 
			
		||||
                    {
 | 
			
		||||
                        ignore: [-1, 0, 1, 2, 10, 100, 1000, 16, 64, 256],
 | 
			
		||||
                        detectObjects: true,
 | 
			
		||||
                        ignoreReadonlyClassProperties: true
 | 
			
		||||
                    }
 | 
			
		||||
                ],
 | 
			
		||||
                '@typescript-eslint/naming-convention': [
 | 
			
		||||
                    'error',
 | 
			
		||||
                    {
 | 
			
		||||
                        selector: 'enumMember',
 | 
			
		||||
                        format: ['UPPER_CASE']
 | 
			
		||||
                    }
 | 
			
		||||
                ],
 | 
			
		||||
                'no-empty': ['error', { 'allowEmptyCatch': true }],
 | 
			
		||||
                // Styling.
 | 
			
		||||
                'array-bracket-spacing': ['error', 'never'],
 | 
			
		||||
                'object-curly-spacing': ['error', 'always'],
 | 
			
		||||
                indent: 'off',
 | 
			
		||||
                'comma-dangle': 'off',
 | 
			
		||||
                '@typescript-eslint/comma-dangle': ['error', 'never'],
 | 
			
		||||
                // Temporary rules. Remove after full refactoring.
 | 
			
		||||
                'import/no-extraneous-dependencies': 'off',
 | 
			
		||||
                '@typescript-eslint/dot-notation': 'off',
 | 
			
		||||
                'no-restricted-globals': 'off',
 | 
			
		||||
                '@typescript-eslint/no-empty-function': 'off',
 | 
			
		||||
                'no-param-reassign': 'off',
 | 
			
		||||
                // Temporary rules. Remove as fast as it can be.
 | 
			
		||||
                'max-classes-per-file': 'off',
 | 
			
		||||
                radix: ['warn', 'as-needed'],
 | 
			
		||||
                'no-prototype-builtins': 'off',
 | 
			
		||||
                'no-return-assign': 'off',
 | 
			
		||||
                'no-restricted-syntax': [
 | 
			
		||||
                    'error',
 | 
			
		||||
                    'LabeledStatement',
 | 
			
		||||
                    'WithStatement'
 | 
			
		||||
                ],
 | 
			
		||||
                'no-console': [
 | 
			
		||||
                    'warn',
 | 
			
		||||
                    {
 | 
			
		||||
                        allow: ['debug', 'error', 'info']
 | 
			
		||||
                    }
 | 
			
		||||
                ],
 | 
			
		||||
                'import/export': 0
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    env: {
 | 
			
		||||
        "es6": true
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										9
									
								
								Interchain-message/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								Interchain-message/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
.env
 | 
			
		||||
typechain-types
 | 
			
		||||
artifacts
 | 
			
		||||
cache
 | 
			
		||||
node_modules
 | 
			
		||||
.idea
 | 
			
		||||
.openzeppelin
 | 
			
		||||
typechain
 | 
			
		||||
.DS_Store
 | 
			
		||||
							
								
								
									
										28
									
								
								Interchain-message/.prettierrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								Interchain-message/.prettierrc
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
{
 | 
			
		||||
  "$schema": "http://json.schemastore.org/prettierrc",
 | 
			
		||||
  "overrides": [
 | 
			
		||||
    {
 | 
			
		||||
      "files": "*.sol",
 | 
			
		||||
      "options": {
 | 
			
		||||
        "semi": true,
 | 
			
		||||
        "singleQuote": true,
 | 
			
		||||
        "printWidth": 120
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "files": ["*.js", "*.ts"],
 | 
			
		||||
      "options": {
 | 
			
		||||
        "arrowParens": "avoid",
 | 
			
		||||
        "bracketSpacing": true,
 | 
			
		||||
        "printWidth": 100,
 | 
			
		||||
        "proseWrap": "always",
 | 
			
		||||
        "quoteProps": "as-needed",
 | 
			
		||||
        "semi": true,
 | 
			
		||||
        "singleQuote": true,
 | 
			
		||||
        "tabWidth": 4,
 | 
			
		||||
        "trailingComma": "none",
 | 
			
		||||
        "useTabs": false
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								Interchain-message/.solhint.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								Interchain-message/.solhint.json
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
{
 | 
			
		||||
  "extends": "solhint:recommended",
 | 
			
		||||
  "plugins": [
 | 
			
		||||
    "prettier"
 | 
			
		||||
  ],
 | 
			
		||||
  "rules": {
 | 
			
		||||
    "prettier/prettier": "error",
 | 
			
		||||
    "quotes": ["error", "single"],
 | 
			
		||||
    "compiler-version": ["error", "^0.7.0"],
 | 
			
		||||
    "func-visibility": ["warn", { "ignoreConstructors": true }],
 | 
			
		||||
    "no-empty-blocks": "off",
 | 
			
		||||
    "reason-string": ["warn", { "maxLength": 64 }],
 | 
			
		||||
    "not-rely-on-time": "off",
 | 
			
		||||
    "no-inline-assembly": "off"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								Interchain-message/.solhintignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Interchain-message/.solhintignore
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
node_modules
 | 
			
		||||
							
								
								
									
										46
									
								
								Interchain-message/contracts/interfaces/IBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								Interchain-message/contracts/interfaces/IBridge.sol
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,46 @@
 | 
			
		|||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
pragma solidity >=0.8.9;
 | 
			
		||||
 | 
			
		||||
interface IBridge {
 | 
			
		||||
    function send(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        address _token,
 | 
			
		||||
        uint256 _amount,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        uint64 _nonce,
 | 
			
		||||
        uint32 _maxSlippage
 | 
			
		||||
    ) external;
 | 
			
		||||
 | 
			
		||||
    function relay(
 | 
			
		||||
        bytes calldata _relayRequest,
 | 
			
		||||
        bytes[] calldata _sigs,
 | 
			
		||||
        address[] calldata _signers,
 | 
			
		||||
        uint256[] calldata _powers
 | 
			
		||||
    ) external;
 | 
			
		||||
 | 
			
		||||
    function transfers(bytes32 transferId) external view returns (bool);
 | 
			
		||||
 | 
			
		||||
    function withdraws(bytes32 withdrawId) external view returns (bool);
 | 
			
		||||
 | 
			
		||||
    function withdraw(
 | 
			
		||||
        bytes calldata _wdmsg,
 | 
			
		||||
        bytes[] calldata _sigs,
 | 
			
		||||
        address[] calldata _signers,
 | 
			
		||||
        uint256[] calldata _powers
 | 
			
		||||
    ) external;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Verifies that a message is signed by a quorum among the signers.
 | 
			
		||||
     * @param _msg signed message
 | 
			
		||||
     * @param _sigs list of signatures sorted by signer addresses in ascending order
 | 
			
		||||
     * @param _signers sorted list of current signers
 | 
			
		||||
     * @param _powers powers of current signers
 | 
			
		||||
     */
 | 
			
		||||
    function verifySigs(
 | 
			
		||||
        bytes memory _msg,
 | 
			
		||||
        bytes[] calldata _sigs,
 | 
			
		||||
        address[] calldata _signers,
 | 
			
		||||
        uint256[] calldata _powers
 | 
			
		||||
    ) external view;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										126
									
								
								Interchain-message/contracts/interfaces/IMessageBus.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								Interchain-message/contracts/interfaces/IMessageBus.sol
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,126 @@
 | 
			
		|||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
pragma solidity >=0.8.9;
 | 
			
		||||
 | 
			
		||||
import "../message/libraries/MsgDataTypes.sol";
 | 
			
		||||
 | 
			
		||||
interface IMessageBus {
 | 
			
		||||
    function liquidityBridge() external view returns (address);
 | 
			
		||||
 | 
			
		||||
    function pegBridge() external view returns (address);
 | 
			
		||||
 | 
			
		||||
    function pegBridgeV2() external view returns (address);
 | 
			
		||||
 | 
			
		||||
    function pegVault() external view returns (address);
 | 
			
		||||
 | 
			
		||||
    function pegVaultV2() external view returns (address);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Calculates the required fee for the message.
 | 
			
		||||
     * @param _message Arbitrary message bytes to be decoded by the destination app contract.
 | 
			
		||||
     @ @return The required fee.
 | 
			
		||||
     */
 | 
			
		||||
    function calcFee(bytes calldata _message) external view returns (uint256);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Sends a message to a contract on another chain.
 | 
			
		||||
     * Sender needs to make sure the uniqueness of the message Id, which is computed as
 | 
			
		||||
     * hash(type.MessageOnly, sender, receiver, srcChainId, srcTxHash, dstChainId, message).
 | 
			
		||||
     * If messages with the same Id are sent, only one of them will succeed at dst chain..
 | 
			
		||||
     * A fee is charged in the native gas token.
 | 
			
		||||
     * @param _receiver The address of the destination app contract.
 | 
			
		||||
     * @param _dstChainId The destination chain ID.
 | 
			
		||||
     * @param _message Arbitrary message bytes to be decoded by the destination app contract.
 | 
			
		||||
     */
 | 
			
		||||
    function sendMessage(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        uint256 _dstChainId,
 | 
			
		||||
        bytes calldata _message
 | 
			
		||||
    ) external payable;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Sends a message associated with a transfer to a contract on another chain.
 | 
			
		||||
     * If messages with the same srcTransferId are sent, only one of them will succeed at dst chain..
 | 
			
		||||
     * A fee is charged in the native token.
 | 
			
		||||
     * @param _receiver The address of the destination app contract.
 | 
			
		||||
     * @param _dstChainId The destination chain ID.
 | 
			
		||||
     * @param _srcBridge The bridge contract to send the transfer with.
 | 
			
		||||
     * @param _srcTransferId The transfer ID.
 | 
			
		||||
     * @param _dstChainId The destination chain ID.
 | 
			
		||||
     * @param _message Arbitrary message bytes to be decoded by the destination app contract.
 | 
			
		||||
     */
 | 
			
		||||
    function sendMessageWithTransfer(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        uint256 _dstChainId,
 | 
			
		||||
        address _srcBridge,
 | 
			
		||||
        bytes32 _srcTransferId,
 | 
			
		||||
        bytes calldata _message
 | 
			
		||||
    ) external payable;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Withdraws message fee in the form of native gas token.
 | 
			
		||||
     * @param _account The address receiving the fee.
 | 
			
		||||
     * @param _cumulativeFee The cumulative fee credited to the account. Tracked by SGN.
 | 
			
		||||
     * @param _sigs The list of signatures sorted by signing addresses in ascending order. A withdrawal must be
 | 
			
		||||
     * signed-off by +2/3 of the sigsVerifier's current signing power to be delivered.
 | 
			
		||||
     * @param _signers The sorted list of signers.
 | 
			
		||||
     * @param _powers The signing powers of the signers.
 | 
			
		||||
     */
 | 
			
		||||
    function withdrawFee(
 | 
			
		||||
        address _account,
 | 
			
		||||
        uint256 _cumulativeFee,
 | 
			
		||||
        bytes[] calldata _sigs,
 | 
			
		||||
        address[] calldata _signers,
 | 
			
		||||
        uint256[] calldata _powers
 | 
			
		||||
    ) external;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Execute a message with a successful transfer.
 | 
			
		||||
     * @param _message Arbitrary message bytes originated from and encoded by the source app contract
 | 
			
		||||
     * @param _transfer The transfer info.
 | 
			
		||||
     * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by
 | 
			
		||||
     * +2/3 of the sigsVerifier's current signing power to be delivered.
 | 
			
		||||
     * @param _signers The sorted list of signers.
 | 
			
		||||
     * @param _powers The signing powers of the signers.
 | 
			
		||||
     */
 | 
			
		||||
    function executeMessageWithTransfer(
 | 
			
		||||
        bytes calldata _message,
 | 
			
		||||
        MsgDataTypes.TransferInfo calldata _transfer,
 | 
			
		||||
        bytes[] calldata _sigs,
 | 
			
		||||
        address[] calldata _signers,
 | 
			
		||||
        uint256[] calldata _powers
 | 
			
		||||
    ) external payable;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Execute a message with a refunded transfer.
 | 
			
		||||
     * @param _message Arbitrary message bytes originated from and encoded by the source app contract
 | 
			
		||||
     * @param _transfer The transfer info.
 | 
			
		||||
     * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by
 | 
			
		||||
     * +2/3 of the sigsVerifier's current signing power to be delivered.
 | 
			
		||||
     * @param _signers The sorted list of signers.
 | 
			
		||||
     * @param _powers The signing powers of the signers.
 | 
			
		||||
     */
 | 
			
		||||
    function executeMessageWithTransferRefund(
 | 
			
		||||
        bytes calldata _message, // the same message associated with the original transfer
 | 
			
		||||
        MsgDataTypes.TransferInfo calldata _transfer,
 | 
			
		||||
        bytes[] calldata _sigs,
 | 
			
		||||
        address[] calldata _signers,
 | 
			
		||||
        uint256[] calldata _powers
 | 
			
		||||
    ) external payable;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Execute a message not associated with a transfer.
 | 
			
		||||
     * @param _message Arbitrary message bytes originated from and encoded by the source app contract
 | 
			
		||||
     * @param _sigs The list of signatures sorted by signing addresses in ascending order. A relay must be signed-off by
 | 
			
		||||
     * +2/3 of the sigsVerifier's current signing power to be delivered.
 | 
			
		||||
     * @param _signers The sorted list of signers.
 | 
			
		||||
     * @param _powers The signing powers of the signers.
 | 
			
		||||
     */
 | 
			
		||||
    function executeMessage(
 | 
			
		||||
        bytes calldata _message,
 | 
			
		||||
        MsgDataTypes.RouteInfo calldata _route,
 | 
			
		||||
        bytes[] calldata _sigs,
 | 
			
		||||
        address[] calldata _signers,
 | 
			
		||||
        uint256[] calldata _powers
 | 
			
		||||
    ) external payable;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,82 @@
 | 
			
		|||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
pragma solidity >=0.8.9;
 | 
			
		||||
 | 
			
		||||
interface IMessageReceiverApp {
 | 
			
		||||
    enum ExecutionStatus {
 | 
			
		||||
        Fail, // execution failed, finalized
 | 
			
		||||
        Success, // execution succeeded, finalized
 | 
			
		||||
        Retry // execution rejected, can retry later
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Called by MessageBus (MessageBusReceiver) if the process is originated from MessageBus (MessageBusSender)'s
 | 
			
		||||
     *         sendMessageWithTransfer it is only called when the tokens are checked to be arrived at this contract's address.
 | 
			
		||||
     * @param _sender The address of the source app contract
 | 
			
		||||
     * @param _token The address of the token that comes out of the bridge
 | 
			
		||||
     * @param _amount The amount of tokens received at this contract through the cross-chain bridge.
 | 
			
		||||
     *        the contract that implements this contract can safely assume that the tokens will arrive before this
 | 
			
		||||
     *        function is called.
 | 
			
		||||
     * @param _srcChainId The source chain ID where the transfer is originated from
 | 
			
		||||
     * @param _message Arbitrary message bytes originated from and encoded by the source app contract
 | 
			
		||||
     * @param _executor Address who called the MessageBus execution function
 | 
			
		||||
     */
 | 
			
		||||
    function executeMessageWithTransfer(
 | 
			
		||||
        address _sender,
 | 
			
		||||
        address _token,
 | 
			
		||||
        uint256 _amount,
 | 
			
		||||
        uint64 _srcChainId,
 | 
			
		||||
        bytes calldata _message,
 | 
			
		||||
        address _executor
 | 
			
		||||
    ) external payable returns (ExecutionStatus);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Only called by MessageBus (MessageBusReceiver) if
 | 
			
		||||
     *         1. executeMessageWithTransfer reverts, or
 | 
			
		||||
     *         2. executeMessageWithTransfer returns ExecutionStatus.Fail
 | 
			
		||||
     * @param _sender The address of the source app contract
 | 
			
		||||
     * @param _token The address of the token that comes out of the bridge
 | 
			
		||||
     * @param _amount The amount of tokens received at this contract through the cross-chain bridge.
 | 
			
		||||
     *        the contract that implements this contract can safely assume that the tokens will arrive before this
 | 
			
		||||
     *        function is called.
 | 
			
		||||
     * @param _srcChainId The source chain ID where the transfer is originated from
 | 
			
		||||
     * @param _message Arbitrary message bytes originated from and encoded by the source app contract
 | 
			
		||||
     * @param _executor Address who called the MessageBus execution function
 | 
			
		||||
     */
 | 
			
		||||
    function executeMessageWithTransferFallback(
 | 
			
		||||
        address _sender,
 | 
			
		||||
        address _token,
 | 
			
		||||
        uint256 _amount,
 | 
			
		||||
        uint64 _srcChainId,
 | 
			
		||||
        bytes calldata _message,
 | 
			
		||||
        address _executor
 | 
			
		||||
    ) external payable returns (ExecutionStatus);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Called by MessageBus (MessageBusReceiver) to process refund of the original transfer from this contract
 | 
			
		||||
     * @param _token The token address of the original transfer
 | 
			
		||||
     * @param _amount The amount of the original transfer
 | 
			
		||||
     * @param _message The same message associated with the original transfer
 | 
			
		||||
     * @param _executor Address who called the MessageBus execution function
 | 
			
		||||
     */
 | 
			
		||||
    function executeMessageWithTransferRefund(
 | 
			
		||||
        address _token,
 | 
			
		||||
        uint256 _amount,
 | 
			
		||||
        bytes calldata _message,
 | 
			
		||||
        address _executor
 | 
			
		||||
    ) external payable returns (ExecutionStatus);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Called by MessageBus (MessageBusReceiver)
 | 
			
		||||
     * @param _sender The address of the source app contract
 | 
			
		||||
     * @param _srcChainId The source chain ID where the transfer is originated from
 | 
			
		||||
     * @param _message Arbitrary message bytes originated from and encoded by the source app contract
 | 
			
		||||
     * @param _executor Address who called the MessageBus execution function
 | 
			
		||||
     */
 | 
			
		||||
    function executeMessage(
 | 
			
		||||
        address _sender,
 | 
			
		||||
        uint64 _srcChainId,
 | 
			
		||||
        bytes calldata _message,
 | 
			
		||||
        address _executor
 | 
			
		||||
    ) external payable returns (ExecutionStatus);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										108
									
								
								Interchain-message/contracts/interfaces/IUniswapRouterV3.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								Interchain-message/contracts/interfaces/IUniswapRouterV3.sol
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,108 @@
 | 
			
		|||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
pragma solidity >=0.7.5;
 | 
			
		||||
pragma abicoder v2;
 | 
			
		||||
 | 
			
		||||
/// @title Router token swapping functionality
 | 
			
		||||
/// @notice Functions for swapping tokens via Uniswap Algebra
 | 
			
		||||
interface IUniswapRouterV3 {
 | 
			
		||||
    /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.
 | 
			
		||||
    /// @dev In the implementation you must pay the pool tokens owed for the swap.
 | 
			
		||||
    /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.
 | 
			
		||||
    /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.
 | 
			
		||||
    /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by
 | 
			
		||||
    /// the end of the swap. If positive, the callback must send that amount of token0 to the pool.
 | 
			
		||||
    /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by
 | 
			
		||||
    /// the end of the swap. If positive, the callback must send that amount of token1 to the pool.
 | 
			
		||||
    /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call
 | 
			
		||||
    function uniswapV3SwapCallback(
 | 
			
		||||
        int256 amount0Delta,
 | 
			
		||||
        int256 amount1Delta,
 | 
			
		||||
        bytes calldata data
 | 
			
		||||
    ) external;
 | 
			
		||||
 | 
			
		||||
    struct ExactInputSingleParams {
 | 
			
		||||
        address tokenIn;
 | 
			
		||||
        address tokenOut;
 | 
			
		||||
        uint24 fee;
 | 
			
		||||
        address recipient;
 | 
			
		||||
        uint256 deadline;
 | 
			
		||||
        uint256 amountIn;
 | 
			
		||||
        uint256 amountOutMinimum;
 | 
			
		||||
        uint160 sqrtPriceLimitX96;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @notice Swaps `amountIn` of one token for as much as possible of another token
 | 
			
		||||
    /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
 | 
			
		||||
    /// @return amountOut The amount of the received token
 | 
			
		||||
    function exactInputSingle(ExactInputSingleParams calldata params)
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        returns (uint256 amountOut);
 | 
			
		||||
 | 
			
		||||
    struct ExactInputParams {
 | 
			
		||||
        bytes path;
 | 
			
		||||
        address recipient;
 | 
			
		||||
        uint256 deadline;
 | 
			
		||||
        uint256 amountIn;
 | 
			
		||||
        uint256 amountOutMinimum;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
 | 
			
		||||
    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
 | 
			
		||||
    /// @return amountOut The amount of the received token
 | 
			
		||||
    function exactInput(ExactInputParams calldata params)
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        returns (uint256 amountOut);
 | 
			
		||||
 | 
			
		||||
    struct ExactOutputSingleParams {
 | 
			
		||||
        address tokenIn;
 | 
			
		||||
        address tokenOut;
 | 
			
		||||
        uint24 fee;
 | 
			
		||||
        address recipient;
 | 
			
		||||
        uint256 deadline;
 | 
			
		||||
        uint256 amountOut;
 | 
			
		||||
        uint256 amountInMaximum;
 | 
			
		||||
        uint160 sqrtPriceLimitX96;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @notice Swaps as little as possible of one token for `amountOut` of another token
 | 
			
		||||
    /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
 | 
			
		||||
    /// @return amountIn The amount of the input token
 | 
			
		||||
    function exactOutputSingle(ExactOutputSingleParams calldata params)
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        returns (uint256 amountIn);
 | 
			
		||||
 | 
			
		||||
    struct ExactOutputParams {
 | 
			
		||||
        bytes path;
 | 
			
		||||
        address recipient;
 | 
			
		||||
        uint256 deadline;
 | 
			
		||||
        uint256 amountOut;
 | 
			
		||||
        uint256 amountInMaximum;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
 | 
			
		||||
    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
 | 
			
		||||
    /// @return amountIn The amount of the input token
 | 
			
		||||
    function exactOutput(ExactOutputParams calldata params)
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        returns (uint256 amountIn);
 | 
			
		||||
 | 
			
		||||
    function WETH9() external view returns (address);
 | 
			
		||||
 | 
			
		||||
    function WNativeToken() external view returns (address);
 | 
			
		||||
 | 
			
		||||
    function refundETH() external payable;
 | 
			
		||||
 | 
			
		||||
    function refundNativeToken() external payable;
 | 
			
		||||
 | 
			
		||||
    function unwrapWETH9(uint256 amountMinimum, address recipient)
 | 
			
		||||
        external
 | 
			
		||||
        payable;
 | 
			
		||||
 | 
			
		||||
    function unwrapWNativeToken(uint256 amountMinimum, address recipient)
 | 
			
		||||
        external
 | 
			
		||||
        payable;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								Interchain-message/contracts/interfaces/IWETH.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								Interchain-message/contracts/interfaces/IWETH.sol
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
pragma solidity >=0.8.9;
 | 
			
		||||
 | 
			
		||||
interface IWETH {
 | 
			
		||||
    function deposit() external payable;
 | 
			
		||||
 | 
			
		||||
    function withdraw(uint256) external;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										99
									
								
								Interchain-message/contracts/message/apps/BridgeSwap.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								Interchain-message/contracts/message/apps/BridgeSwap.sol
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,99 @@
 | 
			
		|||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
pragma solidity >=0.8.9;
 | 
			
		||||
 | 
			
		||||
import "./SwapBase.sol";
 | 
			
		||||
 | 
			
		||||
contract BridgeSwap is SwapBase {
 | 
			
		||||
    function bridgeWithSwapNative(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        uint256 _amountIn,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        address _srcBridgeToken,
 | 
			
		||||
        SwapInfoDest calldata _dstSwap,
 | 
			
		||||
        uint32 _maxBridgeSlippage
 | 
			
		||||
    ) external payable {
 | 
			
		||||
        uint256 _fee = _deriveFeeAndPerformChecksNative(
 | 
			
		||||
            _amountIn,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _dstSwap.integrator,
 | 
			
		||||
            _srcBridgeToken
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        _sendBridgeMessage(
 | 
			
		||||
            _receiver,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _srcBridgeToken,
 | 
			
		||||
            _dstSwap,
 | 
			
		||||
            _maxBridgeSlippage,
 | 
			
		||||
            _fee,
 | 
			
		||||
            _amountIn
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function bridgeWithSwap(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        uint256 _amountIn,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        address _srcBridgeToken,
 | 
			
		||||
        SwapInfoDest calldata _dstSwap,
 | 
			
		||||
        uint32 _maxBridgeSlippage
 | 
			
		||||
    ) external payable {
 | 
			
		||||
        uint256 _fee = _deriveFeeAndPerformChecks(
 | 
			
		||||
            _amountIn,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _dstSwap.integrator,
 | 
			
		||||
            _srcBridgeToken
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        _sendBridgeMessage(
 | 
			
		||||
            _receiver,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _srcBridgeToken,
 | 
			
		||||
            _dstSwap,
 | 
			
		||||
            _maxBridgeSlippage,
 | 
			
		||||
            _fee,
 | 
			
		||||
            _amountIn
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _sendBridgeMessage(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        address _srcBridgeToken,
 | 
			
		||||
        SwapInfoDest calldata _dstSwap,
 | 
			
		||||
        uint32 _maxBridgeSlippage,
 | 
			
		||||
        uint256 _fee,
 | 
			
		||||
        uint256 _amountIn
 | 
			
		||||
    ) private {
 | 
			
		||||
        BaseCrossChainParams memory _baseParams = BaseCrossChainParams(
 | 
			
		||||
            _srcBridgeToken,
 | 
			
		||||
            _amountIn,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _retrieveDstTokenAddress(_dstSwap),
 | 
			
		||||
            _dstSwap.amountOutMinimum,
 | 
			
		||||
            _dstSwap.receiverEOA,
 | 
			
		||||
            _dstSwap.integrator,
 | 
			
		||||
            address(0)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        require(
 | 
			
		||||
            _baseParams.dstChainID != uint64(block.chainid),
 | 
			
		||||
            "same chain id"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        bytes32 id = _sendMessage(
 | 
			
		||||
            _receiver,
 | 
			
		||||
            uint64(_baseParams.dstChainID),
 | 
			
		||||
            _dstSwap,
 | 
			
		||||
            _maxBridgeSlippage,
 | 
			
		||||
            _beforeSwapAndSendMessage(),
 | 
			
		||||
            _fee,
 | 
			
		||||
            _baseParams.srcInputToken,
 | 
			
		||||
            _baseParams.srcInputAmount,
 | 
			
		||||
            true
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        emit CrossChainRequestSent(id, _baseParams);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										392
									
								
								Interchain-message/contracts/message/apps/RubicRouterV2.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										392
									
								
								Interchain-message/contracts/message/apps/RubicRouterV2.sol
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,392 @@
 | 
			
		|||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
pragma solidity >=0.8.9;
 | 
			
		||||
 | 
			
		||||
import "./TransferSwapV2.sol";
 | 
			
		||||
import "./TransferSwapV3.sol";
 | 
			
		||||
import "./TransferSwapInch.sol";
 | 
			
		||||
import "./BridgeSwap.sol";
 | 
			
		||||
 | 
			
		||||
contract RubicRouterV2 is
 | 
			
		||||
    TransferSwapV2,
 | 
			
		||||
    TransferSwapV3,
 | 
			
		||||
    TransferSwapInch,
 | 
			
		||||
    BridgeSwap
 | 
			
		||||
{
 | 
			
		||||
    using SafeERC20Upgradeable for IERC20Upgradeable;
 | 
			
		||||
    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
 | 
			
		||||
 | 
			
		||||
    constructor(
 | 
			
		||||
        uint256 _fixedCryptoFee,
 | 
			
		||||
        uint256 _RubicPlatformFee,
 | 
			
		||||
        address[] memory _routers,
 | 
			
		||||
        address[] memory _tokens,
 | 
			
		||||
        uint256[] memory _minTokenAmounts,
 | 
			
		||||
        uint256[] memory _maxTokenAmounts,
 | 
			
		||||
        uint256[] memory _blockchainIDs,
 | 
			
		||||
        uint256[] memory _blockchainToGasFee,
 | 
			
		||||
        address _relayer,
 | 
			
		||||
        address _messageBus,
 | 
			
		||||
        address _nativeWrap
 | 
			
		||||
    ) {
 | 
			
		||||
        initialize(
 | 
			
		||||
            _fixedCryptoFee,
 | 
			
		||||
            _RubicPlatformFee,
 | 
			
		||||
            _routers,
 | 
			
		||||
            _tokens,
 | 
			
		||||
            _minTokenAmounts,
 | 
			
		||||
            _maxTokenAmounts,
 | 
			
		||||
            _blockchainIDs,
 | 
			
		||||
            _blockchainToGasFee
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        nativeWrap = _nativeWrap;
 | 
			
		||||
        messageBus = _messageBus;
 | 
			
		||||
        _setupRole(RELAYER_ROLE, _relayer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function initialize(
 | 
			
		||||
        uint256 _fixedCryptoFee,
 | 
			
		||||
        uint256 _RubicPlatformFee,
 | 
			
		||||
        address[] memory _routers,
 | 
			
		||||
        address[] memory _tokens,
 | 
			
		||||
        uint256[] memory _minTokenAmounts,
 | 
			
		||||
        uint256[] memory _maxTokenAmounts,
 | 
			
		||||
        uint256[] memory _blockchainIDs,
 | 
			
		||||
        uint256[] memory _blockchainToGasFee
 | 
			
		||||
    ) private initializer {
 | 
			
		||||
        __WithDestinationFunctionalityInit(
 | 
			
		||||
            _fixedCryptoFee,
 | 
			
		||||
            _RubicPlatformFee,
 | 
			
		||||
            _routers,
 | 
			
		||||
            _tokens,
 | 
			
		||||
            _minTokenAmounts,
 | 
			
		||||
            _maxTokenAmounts,
 | 
			
		||||
            _blockchainIDs,
 | 
			
		||||
            _blockchainToGasFee
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice called by MessageBus when the tokens are checked to be arrived at this contract's address.
 | 
			
		||||
               sends the amount received to the receiver. swaps beforehand if swap behavior is defined in message
 | 
			
		||||
     * NOTE: if the swap fails, it sends the tokens received directly to the receiver as fallback behavior
 | 
			
		||||
     * @param _token the address of the token sent through the bridge
 | 
			
		||||
     * @param _amount the amount of tokens received at this contract through the cross-chain bridge
 | 
			
		||||
     * @param _srcChainId source chain ID
 | 
			
		||||
     * @param _message SwapRequestDst message that defines the swap behavior on this destination chain
 | 
			
		||||
     */
 | 
			
		||||
    function executeMessageWithTransfer(
 | 
			
		||||
        address,
 | 
			
		||||
        address _token,
 | 
			
		||||
        uint256 _amount,
 | 
			
		||||
        uint64 _srcChainId,
 | 
			
		||||
        bytes calldata _message,
 | 
			
		||||
        address _relayer
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        override
 | 
			
		||||
        onlyMessageBus
 | 
			
		||||
        nonReentrant
 | 
			
		||||
        whenNotPaused
 | 
			
		||||
        onlyRelayer(_relayer)
 | 
			
		||||
        returns (ExecutionStatus)
 | 
			
		||||
    {
 | 
			
		||||
        SwapRequestDest memory m = abi.decode((_message), (SwapRequestDest));
 | 
			
		||||
        bytes32 id = _computeSwapRequestId(
 | 
			
		||||
            m.swap.receiverEOA,
 | 
			
		||||
            _srcChainId,
 | 
			
		||||
            uint64(block.chainid),
 | 
			
		||||
            _message
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        _amount = accrueTokenFees(
 | 
			
		||||
            m.swap.integrator,
 | 
			
		||||
            integratorToFeeInfo[m.swap.integrator],
 | 
			
		||||
            _amount,
 | 
			
		||||
            0,
 | 
			
		||||
            _token
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        address _outputToken = _retrieveDstTokenAddress(m.swap);
 | 
			
		||||
 | 
			
		||||
        if (m.swap.version == SwapVersion.v3) {
 | 
			
		||||
            _executeDstSwapV3(_token, _outputToken, _amount, id, m);
 | 
			
		||||
        } else if (m.swap.version == SwapVersion.bridge) {
 | 
			
		||||
            _executeDstBridge(_token, _amount, id, m);
 | 
			
		||||
        } else {
 | 
			
		||||
            _executeDstSwapV2(_token, _outputToken, _amount, id, m);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // always return true since swap failure is already handled in-place
 | 
			
		||||
        return ExecutionStatus.Success;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice called by MessageBus when the executeMessageWithTransfer call fails. does nothing but emitting a "fail" event
 | 
			
		||||
     * @param _srcChainId source chain ID
 | 
			
		||||
     * @param _message SwapRequestDst message that defines the swap behavior on this destination chain
 | 
			
		||||
     * execution on dst chain
 | 
			
		||||
     */
 | 
			
		||||
    function executeMessageWithTransferFallback(
 | 
			
		||||
        address, // _sender
 | 
			
		||||
        address _token,
 | 
			
		||||
        uint256 _amount,
 | 
			
		||||
        uint64 _srcChainId,
 | 
			
		||||
        bytes calldata _message,
 | 
			
		||||
        address _relayer
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        override
 | 
			
		||||
        onlyMessageBus
 | 
			
		||||
        nonReentrant
 | 
			
		||||
        onlyRelayer(_relayer)
 | 
			
		||||
        returns (ExecutionStatus)
 | 
			
		||||
    {
 | 
			
		||||
        SwapRequestDest memory m = abi.decode((_message), (SwapRequestDest));
 | 
			
		||||
 | 
			
		||||
        bytes32 id = _computeSwapRequestId(
 | 
			
		||||
            m.swap.receiverEOA,
 | 
			
		||||
            _srcChainId,
 | 
			
		||||
            uint64(block.chainid),
 | 
			
		||||
            _message
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // collect data about failed cross-chain for manual refund
 | 
			
		||||
        refundDetails[id] = RefundData(
 | 
			
		||||
            m.swap.integrator,
 | 
			
		||||
            _token,
 | 
			
		||||
            _amount,
 | 
			
		||||
            m.swap.receiverEOA,
 | 
			
		||||
            m.swap.nativeOut
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Failed status means user hasn't received funds
 | 
			
		||||
        _afterTargetProcessing(id, _token, _amount, SwapStatus.Failed);
 | 
			
		||||
        // always return Fail to mark this transfer as failed since if this function is called then there nothing more
 | 
			
		||||
        // we can do in this app as the swap failures are already handled in executeMessageWithTransfer
 | 
			
		||||
        return ExecutionStatus.Fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // called on source chain for handling of bridge failures (bad liquidity, bad slippage, etc...)
 | 
			
		||||
    function executeMessageWithTransferRefund(
 | 
			
		||||
        address _token,
 | 
			
		||||
        uint256 _amount,
 | 
			
		||||
        bytes calldata _message,
 | 
			
		||||
        address _relayer
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        override
 | 
			
		||||
        onlyMessageBus
 | 
			
		||||
        nonReentrant
 | 
			
		||||
        whenNotPaused
 | 
			
		||||
        onlyRelayer(_relayer)
 | 
			
		||||
        returns (ExecutionStatus)
 | 
			
		||||
    {
 | 
			
		||||
        SwapRequestDest memory m = abi.decode((_message), (SwapRequestDest));
 | 
			
		||||
 | 
			
		||||
        bytes32 id = _computeSwapRequestId(
 | 
			
		||||
            m.swap.receiverEOA,
 | 
			
		||||
            uint64(block.chainid),
 | 
			
		||||
            m.dstChainId,
 | 
			
		||||
            _message
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        _sendToken(_token, _amount, m.swap.receiverEOA, m.swap.nativeOut);
 | 
			
		||||
 | 
			
		||||
        _afterTargetProcessing(id, _token, _amount, SwapStatus.Fallback);
 | 
			
		||||
 | 
			
		||||
        return ExecutionStatus.Success;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // no need to swap, directly send the bridged token to user
 | 
			
		||||
    function _executeDstBridge(
 | 
			
		||||
        address _inputToken,
 | 
			
		||||
        uint256 _amount,
 | 
			
		||||
        bytes32 _id,
 | 
			
		||||
        SwapRequestDest memory _msgDst
 | 
			
		||||
    ) private {
 | 
			
		||||
        _sendToken(
 | 
			
		||||
            _inputToken,
 | 
			
		||||
            _amount,
 | 
			
		||||
            _msgDst.swap.receiverEOA,
 | 
			
		||||
            _msgDst.swap.nativeOut
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        _afterTargetProcessing(_id, _inputToken, _amount, SwapStatus.Succeeded);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _executeDstSwapV2(
 | 
			
		||||
        address _inputToken,
 | 
			
		||||
        address _outputToken,
 | 
			
		||||
        uint256 _amount,
 | 
			
		||||
        bytes32 _id,
 | 
			
		||||
        SwapRequestDest memory _msgDst
 | 
			
		||||
    ) private isTransit(_inputToken, _msgDst.swap.path[0]) {
 | 
			
		||||
        SwapInfoV2 memory _dstSwap = SwapInfoV2({
 | 
			
		||||
            dex: _msgDst.swap.dex,
 | 
			
		||||
            path: _msgDst.swap.path,
 | 
			
		||||
            deadline: _msgDst.swap.deadline,
 | 
			
		||||
            amountOutMinimum: _msgDst.swap.amountOutMinimum
 | 
			
		||||
        });
 | 
			
		||||
        uint256 balanceBefore = IERC20Upgradeable(_outputToken).balanceOf(
 | 
			
		||||
            address(this)
 | 
			
		||||
        );
 | 
			
		||||
        (bool success, ) = _trySwapV2(_dstSwap, _amount);
 | 
			
		||||
        uint256 dstAmount = IERC20Upgradeable(_outputToken).balanceOf(
 | 
			
		||||
            address(this)
 | 
			
		||||
        ) - balanceBefore;
 | 
			
		||||
        if (success) {
 | 
			
		||||
            _sendToken(
 | 
			
		||||
                _outputToken,
 | 
			
		||||
                dstAmount,
 | 
			
		||||
                _msgDst.swap.receiverEOA,
 | 
			
		||||
                _msgDst.swap.nativeOut
 | 
			
		||||
            );
 | 
			
		||||
            _afterTargetProcessing(
 | 
			
		||||
                _id,
 | 
			
		||||
                _outputToken,
 | 
			
		||||
                dstAmount,
 | 
			
		||||
                SwapStatus.Succeeded
 | 
			
		||||
            );
 | 
			
		||||
        } else {
 | 
			
		||||
            // handle swap failure, send the received token directly to receiver
 | 
			
		||||
            _sendToken(
 | 
			
		||||
                _inputToken,
 | 
			
		||||
                _amount,
 | 
			
		||||
                _msgDst.swap.receiverEOA,
 | 
			
		||||
                _msgDst.swap.nativeOut
 | 
			
		||||
            );
 | 
			
		||||
            _afterTargetProcessing(
 | 
			
		||||
                _id,
 | 
			
		||||
                _inputToken,
 | 
			
		||||
                _amount,
 | 
			
		||||
                SwapStatus.Fallback
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _executeDstSwapV3(
 | 
			
		||||
        address _inputToken,
 | 
			
		||||
        address _outputToken,
 | 
			
		||||
        uint256 _amount,
 | 
			
		||||
        bytes32 _id,
 | 
			
		||||
        SwapRequestDest memory _msgDst
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        isTransit(_inputToken, address(_getFirstBytes20(_msgDst.swap.pathV3)))
 | 
			
		||||
    {
 | 
			
		||||
        SwapInfoV3 memory _dstSwap = SwapInfoV3({
 | 
			
		||||
            dex: _msgDst.swap.dex,
 | 
			
		||||
            path: _msgDst.swap.pathV3,
 | 
			
		||||
            deadline: _msgDst.swap.deadline,
 | 
			
		||||
            amountOutMinimum: _msgDst.swap.amountOutMinimum
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
        uint256 balanceBefore = IERC20Upgradeable(_outputToken).balanceOf(
 | 
			
		||||
            address(this)
 | 
			
		||||
        );
 | 
			
		||||
        (bool success, ) = _trySwapV3(_dstSwap, _amount);
 | 
			
		||||
        uint256 dstAmount = IERC20Upgradeable(_outputToken).balanceOf(
 | 
			
		||||
            address(this)
 | 
			
		||||
        ) - balanceBefore;
 | 
			
		||||
 | 
			
		||||
        if (success) {
 | 
			
		||||
            _sendToken(
 | 
			
		||||
                _outputToken,
 | 
			
		||||
                dstAmount,
 | 
			
		||||
                _msgDst.swap.receiverEOA,
 | 
			
		||||
                _msgDst.swap.nativeOut
 | 
			
		||||
            );
 | 
			
		||||
            _afterTargetProcessing(
 | 
			
		||||
                _id,
 | 
			
		||||
                _outputToken,
 | 
			
		||||
                dstAmount,
 | 
			
		||||
                SwapStatus.Succeeded
 | 
			
		||||
            );
 | 
			
		||||
        } else {
 | 
			
		||||
            // handle swap failure, send the received token directly to receiver
 | 
			
		||||
            _sendToken(
 | 
			
		||||
                _inputToken,
 | 
			
		||||
                _amount,
 | 
			
		||||
                _msgDst.swap.receiverEOA,
 | 
			
		||||
                _msgDst.swap.nativeOut
 | 
			
		||||
            );
 | 
			
		||||
            _afterTargetProcessing(
 | 
			
		||||
                _id,
 | 
			
		||||
                _inputToken,
 | 
			
		||||
                _amount,
 | 
			
		||||
                SwapStatus.Fallback
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _sendToken(
 | 
			
		||||
        address _token,
 | 
			
		||||
        uint256 _amount,
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        bool _nativeOut
 | 
			
		||||
    ) private {
 | 
			
		||||
        if (_token == nativeWrap && _nativeOut == true) {
 | 
			
		||||
            IWETH(nativeWrap).withdraw(_amount);
 | 
			
		||||
            sendToken(address(0), _amount, _receiver);
 | 
			
		||||
        } else {
 | 
			
		||||
            sendToken(_token, _amount, _receiver);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _afterTargetProcessing(
 | 
			
		||||
        bytes32 _id,
 | 
			
		||||
        address _token,
 | 
			
		||||
        uint256 _amount,
 | 
			
		||||
        SwapStatus _status
 | 
			
		||||
    ) private {
 | 
			
		||||
        processedTransactions[_id] = _status;
 | 
			
		||||
        emit CrossChainProcessed(_id, _token, _amount, _status);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function sweepTokens(address _token, uint256 _amount) external onlyAdmin {
 | 
			
		||||
        sendToken(_token, _amount, msg.sender);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function manualRefund(bytes32 _id)
 | 
			
		||||
        external
 | 
			
		||||
        nonReentrant
 | 
			
		||||
        onlyManagerOrAdmin
 | 
			
		||||
    {
 | 
			
		||||
        SwapStatus _status = processedTransactions[_id];
 | 
			
		||||
        require(
 | 
			
		||||
            _status != SwapStatus.Succeeded && _status != SwapStatus.Fallback
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        RefundData memory refundParams = refundDetails[_id];
 | 
			
		||||
 | 
			
		||||
        uint256 _amount = accrueTokenFees(
 | 
			
		||||
            refundParams.integrator,
 | 
			
		||||
            integratorToFeeInfo[refundParams.integrator],
 | 
			
		||||
            refundParams.amount,
 | 
			
		||||
            0,
 | 
			
		||||
            refundParams.token
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        _sendToken(
 | 
			
		||||
            refundParams.token,
 | 
			
		||||
            _amount,
 | 
			
		||||
            refundParams.to,
 | 
			
		||||
            refundParams.nativeOut
 | 
			
		||||
        );
 | 
			
		||||
        processedTransactions[_id] = SwapStatus.Fallback;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setNativeWrap(address _nativeWrap) external onlyManagerOrAdmin {
 | 
			
		||||
        nativeWrap = _nativeWrap;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setMessageBus(address _messageBus) external onlyManagerOrAdmin {
 | 
			
		||||
        messageBus = _messageBus;
 | 
			
		||||
        emit MessageBusUpdated(messageBus);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										326
									
								
								Interchain-message/contracts/message/apps/RubicRouterV2ETH.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										326
									
								
								Interchain-message/contracts/message/apps/RubicRouterV2ETH.sol
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,326 @@
 | 
			
		|||
//// SPDX-License-Identifier: MIT
 | 
			
		||||
//
 | 
			
		||||
//pragma solidity >=0.8.9;
 | 
			
		||||
//
 | 
			
		||||
//import './TransferSwapV2.sol';
 | 
			
		||||
//import './TransferSwapV3.sol';
 | 
			
		||||
//import './TransferSwapInch.sol';
 | 
			
		||||
//import './BridgeSwap.sol';
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
//contract RubicRouterV2ETH is TransferSwapV2, TransferSwapV3, TransferSwapInch, BridgeSwap {
 | 
			
		||||
//    using SafeERC20Upgradeable for IERC20Upgradeable;
 | 
			
		||||
//    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
 | 
			
		||||
//
 | 
			
		||||
//    event CrossChainProcessed(bytes32 id, uint256 dstAmount, SwapStatus status);
 | 
			
		||||
//
 | 
			
		||||
//    /// @dev This modifier prevents using executor functions
 | 
			
		||||
//    modifier onlyExecutor(address _executor) {
 | 
			
		||||
//        require(hasRole(EXECUTOR_ROLE, _executor), 'SwapBase: caller is not an executor');
 | 
			
		||||
//        _;
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    constructor(
 | 
			
		||||
//        uint256[] memory _blockchainIDs,
 | 
			
		||||
//        uint256[] memory _cryptoFees,
 | 
			
		||||
//        uint256[] memory _platformFees,
 | 
			
		||||
//        address[] memory _tokens,
 | 
			
		||||
//        uint256[] memory _minTokenAmounts,
 | 
			
		||||
//        uint256[] memory _maxTokenAmounts,
 | 
			
		||||
//        address[] memory _routers,
 | 
			
		||||
//        address _executor,
 | 
			
		||||
//        address _messageBus,
 | 
			
		||||
//        address _nativeWrap
 | 
			
		||||
//    ) {
 | 
			
		||||
//        initialize(
 | 
			
		||||
//            _blockchainIDs,
 | 
			
		||||
//            _cryptoFees,
 | 
			
		||||
//            _platformFees,
 | 
			
		||||
//            _tokens,
 | 
			
		||||
//            _minTokenAmounts,
 | 
			
		||||
//            _maxTokenAmounts,
 | 
			
		||||
//            _routers
 | 
			
		||||
//        );
 | 
			
		||||
//
 | 
			
		||||
//        nativeWrap = _nativeWrap;
 | 
			
		||||
//        messageBus = _messageBus;
 | 
			
		||||
//        _setupRole(EXECUTOR_ROLE, _executor);
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    function initialize(
 | 
			
		||||
//        uint256[] memory _blockchainIDs,
 | 
			
		||||
//        uint256[] memory _cryptoFees,
 | 
			
		||||
//        uint256[] memory _platformFees,
 | 
			
		||||
//        address[] memory _tokens,
 | 
			
		||||
//        uint256[] memory _minTokenAmounts,
 | 
			
		||||
//        uint256[] memory _maxTokenAmounts,
 | 
			
		||||
//        address[] memory _routers
 | 
			
		||||
//    ) private initializer {
 | 
			
		||||
//        __MultipleTransitTokenInit(
 | 
			
		||||
//            _blockchainIDs,
 | 
			
		||||
//            _cryptoFees,
 | 
			
		||||
//            _platformFees,
 | 
			
		||||
//            _tokens,
 | 
			
		||||
//            _minTokenAmounts,
 | 
			
		||||
//            _maxTokenAmounts,
 | 
			
		||||
//            _routers
 | 
			
		||||
//        );
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    /**
 | 
			
		||||
//     * @notice called by MessageBus when the tokens are checked to be arrived at this contract's address.
 | 
			
		||||
//               sends the amount received to the receiver. swaps beforehand if swap behavior is defined in message
 | 
			
		||||
//     * NOTE: if the swap fails, it sends the tokens received directly to the receiver as fallback behavior
 | 
			
		||||
//     * @param _token the address of the token sent through the bridge
 | 
			
		||||
//     * @param _amount the amount of tokens received at this contract through the cross-chain bridge
 | 
			
		||||
//     * @param _srcChainId source chain ID
 | 
			
		||||
//     * @param _message SwapRequestV2 message that defines the swap behavior on this destination chain
 | 
			
		||||
//     */
 | 
			
		||||
//    function executeMessageWithTransfer(
 | 
			
		||||
//        address,
 | 
			
		||||
//        address _token,
 | 
			
		||||
//        uint256 _amount,
 | 
			
		||||
//        uint64 _srcChainId,
 | 
			
		||||
//        bytes calldata _message,
 | 
			
		||||
//        address _executor
 | 
			
		||||
//    )
 | 
			
		||||
//        external
 | 
			
		||||
//        payable
 | 
			
		||||
//        override
 | 
			
		||||
//        onlyMessageBus
 | 
			
		||||
//        nonReentrant
 | 
			
		||||
//        whenNotPaused
 | 
			
		||||
//        onlyExecutor(_executor)
 | 
			
		||||
//        returns (ExecutionStatus)
 | 
			
		||||
//    {
 | 
			
		||||
//        SwapRequestDest memory m = abi.decode((_message), (SwapRequestDest));
 | 
			
		||||
//        bytes32 id = _computeSwapRequestId(m.receiver, _srcChainId, uint64(block.chainid), _message);
 | 
			
		||||
//
 | 
			
		||||
//        if (_token == nativeWrap) {
 | 
			
		||||
//            IWETH(nativeWrap).deposit{value: _amount}();
 | 
			
		||||
//        }
 | 
			
		||||
//
 | 
			
		||||
//        _amount = calculateFee(m.swap.integrator, _amount, uint256(_srcChainId), _token);
 | 
			
		||||
//
 | 
			
		||||
//        if (m.swap.version == SwapVersion.v3) {
 | 
			
		||||
//            _executeDstSwapV3(_token, _amount, id, m);
 | 
			
		||||
//        } else if (m.swap.version == SwapVersion.bridge) {
 | 
			
		||||
//            _executeDstBridge(_token, _amount, id, m);
 | 
			
		||||
//        } else {
 | 
			
		||||
//            _executeDstSwapV2(_token, _amount, id, m);
 | 
			
		||||
//        }
 | 
			
		||||
//
 | 
			
		||||
//        // always return true since swap failure is already handled in-place
 | 
			
		||||
//        return ExecutionStatus.Success;
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    /**
 | 
			
		||||
//     * @notice called by MessageBus when the executeMessageWithTransfer call fails. does nothing but emitting a "fail" event
 | 
			
		||||
//     * @param _srcChainId source chain ID
 | 
			
		||||
//     * @param _message SwapRequest message that defines the swap behavior on this destination chain
 | 
			
		||||
//     * execution on dst chain
 | 
			
		||||
//     */
 | 
			
		||||
//    function executeMessageWithTransferFallback(
 | 
			
		||||
//        address, // _sender
 | 
			
		||||
//        address _token,
 | 
			
		||||
//        uint256 _amount,
 | 
			
		||||
//        uint64 _srcChainId,
 | 
			
		||||
//        bytes calldata _message,
 | 
			
		||||
//        address _executor
 | 
			
		||||
//    ) external payable override onlyMessageBus nonReentrant onlyExecutor(_executor) returns (ExecutionStatus) {
 | 
			
		||||
//        SwapRequestDest memory m = abi.decode((_message), (SwapRequestDest));
 | 
			
		||||
//
 | 
			
		||||
//        bytes32 id = _computeSwapRequestId(m.receiver, _srcChainId, uint64(block.chainid), _message);
 | 
			
		||||
//
 | 
			
		||||
//        if (_token == nativeWrap) {
 | 
			
		||||
//            IWETH(nativeWrap).deposit{value: _amount}();
 | 
			
		||||
//        }
 | 
			
		||||
//
 | 
			
		||||
//        // Failed status means user hasn't received funds
 | 
			
		||||
//        SwapStatus status = SwapStatus.Failed;
 | 
			
		||||
//        processedTransactions[id] = status;
 | 
			
		||||
//        emit CrossChainProcessed(id, _amount, status);
 | 
			
		||||
//        // always return Fail to mark this transfer as failed since if this function is called then there nothing more
 | 
			
		||||
//        // we can do in this app as the swap failures are already handled in executeMessageWithTransfer
 | 
			
		||||
//        return ExecutionStatus.Fail;
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    // called on source chain for handling of bridge failures (bad liquidity, bad slippage, etc...)
 | 
			
		||||
//    function executeMessageWithTransferRefund(
 | 
			
		||||
//        address _token,
 | 
			
		||||
//        uint256 _amount,
 | 
			
		||||
//        bytes calldata _message,
 | 
			
		||||
//        address _executor
 | 
			
		||||
//    )
 | 
			
		||||
//        external
 | 
			
		||||
//        payable
 | 
			
		||||
//        override
 | 
			
		||||
//        onlyMessageBus
 | 
			
		||||
//        nonReentrant
 | 
			
		||||
//        whenNotPaused
 | 
			
		||||
//        onlyExecutor(_executor)
 | 
			
		||||
//        returns (ExecutionStatus)
 | 
			
		||||
//    {
 | 
			
		||||
//        SwapRequestDest memory m = abi.decode((_message), (SwapRequestDest));
 | 
			
		||||
//
 | 
			
		||||
//        bytes32 id = _computeSwapRequestId(m.receiver, uint64(block.chainid), m.dstChainId, _message);
 | 
			
		||||
//
 | 
			
		||||
//        if (_token == nativeWrap) {
 | 
			
		||||
//            IWETH(nativeWrap).deposit{value: _amount}();
 | 
			
		||||
//        }
 | 
			
		||||
//
 | 
			
		||||
//        _sendToken(_token, _amount, m.receiver, m.swap.nativeOut);
 | 
			
		||||
//
 | 
			
		||||
//        SwapStatus status = SwapStatus.Fallback;
 | 
			
		||||
//        processedTransactions[id] = status;
 | 
			
		||||
//        emit CrossChainProcessed(id, _amount, status);
 | 
			
		||||
//
 | 
			
		||||
//        return ExecutionStatus.Success;
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    // no need to swap, directly send the bridged token to user
 | 
			
		||||
//    function _executeDstBridge(
 | 
			
		||||
//        address _token,
 | 
			
		||||
//        uint256 _amount,
 | 
			
		||||
//        bytes32 _id,
 | 
			
		||||
//        SwapRequestDest memory _msgDst
 | 
			
		||||
//    ) private {
 | 
			
		||||
//        require(
 | 
			
		||||
//            _token == _msgDst.swap.path[0],
 | 
			
		||||
//            'bridged token must be the same as the first token in destination swap path'
 | 
			
		||||
//        );
 | 
			
		||||
//        require(_msgDst.swap.path.length == 1, 'dst bridge expected');
 | 
			
		||||
//        _sendToken(_msgDst.swap.path[0], _amount, _msgDst.receiver, _msgDst.swap.nativeOut);
 | 
			
		||||
//
 | 
			
		||||
//        SwapStatus status;
 | 
			
		||||
//        status = SwapStatus.Succeeded;
 | 
			
		||||
//
 | 
			
		||||
//        processedTransactions[_id] = status;
 | 
			
		||||
//        emit CrossChainProcessed(_id, _amount, status);
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    function _executeDstSwapV2(
 | 
			
		||||
//        address _token,
 | 
			
		||||
//        uint256 _amount,
 | 
			
		||||
//        bytes32 _id,
 | 
			
		||||
//        SwapRequestDest memory _msgDst
 | 
			
		||||
//    ) private {
 | 
			
		||||
//        require(
 | 
			
		||||
//            _token == _msgDst.swap.path[0],
 | 
			
		||||
//            'bridged token must be the same as the first token in destination swap path'
 | 
			
		||||
//        );
 | 
			
		||||
//        require(_msgDst.swap.path.length > 1, 'dst swap expected');
 | 
			
		||||
//
 | 
			
		||||
//        uint256 dstAmount;
 | 
			
		||||
//        SwapStatus status;
 | 
			
		||||
//
 | 
			
		||||
//        SwapInfoV2 memory _dstSwap = SwapInfoV2({
 | 
			
		||||
//            dex: _msgDst.swap.dex,
 | 
			
		||||
//            path: _msgDst.swap.path,
 | 
			
		||||
//            deadline: _msgDst.swap.deadline,
 | 
			
		||||
//            amountOutMinimum: _msgDst.swap.amountOutMinimum
 | 
			
		||||
//        });
 | 
			
		||||
//
 | 
			
		||||
//        bool success;
 | 
			
		||||
//        (success, dstAmount) = _trySwapV2(_dstSwap, _amount);
 | 
			
		||||
//        if (success) {
 | 
			
		||||
//            _sendToken(_dstSwap.path[_dstSwap.path.length - 1], dstAmount, _msgDst.receiver, _msgDst.swap.nativeOut);
 | 
			
		||||
//            status = SwapStatus.Succeeded;
 | 
			
		||||
//            processedTransactions[_id] = status;
 | 
			
		||||
//        } else {
 | 
			
		||||
//            // handle swap failure, send the received token directly to receiver
 | 
			
		||||
//            _sendToken(_token, _amount, _msgDst.receiver, _msgDst.swap.nativeOut);
 | 
			
		||||
//            dstAmount = _amount;
 | 
			
		||||
//            status = SwapStatus.Fallback;
 | 
			
		||||
//            processedTransactions[_id] = status;
 | 
			
		||||
//        }
 | 
			
		||||
//
 | 
			
		||||
//        emit CrossChainProcessed(_id, dstAmount, status);
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    function _executeDstSwapV3(
 | 
			
		||||
//        address _token,
 | 
			
		||||
//        uint256 _amount,
 | 
			
		||||
//        bytes32 _id,
 | 
			
		||||
//        SwapRequestDest memory _msgDst
 | 
			
		||||
//    ) private {
 | 
			
		||||
//        require(
 | 
			
		||||
//            _token == address(_getFirstBytes20(_msgDst.swap.pathV3)),
 | 
			
		||||
//            'bridged token must be the same as the first token in destination swap path'
 | 
			
		||||
//        );
 | 
			
		||||
//        require(_msgDst.swap.pathV3.length > 20, 'dst swap expected');
 | 
			
		||||
//
 | 
			
		||||
//        uint256 dstAmount;
 | 
			
		||||
//        SwapStatus status;
 | 
			
		||||
//
 | 
			
		||||
//        SwapInfoV3 memory _dstSwap = SwapInfoV3({
 | 
			
		||||
//            dex: _msgDst.swap.dex,
 | 
			
		||||
//            path: _msgDst.swap.pathV3,
 | 
			
		||||
//            deadline: _msgDst.swap.deadline,
 | 
			
		||||
//            amountOutMinimum: _msgDst.swap.amountOutMinimum
 | 
			
		||||
//        });
 | 
			
		||||
//
 | 
			
		||||
//        bool success;
 | 
			
		||||
//        (success, dstAmount) = _trySwapV3(_dstSwap, _amount);
 | 
			
		||||
//        if (success) {
 | 
			
		||||
//            _sendToken(address(_getLastBytes20(_dstSwap.path)), dstAmount, _msgDst.receiver, _msgDst.swap.nativeOut);
 | 
			
		||||
//            status = SwapStatus.Succeeded;
 | 
			
		||||
//            processedTransactions[_id] = status;
 | 
			
		||||
//        } else {
 | 
			
		||||
//            // handle swap failure, send the received token directly to receiver
 | 
			
		||||
//            _sendToken(_token, _amount, _msgDst.receiver, _msgDst.swap.nativeOut);
 | 
			
		||||
//            dstAmount = _amount;
 | 
			
		||||
//            status = SwapStatus.Fallback;
 | 
			
		||||
//            processedTransactions[_id] = status;
 | 
			
		||||
//        }
 | 
			
		||||
//
 | 
			
		||||
//        emit CrossChainProcessed(_id, dstAmount, status);
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    function _sendToken(
 | 
			
		||||
//        address _token,
 | 
			
		||||
//        uint256 _amount,
 | 
			
		||||
//        address _receiver,
 | 
			
		||||
//        bool _nativeOut
 | 
			
		||||
//    ) private {
 | 
			
		||||
//        if (_token == nativeWrap && _nativeOut == true) {
 | 
			
		||||
//            IWETH(nativeWrap).withdraw(_amount);
 | 
			
		||||
//            (bool sent, ) = _receiver.call{value: _amount, gas: 50000}('');
 | 
			
		||||
//            require(sent, 'failed to send native');
 | 
			
		||||
//        } else {
 | 
			
		||||
//            IERC20Upgradeable(_token).safeTransfer(_receiver, _amount);
 | 
			
		||||
//        }
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    function sweepTokens(
 | 
			
		||||
//        address _token,
 | 
			
		||||
//        uint256 _amount,
 | 
			
		||||
//        bool _nativeOut
 | 
			
		||||
//    ) external onlyManagerOrAdmin {
 | 
			
		||||
//        _sendToken(_token, _amount, msg.sender, _nativeOut);
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    function manualRefund(
 | 
			
		||||
//        bytes32 _id,
 | 
			
		||||
//        address _token,
 | 
			
		||||
//        uint256 _amount,
 | 
			
		||||
//        address _to,
 | 
			
		||||
//        bool _nativeOut
 | 
			
		||||
//    ) external nonReentrant {
 | 
			
		||||
//        require(
 | 
			
		||||
//            hasRole(MANAGER_ROLE, msg.sender) || hasRole(EXECUTOR_ROLE, msg.sender) || hasRole(DEFAULT_ADMIN_ROLE, msg.sender)
 | 
			
		||||
//        );
 | 
			
		||||
//        require(processedTransactions[_id] != SwapStatus.Succeeded && processedTransactions[_id] != SwapStatus.Fallback);
 | 
			
		||||
//        _sendToken(_token, _amount, _to, _nativeOut);
 | 
			
		||||
//        processedTransactions[_id] = SwapStatus.Fallback;
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    function setNativeWrap(address _nativeWrap) external onlyManagerOrAdmin {
 | 
			
		||||
//        nativeWrap = _nativeWrap;
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    function setMessageBus(address _messageBus) public onlyManagerOrAdmin {
 | 
			
		||||
//        messageBus = _messageBus;
 | 
			
		||||
//        emit MessageBusUpdated(messageBus);
 | 
			
		||||
//    }
 | 
			
		||||
//}
 | 
			
		||||
							
								
								
									
										280
									
								
								Interchain-message/contracts/message/apps/SwapBase.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										280
									
								
								Interchain-message/contracts/message/apps/SwapBase.sol
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,280 @@
 | 
			
		|||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
pragma solidity >=0.8.9;
 | 
			
		||||
 | 
			
		||||
import "rubic-bridge-base/contracts/architecture/WithDestinationFunctionality.sol";
 | 
			
		||||
 | 
			
		||||
import "rubic-bridge-base/contracts/libraries/SmartApprove.sol";
 | 
			
		||||
 | 
			
		||||
import "../framework/MessageSenderApp.sol";
 | 
			
		||||
import "../../interfaces/IWETH.sol";
 | 
			
		||||
 | 
			
		||||
contract SwapBase is MessageSenderApp, WithDestinationFunctionality {
 | 
			
		||||
    using SafeERC20Upgradeable for IERC20Upgradeable;
 | 
			
		||||
    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
 | 
			
		||||
 | 
			
		||||
    address public nativeWrap;
 | 
			
		||||
    uint64 public nonce;
 | 
			
		||||
 | 
			
		||||
    mapping(bytes32 => RefundData) public refundDetails;
 | 
			
		||||
 | 
			
		||||
    modifier isTransit(address _transitToken, address _tokenInPath) {
 | 
			
		||||
        checkIsTransit(_transitToken, _tokenInPath);
 | 
			
		||||
        _;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ============== struct for refunds ==============
 | 
			
		||||
 | 
			
		||||
    struct RefundData {
 | 
			
		||||
        address integrator; // integrator address in order to take commission
 | 
			
		||||
        address token; // transit token
 | 
			
		||||
        uint256 amount; // amount of transit token
 | 
			
		||||
        address to; // recipient
 | 
			
		||||
        bool nativeOut; // receive wrapped/native
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ============== struct for V2 like dexes ==============
 | 
			
		||||
 | 
			
		||||
    struct SwapInfoV2 {
 | 
			
		||||
        address dex; // the DEX to use for the swap
 | 
			
		||||
        // if this array has only one element, it means no need to swap
 | 
			
		||||
        address[] path;
 | 
			
		||||
        // the following fields are only needed if path.length > 1
 | 
			
		||||
        uint256 deadline; // deadline for the swap
 | 
			
		||||
        uint256 amountOutMinimum; // minimum receive amount for the swap
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ============== struct for V3 like dexes ==============
 | 
			
		||||
 | 
			
		||||
    struct SwapInfoV3 {
 | 
			
		||||
        address dex; // the DEX to use for the swap
 | 
			
		||||
        bytes path;
 | 
			
		||||
        uint256 deadline;
 | 
			
		||||
        uint256 amountOutMinimum;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ============== struct for inch swap ==============
 | 
			
		||||
 | 
			
		||||
    struct SwapInfoInch {
 | 
			
		||||
        address dex;
 | 
			
		||||
        // path is tokenIn, tokenOut
 | 
			
		||||
        address[] path;
 | 
			
		||||
        bytes data;
 | 
			
		||||
        uint256 amountOutMinimum;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ============== struct dstSwap ==============
 | 
			
		||||
    // This is needed to make v2 -> SGN -> v3 swaps and etc.
 | 
			
		||||
 | 
			
		||||
    struct SwapInfoDest {
 | 
			
		||||
        address dex; // dex address
 | 
			
		||||
        bool nativeOut;
 | 
			
		||||
        address receiverEOA; // EOA recipient in dst chain
 | 
			
		||||
        address integrator;
 | 
			
		||||
        SwapVersion version; // identifies swap type
 | 
			
		||||
        address[] path; // path address for v2 and inch
 | 
			
		||||
        bytes pathV3; // path address for v3
 | 
			
		||||
        uint256 deadline; // for v2 and v3
 | 
			
		||||
        uint256 amountOutMinimum;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct SwapRequestDest {
 | 
			
		||||
        SwapInfoDest swap;
 | 
			
		||||
        uint64 nonce;
 | 
			
		||||
        uint64 dstChainId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enum SwapVersion {
 | 
			
		||||
        v2,
 | 
			
		||||
        v3,
 | 
			
		||||
        bridge
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ============== common checks for src swaps ==============
 | 
			
		||||
 | 
			
		||||
    function _deriveFeeAndPerformChecksNative(
 | 
			
		||||
        uint256 _amountIn,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        address _integrator,
 | 
			
		||||
        address srcInputToken
 | 
			
		||||
    ) internal onlyEOA whenNotPaused returns (uint256 _fee) {
 | 
			
		||||
        require(srcInputToken == nativeWrap, "token mismatch");
 | 
			
		||||
        require(msg.value >= _amountIn, "amount insufficient");
 | 
			
		||||
        IWETH(nativeWrap).deposit{value: _amountIn}();
 | 
			
		||||
 | 
			
		||||
        _fee =
 | 
			
		||||
            accrueFixedAndGasFees(
 | 
			
		||||
                _integrator,
 | 
			
		||||
                integratorToFeeInfo[_integrator],
 | 
			
		||||
                _dstChainId
 | 
			
		||||
            ) -
 | 
			
		||||
            _amountIn;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _deriveFeeAndPerformChecks(
 | 
			
		||||
        uint256 _amountIn,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        address _integrator,
 | 
			
		||||
        address srcInputToken
 | 
			
		||||
    ) internal onlyEOA whenNotPaused returns (uint256 _fee) {
 | 
			
		||||
        IERC20Upgradeable(srcInputToken).safeTransferFrom(
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            address(this),
 | 
			
		||||
            _amountIn
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        _fee = accrueFixedAndGasFees(
 | 
			
		||||
            _integrator,
 | 
			
		||||
            integratorToFeeInfo[_integrator],
 | 
			
		||||
            _dstChainId
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ============== Celer call ==============
 | 
			
		||||
 | 
			
		||||
    function _sendMessage(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        SwapInfoDest calldata _dstSwap,
 | 
			
		||||
        uint32 _maxBridgeSlippage,
 | 
			
		||||
        uint64 _nonce,
 | 
			
		||||
        uint256 _fee,
 | 
			
		||||
        address _srcOutputToken,
 | 
			
		||||
        uint256 _srcAmtOut,
 | 
			
		||||
        bool _success
 | 
			
		||||
    ) internal returns (bytes32 id) {
 | 
			
		||||
        if (!_success) revert("src swap failed");
 | 
			
		||||
 | 
			
		||||
        require(_srcAmtOut >= minTokenAmount[_srcOutputToken], "less than min");
 | 
			
		||||
        if (maxTokenAmount[_srcOutputToken] > 0) {
 | 
			
		||||
            require(
 | 
			
		||||
                _srcAmtOut <= maxTokenAmount[_srcOutputToken],
 | 
			
		||||
                "greater than max"
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        id = _crossChainTransferWithSwap(
 | 
			
		||||
            _receiver,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _dstSwap,
 | 
			
		||||
            _maxBridgeSlippage,
 | 
			
		||||
            _nonce,
 | 
			
		||||
            _fee,
 | 
			
		||||
            _srcOutputToken,
 | 
			
		||||
            _srcAmtOut
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _crossChainTransferWithSwap(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        SwapInfoDest calldata _dstSwap,
 | 
			
		||||
        uint32 _maxBridgeSlippage,
 | 
			
		||||
        uint64 _nonce,
 | 
			
		||||
        uint256 _fee,
 | 
			
		||||
        address srcOutputToken,
 | 
			
		||||
        uint256 srcAmtOut
 | 
			
		||||
    ) private returns (bytes32 id) {
 | 
			
		||||
        // todo increment nonce in compute ...
 | 
			
		||||
        require(_dstSwap.path.length > 0, "empty dst swap path");
 | 
			
		||||
        bytes memory message = abi.encode(
 | 
			
		||||
            SwapRequestDest({
 | 
			
		||||
                swap: _dstSwap,
 | 
			
		||||
                nonce: nonce,
 | 
			
		||||
                dstChainId: _dstChainId
 | 
			
		||||
            })
 | 
			
		||||
        );
 | 
			
		||||
        id = _computeSwapRequestId(
 | 
			
		||||
            _dstSwap.receiverEOA,
 | 
			
		||||
            uint64(block.chainid),
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            message
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        sendMessageWithTransfer(
 | 
			
		||||
            _receiver,
 | 
			
		||||
            srcOutputToken,
 | 
			
		||||
            srcAmtOut,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _nonce,
 | 
			
		||||
            _maxBridgeSlippage,
 | 
			
		||||
            message,
 | 
			
		||||
            _fee
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ============== Utilities ==============
 | 
			
		||||
 | 
			
		||||
    function _beforeSwapAndSendMessage() internal returns (uint64) {
 | 
			
		||||
        return ++nonce;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _retrieveDstTokenAddress(SwapInfoDest memory _swapInfo)
 | 
			
		||||
        internal
 | 
			
		||||
        pure
 | 
			
		||||
        returns (address)
 | 
			
		||||
    {
 | 
			
		||||
        if (_swapInfo.version == SwapVersion.v3) {
 | 
			
		||||
            require(_swapInfo.pathV3.length > 20, "dst swap expected");
 | 
			
		||||
 | 
			
		||||
            return address(_getLastBytes20(_swapInfo.pathV3));
 | 
			
		||||
        } else if (_swapInfo.version == SwapVersion.v2) {
 | 
			
		||||
            require(_swapInfo.path.length > 1, "dst swap expected");
 | 
			
		||||
 | 
			
		||||
            return _swapInfo.path[_swapInfo.path.length - 1];
 | 
			
		||||
        } else {
 | 
			
		||||
            require(_swapInfo.path.length == 1, "dst bridge expected");
 | 
			
		||||
            return _swapInfo.path[0];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // returns address of first token for V3
 | 
			
		||||
    function _getFirstBytes20(bytes memory input)
 | 
			
		||||
        internal
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes20 result)
 | 
			
		||||
    {
 | 
			
		||||
        assembly {
 | 
			
		||||
            result := mload(add(input, 32))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // returns address of tokenOut for V3
 | 
			
		||||
    function _getLastBytes20(bytes memory input)
 | 
			
		||||
        internal
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes20 result)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 offset = input.length + 12;
 | 
			
		||||
        assembly {
 | 
			
		||||
            result := mload(add(input, offset))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _computeSwapRequestId(
 | 
			
		||||
        address _receiverEOA,
 | 
			
		||||
        uint64 _srcChainId,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        bytes memory _message
 | 
			
		||||
    ) internal pure returns (bytes32) {
 | 
			
		||||
        return
 | 
			
		||||
            keccak256(
 | 
			
		||||
                abi.encodePacked(
 | 
			
		||||
                    _receiverEOA,
 | 
			
		||||
                    _srcChainId,
 | 
			
		||||
                    _dstChainId,
 | 
			
		||||
                    _message
 | 
			
		||||
                )
 | 
			
		||||
            );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Function to check if the address in path is transit token received from Celer
 | 
			
		||||
     */
 | 
			
		||||
    function checkIsTransit(address _transitToken, address _tokenInPath)
 | 
			
		||||
        internal
 | 
			
		||||
        pure
 | 
			
		||||
    {
 | 
			
		||||
        require(_transitToken == _tokenInPath, "first token must be transit");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										146
									
								
								Interchain-message/contracts/message/apps/TransferSwapInch.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								Interchain-message/contracts/message/apps/TransferSwapInch.sol
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,146 @@
 | 
			
		|||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
pragma solidity >=0.8.9;
 | 
			
		||||
 | 
			
		||||
import "./SwapBase.sol";
 | 
			
		||||
 | 
			
		||||
contract TransferSwapInch is SwapBase {
 | 
			
		||||
    using AddressUpgradeable for address payable;
 | 
			
		||||
    using SafeERC20Upgradeable for IERC20Upgradeable;
 | 
			
		||||
    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
 | 
			
		||||
 | 
			
		||||
    function transferWithSwapInchNative(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        uint256 _amountIn,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        SwapInfoInch calldata _srcSwap,
 | 
			
		||||
        SwapInfoDest calldata _dstSwap,
 | 
			
		||||
        uint32 _maxBridgeSlippage
 | 
			
		||||
    ) external payable {
 | 
			
		||||
        uint256 _fee = _deriveFeeAndPerformChecksNative(
 | 
			
		||||
            _amountIn,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _dstSwap.integrator,
 | 
			
		||||
            _srcSwap.path[0]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        _swapAndSendMessageInch(
 | 
			
		||||
            _receiver,
 | 
			
		||||
            _amountIn,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _srcSwap,
 | 
			
		||||
            _dstSwap,
 | 
			
		||||
            _maxBridgeSlippage,
 | 
			
		||||
            _fee,
 | 
			
		||||
            _srcSwap.path[_srcSwap.path.length - 1]
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function transferWithSwapInch(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        uint256 _amountIn,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        SwapInfoInch calldata _srcSwap,
 | 
			
		||||
        SwapInfoDest calldata _dstSwap,
 | 
			
		||||
        uint32 _maxBridgeSlippage
 | 
			
		||||
    ) external payable {
 | 
			
		||||
        uint256 _fee = _deriveFeeAndPerformChecks(
 | 
			
		||||
            _amountIn,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _dstSwap.integrator,
 | 
			
		||||
            _srcSwap.path[0]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        _swapAndSendMessageInch(
 | 
			
		||||
            _receiver,
 | 
			
		||||
            _amountIn,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _srcSwap,
 | 
			
		||||
            _dstSwap,
 | 
			
		||||
            _maxBridgeSlippage,
 | 
			
		||||
            _fee,
 | 
			
		||||
            _srcSwap.path[_srcSwap.path.length - 1]
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Sends a cross-chain transfer via the liquidity pool-based bridge and sends a message specifying a wanted swap action on the
 | 
			
		||||
               destination chain via the message bus
 | 
			
		||||
     * @param _receiver the app contract that implements the MessageReceiver abstract contract
 | 
			
		||||
     *        NOTE not to be confused with the receiver field in SwapInfoInch which is an EOA address of a user
 | 
			
		||||
     * @param _amountIn the input amount that the user wants to swap and/or bridge
 | 
			
		||||
     * @param _dstChainId destination chain ID
 | 
			
		||||
     * @param _srcSwap a struct containing swap related requirements
 | 
			
		||||
     * @param _dstSwap a struct containing swap related requirements
 | 
			
		||||
     * @param _maxBridgeSlippage the max acceptable slippage at bridge, given as percentage in point (pip). Eg. 5000 means 0.5%.
 | 
			
		||||
     *        Must be greater than minimalMaxSlippage. Receiver is guaranteed to receive at least (100% - max slippage percentage) * amount or the
 | 
			
		||||
     *        transfer can be refunded.
 | 
			
		||||
     * @param _fee the fee to pay to MessageBus.
 | 
			
		||||
     */
 | 
			
		||||
    function _swapAndSendMessageInch(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        uint256 _amountIn,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        SwapInfoInch calldata _srcSwap,
 | 
			
		||||
        SwapInfoDest calldata _dstSwap,
 | 
			
		||||
        uint32 _maxBridgeSlippage,
 | 
			
		||||
        uint256 _fee,
 | 
			
		||||
        address srcOutputToken
 | 
			
		||||
    ) private {
 | 
			
		||||
        BaseCrossChainParams memory _baseParams = BaseCrossChainParams(
 | 
			
		||||
            _srcSwap.path[0],
 | 
			
		||||
            _amountIn,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _retrieveDstTokenAddress(_dstSwap),
 | 
			
		||||
            _dstSwap.amountOutMinimum,
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            _dstSwap.integrator,
 | 
			
		||||
            _srcSwap.dex
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        require(_srcSwap.path.length > 1, "empty swap path");
 | 
			
		||||
 | 
			
		||||
        (bool success, uint256 srcAmtOut) = _trySwapInch(_srcSwap, _amountIn);
 | 
			
		||||
 | 
			
		||||
        bytes32 id = _sendMessage(
 | 
			
		||||
            _receiver,
 | 
			
		||||
            uint64(_baseParams.dstChainID),
 | 
			
		||||
            _dstSwap,
 | 
			
		||||
            _maxBridgeSlippage,
 | 
			
		||||
            _beforeSwapAndSendMessage(),
 | 
			
		||||
            _fee,
 | 
			
		||||
            srcOutputToken,
 | 
			
		||||
            srcAmtOut,
 | 
			
		||||
            success
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        emit CrossChainRequestSent(id, _baseParams);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _trySwapInch(SwapInfoInch memory _swap, uint256 _amount)
 | 
			
		||||
        internal
 | 
			
		||||
        returns (bool ok, uint256 amountOut)
 | 
			
		||||
    {
 | 
			
		||||
        if (!availableRouters.contains(_swap.dex)) {
 | 
			
		||||
            return (false, 0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SmartApprove.smartApprove(_swap.path[0], _amount, _swap.dex);
 | 
			
		||||
 | 
			
		||||
        IERC20Upgradeable Transit = IERC20Upgradeable(
 | 
			
		||||
            _swap.path[_swap.path.length - 1]
 | 
			
		||||
        );
 | 
			
		||||
        uint256 transitBalanceBefore = Transit.balanceOf(address(this));
 | 
			
		||||
 | 
			
		||||
        AddressUpgradeable.functionCall(_swap.dex, _swap.data);
 | 
			
		||||
 | 
			
		||||
        uint256 balanceDif = Transit.balanceOf(address(this)) -
 | 
			
		||||
            transitBalanceBefore;
 | 
			
		||||
 | 
			
		||||
        if (balanceDif >= _swap.amountOutMinimum) {
 | 
			
		||||
            return (true, balanceDif);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (false, 0);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										144
									
								
								Interchain-message/contracts/message/apps/TransferSwapV2.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								Interchain-message/contracts/message/apps/TransferSwapV2.sol
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,144 @@
 | 
			
		|||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
pragma solidity >=0.8.9;
 | 
			
		||||
 | 
			
		||||
import "./SwapBase.sol";
 | 
			
		||||
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
 | 
			
		||||
 | 
			
		||||
contract TransferSwapV2 is SwapBase {
 | 
			
		||||
    using SafeERC20Upgradeable for IERC20Upgradeable;
 | 
			
		||||
    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
 | 
			
		||||
 | 
			
		||||
    function transferWithSwapV2Native(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        uint256 _amountIn,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        SwapInfoV2 calldata _srcSwap,
 | 
			
		||||
        SwapInfoDest calldata _dstSwap,
 | 
			
		||||
        uint32 _maxBridgeSlippage
 | 
			
		||||
    ) external payable {
 | 
			
		||||
        uint256 _fee = _deriveFeeAndPerformChecksNative(
 | 
			
		||||
            _amountIn,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _dstSwap.integrator,
 | 
			
		||||
            _srcSwap.path[0]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        _swapAndSendMessageV2(
 | 
			
		||||
            _receiver,
 | 
			
		||||
            _amountIn,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _srcSwap,
 | 
			
		||||
            _dstSwap,
 | 
			
		||||
            _maxBridgeSlippage,
 | 
			
		||||
            _fee,
 | 
			
		||||
            _srcSwap.path[_srcSwap.path.length - 1]
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function transferWithSwapV2(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        uint256 _amountIn,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        SwapInfoV2 calldata _srcSwap,
 | 
			
		||||
        SwapInfoDest calldata _dstSwap,
 | 
			
		||||
        uint32 _maxBridgeSlippage
 | 
			
		||||
    ) external payable {
 | 
			
		||||
        uint256 _fee = _deriveFeeAndPerformChecks(
 | 
			
		||||
            _amountIn,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _dstSwap.integrator,
 | 
			
		||||
            _srcSwap.path[0]
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        _swapAndSendMessageV2(
 | 
			
		||||
            _receiver,
 | 
			
		||||
            _amountIn,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _srcSwap,
 | 
			
		||||
            _dstSwap,
 | 
			
		||||
            _maxBridgeSlippage,
 | 
			
		||||
            _fee,
 | 
			
		||||
            _srcSwap.path[_srcSwap.path.length - 1]
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Sends a cross-chain transfer via the liquidity pool-based bridge and sends a message specifying a wanted swap action on the
 | 
			
		||||
               destination chain via the message bus
 | 
			
		||||
     * @param _receiver the app contract that implements the MessageReceiver abstract contract
 | 
			
		||||
     *        NOTE not to be confused with the receiver field in SwapInfoV2 which is an EOA address of a user
 | 
			
		||||
     * @param _amountIn the input amount that the user wants to swap and/or bridge
 | 
			
		||||
     * @param _dstChainId destination chain ID
 | 
			
		||||
     * @param _srcSwap a struct containing swap related requirements
 | 
			
		||||
     * @param _dstSwap a struct containing swap related requirements
 | 
			
		||||
     * @param _maxBridgeSlippage the max acceptable slippage at bridge, given as percentage in point (pip). Eg. 5000 means 0.5%.
 | 
			
		||||
     *        Must be greater than minimalMaxSlippage. Receiver is guaranteed to receive at least (100% - max slippage percentage) * amount or the
 | 
			
		||||
     *        transfer can be refunded.
 | 
			
		||||
     * @param _fee the fee to pay to MessageBus.
 | 
			
		||||
     */
 | 
			
		||||
    function _swapAndSendMessageV2(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        uint256 _amountIn,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        SwapInfoV2 calldata _srcSwap,
 | 
			
		||||
        SwapInfoDest calldata _dstSwap,
 | 
			
		||||
        uint32 _maxBridgeSlippage,
 | 
			
		||||
        uint256 _fee,
 | 
			
		||||
        address _outputToken
 | 
			
		||||
    ) private {
 | 
			
		||||
        BaseCrossChainParams memory _baseParams = BaseCrossChainParams(
 | 
			
		||||
            _srcSwap.path[0],
 | 
			
		||||
            _amountIn,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _retrieveDstTokenAddress(_dstSwap),
 | 
			
		||||
            _dstSwap.amountOutMinimum,
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            _dstSwap.integrator,
 | 
			
		||||
            _srcSwap.dex
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        require(_srcSwap.path.length > 1, "empty swap path");
 | 
			
		||||
 | 
			
		||||
        (bool success, uint256 srcAmtOut) = _trySwapV2(_srcSwap, _amountIn);
 | 
			
		||||
 | 
			
		||||
        bytes32 id = _sendMessage(
 | 
			
		||||
            _receiver,
 | 
			
		||||
            uint64(_baseParams.dstChainID),
 | 
			
		||||
            _dstSwap,
 | 
			
		||||
            _maxBridgeSlippage,
 | 
			
		||||
            _beforeSwapAndSendMessage(),
 | 
			
		||||
            _fee,
 | 
			
		||||
            _outputToken,
 | 
			
		||||
            srcAmtOut,
 | 
			
		||||
            success
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        emit CrossChainRequestSent(id, _baseParams);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _trySwapV2(SwapInfoV2 memory _swap, uint256 _amount)
 | 
			
		||||
        internal
 | 
			
		||||
        returns (bool ok, uint256 amountOut)
 | 
			
		||||
    {
 | 
			
		||||
        if (!availableRouters.contains(_swap.dex)) {
 | 
			
		||||
            return (false, 0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SmartApprove.smartApprove(_swap.path[0], _amount, _swap.dex);
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
            IUniswapV2Router02(_swap.dex).swapExactTokensForTokens(
 | 
			
		||||
                _amount,
 | 
			
		||||
                _swap.amountOutMinimum,
 | 
			
		||||
                _swap.path,
 | 
			
		||||
                address(this),
 | 
			
		||||
                _swap.deadline
 | 
			
		||||
            )
 | 
			
		||||
        returns (uint256[] memory amounts) {
 | 
			
		||||
            return (true, amounts[amounts.length - 1]);
 | 
			
		||||
        } catch {
 | 
			
		||||
            return (false, 0);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										151
									
								
								Interchain-message/contracts/message/apps/TransferSwapV3.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								Interchain-message/contracts/message/apps/TransferSwapV3.sol
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,151 @@
 | 
			
		|||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
pragma solidity >=0.8.9;
 | 
			
		||||
 | 
			
		||||
import "./SwapBase.sol";
 | 
			
		||||
import "../../interfaces/IUniswapRouterV3.sol";
 | 
			
		||||
 | 
			
		||||
contract TransferSwapV3 is SwapBase {
 | 
			
		||||
    using SafeERC20Upgradeable for IERC20Upgradeable;
 | 
			
		||||
    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
 | 
			
		||||
 | 
			
		||||
    function transferWithSwapV3Native(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        uint256 _amountIn,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        SwapInfoV3 calldata _srcSwap,
 | 
			
		||||
        SwapInfoDest calldata _dstSwap,
 | 
			
		||||
        uint32 _maxBridgeSlippage
 | 
			
		||||
    ) external payable {
 | 
			
		||||
        uint256 _fee = _deriveFeeAndPerformChecksNative(
 | 
			
		||||
            _amountIn,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _dstSwap.integrator,
 | 
			
		||||
            address(_getFirstBytes20(_srcSwap.path))
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        _swapAndSendMessageV3(
 | 
			
		||||
            _receiver,
 | 
			
		||||
            _amountIn,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _srcSwap,
 | 
			
		||||
            _dstSwap,
 | 
			
		||||
            _maxBridgeSlippage,
 | 
			
		||||
            _fee,
 | 
			
		||||
            address(_getLastBytes20(_srcSwap.path))
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function transferWithSwapV3(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        uint256 _amountIn,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        SwapInfoV3 calldata _srcSwap,
 | 
			
		||||
        SwapInfoDest calldata _dstSwap,
 | 
			
		||||
        uint32 _maxBridgeSlippage
 | 
			
		||||
    ) external payable {
 | 
			
		||||
        uint256 _fee = _deriveFeeAndPerformChecks(
 | 
			
		||||
            _amountIn,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _dstSwap.integrator,
 | 
			
		||||
            address(_getFirstBytes20(_srcSwap.path))
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        _swapAndSendMessageV3(
 | 
			
		||||
            _receiver,
 | 
			
		||||
            _amountIn,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _srcSwap,
 | 
			
		||||
            _dstSwap,
 | 
			
		||||
            _maxBridgeSlippage,
 | 
			
		||||
            _fee,
 | 
			
		||||
            address(_getLastBytes20(_srcSwap.path))
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Sends a cross-chain transfer via the liquidity pool-based bridge and sends a message specifying a wanted swap action on the
 | 
			
		||||
               destination chain via the message bus
 | 
			
		||||
     * @param _receiver the app contract that implements the MessageReceiver abstract contract
 | 
			
		||||
     *        NOTE not to be confused with the receiver field in SwapInfoV3 which is an EOA address of a user
 | 
			
		||||
     * @param _amountIn the input amount that the user wants to swap and/or bridge
 | 
			
		||||
     * @param _dstChainId destination chain ID
 | 
			
		||||
     * @param _srcSwap a struct containing swap related requirements
 | 
			
		||||
     * @param _dstSwap a struct containing swap related requirements
 | 
			
		||||
     * @param _maxBridgeSlippage the max acceptable slippage at bridge, given as percentage in point (pip). Eg. 5000 means 0.5%.
 | 
			
		||||
     *        Must be greater than minimalMaxSlippage. Receiver is guaranteed to receive at least (100% - max slippage percentage) * amount or the
 | 
			
		||||
     *        transfer can be refunded.
 | 
			
		||||
     * @param _fee the fee to pay to MessageBus.
 | 
			
		||||
     */
 | 
			
		||||
    function _swapAndSendMessageV3(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        uint256 _amountIn,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        SwapInfoV3 calldata _srcSwap,
 | 
			
		||||
        SwapInfoDest calldata _dstSwap,
 | 
			
		||||
        uint32 _maxBridgeSlippage,
 | 
			
		||||
        uint256 _fee,
 | 
			
		||||
        address srcOutputToken
 | 
			
		||||
    ) private {
 | 
			
		||||
        BaseCrossChainParams memory _baseParams = BaseCrossChainParams(
 | 
			
		||||
            address(_getFirstBytes20(_srcSwap.path)),
 | 
			
		||||
            _amountIn,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _retrieveDstTokenAddress(_dstSwap),
 | 
			
		||||
            _dstSwap.amountOutMinimum,
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            _dstSwap.integrator,
 | 
			
		||||
            _srcSwap.dex
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        require(_srcSwap.path.length > 20, "empty swap path");
 | 
			
		||||
 | 
			
		||||
        (bool success, uint256 srcAmtOut) = _trySwapV3(_srcSwap, _amountIn);
 | 
			
		||||
 | 
			
		||||
        bytes32 id = _sendMessage(
 | 
			
		||||
            _receiver,
 | 
			
		||||
            uint64(_baseParams.dstChainID),
 | 
			
		||||
            _dstSwap,
 | 
			
		||||
            _maxBridgeSlippage,
 | 
			
		||||
            _beforeSwapAndSendMessage(), // TODO rename
 | 
			
		||||
            _fee,
 | 
			
		||||
            srcOutputToken,
 | 
			
		||||
            srcAmtOut,
 | 
			
		||||
            success
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        emit CrossChainRequestSent(id, _baseParams);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _trySwapV3(SwapInfoV3 memory _swap, uint256 _amount)
 | 
			
		||||
        internal
 | 
			
		||||
        returns (bool ok, uint256 amountOut)
 | 
			
		||||
    {
 | 
			
		||||
        if (!availableRouters.contains(_swap.dex)) {
 | 
			
		||||
            return (false, 0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SmartApprove.smartApprove(
 | 
			
		||||
            address(_getFirstBytes20(_swap.path)),
 | 
			
		||||
            _amount,
 | 
			
		||||
            _swap.dex
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        IUniswapRouterV3.ExactInputParams memory paramsV3 = IUniswapRouterV3
 | 
			
		||||
            .ExactInputParams(
 | 
			
		||||
                _swap.path,
 | 
			
		||||
                address(this),
 | 
			
		||||
                _swap.deadline,
 | 
			
		||||
                _amount,
 | 
			
		||||
                _swap.amountOutMinimum
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
        try IUniswapRouterV3(_swap.dex).exactInput(paramsV3) returns (
 | 
			
		||||
            uint256 _amountOut
 | 
			
		||||
        ) {
 | 
			
		||||
            return (true, _amountOut);
 | 
			
		||||
        } catch {
 | 
			
		||||
            return (false, 0);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,118 @@
 | 
			
		|||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
pragma solidity >=0.8.9;
 | 
			
		||||
 | 
			
		||||
import "../../interfaces/IMessageReceiverApp.sol";
 | 
			
		||||
 | 
			
		||||
abstract contract MessageReceiverApp is IMessageReceiverApp {
 | 
			
		||||
    address public messageBus;
 | 
			
		||||
    event MessageBusUpdated(address messageBus);
 | 
			
		||||
 | 
			
		||||
    modifier onlyMessageBus() {
 | 
			
		||||
        checkIsMessageBus();
 | 
			
		||||
        _;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function checkIsMessageBus() internal view {
 | 
			
		||||
        require(msg.sender == messageBus, "caller is not message bus");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Called by MessageBus (MessageBusReceiver) if the process is originated from MessageBus (MessageBusSender)'s
 | 
			
		||||
     *         sendMessageWithTransfer it is only called when the tokens are checked to be arrived at this contract's address.
 | 
			
		||||
     * @param _sender The address of the source app contract
 | 
			
		||||
     * @param _token The address of the token that comes out of the bridge
 | 
			
		||||
     * @param _amount The amount of tokens received at this contract through the cross-chain bridge.
 | 
			
		||||
     *        the contract that implements this contract can safely assume that the tokens will arrive before this
 | 
			
		||||
     *        function is called.
 | 
			
		||||
     * @param _srcChainId The source chain ID where the transfer is originated from
 | 
			
		||||
     * @param _message Arbitrary message bytes originated from and encoded by the source app contract
 | 
			
		||||
     * @param _executor Address who called the MessageBus execution function
 | 
			
		||||
     */
 | 
			
		||||
    function executeMessageWithTransfer(
 | 
			
		||||
        address _sender,
 | 
			
		||||
        address _token,
 | 
			
		||||
        uint256 _amount,
 | 
			
		||||
        uint64 _srcChainId,
 | 
			
		||||
        bytes calldata _message,
 | 
			
		||||
        address _executor
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        virtual
 | 
			
		||||
        override
 | 
			
		||||
        onlyMessageBus
 | 
			
		||||
        returns (ExecutionStatus)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Only called by MessageBus (MessageBusReceiver) if
 | 
			
		||||
     *         1. executeMessageWithTransfer reverts, or
 | 
			
		||||
     *         2. executeMessageWithTransfer returns ExecutionStatus.Fail
 | 
			
		||||
     * @param _sender The address of the source app contract
 | 
			
		||||
     * @param _token The address of the token that comes out of the bridge
 | 
			
		||||
     * @param _amount The amount of tokens received at this contract through the cross-chain bridge.
 | 
			
		||||
     *        the contract that implements this contract can safely assume that the tokens will arrive before this
 | 
			
		||||
     *        function is called.
 | 
			
		||||
     * @param _srcChainId The source chain ID where the transfer is originated from
 | 
			
		||||
     * @param _message Arbitrary message bytes originated from and encoded by the source app contract
 | 
			
		||||
     * @param _executor Address who called the MessageBus execution function
 | 
			
		||||
     */
 | 
			
		||||
    function executeMessageWithTransferFallback(
 | 
			
		||||
        address _sender,
 | 
			
		||||
        address _token,
 | 
			
		||||
        uint256 _amount,
 | 
			
		||||
        uint64 _srcChainId,
 | 
			
		||||
        bytes calldata _message,
 | 
			
		||||
        address _executor
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        virtual
 | 
			
		||||
        override
 | 
			
		||||
        onlyMessageBus
 | 
			
		||||
        returns (ExecutionStatus)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Called by MessageBus (MessageBusReceiver) to process refund of the original transfer from this contract
 | 
			
		||||
     * @param _token The token address of the original transfer
 | 
			
		||||
     * @param _amount The amount of the original transfer
 | 
			
		||||
     * @param _message The same message associated with the original transfer
 | 
			
		||||
     * @param _executor Address who called the MessageBus execution function
 | 
			
		||||
     */
 | 
			
		||||
    function executeMessageWithTransferRefund(
 | 
			
		||||
        address _token,
 | 
			
		||||
        uint256 _amount,
 | 
			
		||||
        bytes calldata _message,
 | 
			
		||||
        address _executor
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        virtual
 | 
			
		||||
        override
 | 
			
		||||
        onlyMessageBus
 | 
			
		||||
        returns (ExecutionStatus)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Called by MessageBus (MessageBusReceiver)
 | 
			
		||||
     * @param _sender The address of the source app contract
 | 
			
		||||
     * @param _srcChainId The source chain ID where the transfer is originated from
 | 
			
		||||
     * @param _message Arbitrary message bytes originated from and encoded by the source app contract
 | 
			
		||||
     * @param _executor Address who called the MessageBus execution function
 | 
			
		||||
     */
 | 
			
		||||
    function executeMessage(
 | 
			
		||||
        address _sender,
 | 
			
		||||
        uint64 _srcChainId,
 | 
			
		||||
        bytes calldata _message,
 | 
			
		||||
        address _executor
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        virtual
 | 
			
		||||
        override
 | 
			
		||||
        onlyMessageBus
 | 
			
		||||
        returns (ExecutionStatus)
 | 
			
		||||
    {}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,53 @@
 | 
			
		|||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
pragma solidity >=0.8.9;
 | 
			
		||||
 | 
			
		||||
import "../libraries/MsgDataTypes.sol";
 | 
			
		||||
import "../libraries/MessageSenderLib.sol";
 | 
			
		||||
 | 
			
		||||
import "./MessageReceiverApp.sol";
 | 
			
		||||
 | 
			
		||||
abstract contract MessageSenderApp is MessageReceiverApp {
 | 
			
		||||
    // ============== Utility functions called by apps ==============
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Sends a message associated with a transfer to a contract on another chain.
 | 
			
		||||
     * @param _receiver The address of the destination app contract.
 | 
			
		||||
     * @param _token The address of the token to be sent.
 | 
			
		||||
     * @param _amount The amount of tokens to be sent.
 | 
			
		||||
     * @param _dstChainId The destination chain ID.
 | 
			
		||||
     * @param _nonce A number input to guarantee uniqueness of transferId. Can be timestamp in practice.
 | 
			
		||||
     * @param _maxSlippage The max slippage accepted, given as percentage in point (pip). Eg. 5000 means 0.5%.
 | 
			
		||||
     *        Must be greater than minimalMaxSlippage. Receiver is guaranteed to receive at least
 | 
			
		||||
     *        (100% - max slippage percentage) * amount or the transfer can be refunded.
 | 
			
		||||
     *        Only applicable to the {MsgDataTypes.BridgeSendType.Liquidity}.
 | 
			
		||||
     * @param _message Arbitrary message bytes to be decoded by the destination app contract.
 | 
			
		||||
     *        If message is empty, only the token transfer will be sent
 | 
			
		||||
     * param _bridgeSendType One of the {BridgeSendType} enum.
 | 
			
		||||
     * @param _fee The fee amount to pay to MessageBus.
 | 
			
		||||
     * @return The transfer ID.
 | 
			
		||||
     */
 | 
			
		||||
    function sendMessageWithTransfer(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        address _token,
 | 
			
		||||
        uint256 _amount,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        uint64 _nonce,
 | 
			
		||||
        uint32 _maxSlippage,
 | 
			
		||||
        bytes memory _message,
 | 
			
		||||
        uint256 _fee
 | 
			
		||||
    ) internal returns (bytes32) {
 | 
			
		||||
        return
 | 
			
		||||
            MessageSenderLib.sendMessageWithTransfer(
 | 
			
		||||
                _receiver,
 | 
			
		||||
                _token,
 | 
			
		||||
                _amount,
 | 
			
		||||
                _dstChainId,
 | 
			
		||||
                _nonce,
 | 
			
		||||
                _maxSlippage,
 | 
			
		||||
                _message,
 | 
			
		||||
                messageBus,
 | 
			
		||||
                _fee
 | 
			
		||||
            );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,117 @@
 | 
			
		|||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
pragma solidity >=0.8.9;
 | 
			
		||||
 | 
			
		||||
import "rubic-bridge-base/contracts/libraries/SmartApprove.sol";
 | 
			
		||||
 | 
			
		||||
import "../../interfaces/IBridge.sol";
 | 
			
		||||
import "../../interfaces/IMessageBus.sol";
 | 
			
		||||
 | 
			
		||||
import "./MsgDataTypes.sol";
 | 
			
		||||
 | 
			
		||||
library MessageSenderLib {
 | 
			
		||||
    // ============== Internal library functions called by apps ==============
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Sends a message associated with a transfer to a contract on another chain.
 | 
			
		||||
     * @param _receiver The address of the destination app contract.
 | 
			
		||||
     * @param _token The address of the token to be sent.
 | 
			
		||||
     * @param _amount The amount of tokens to be sent.
 | 
			
		||||
     * @param _dstChainId The destination chain ID.
 | 
			
		||||
     * @param _nonce A number input to guarantee uniqueness of transferId. Can be timestamp in practice.
 | 
			
		||||
     * @param _maxSlippage The max slippage accepted, given as percentage in point (pip). Eg. 5000 means 0.5%.
 | 
			
		||||
     *        Must be greater than minimalMaxSlippage. Receiver is guaranteed to receive at least
 | 
			
		||||
     *        (100% - max slippage percentage) * amount or the transfer can be refunded.
 | 
			
		||||
     *        Only applicable to the {MsgDataTypes.BridgeSendType.Liquidity}.
 | 
			
		||||
     * @param _message Arbitrary message bytes to be decoded by the destination app contract.
 | 
			
		||||
     *        If message is empty, only the token transfer will be sent
 | 
			
		||||
     * param _bridgeSendType One of the {MsgDataTypes.BridgeSendType} enum.
 | 
			
		||||
     * @param _messageBus The address of the MessageBus on this chain.
 | 
			
		||||
     * @param _fee The fee amount to pay to MessageBus.
 | 
			
		||||
     * @return The transfer ID.
 | 
			
		||||
     */
 | 
			
		||||
    function sendMessageWithTransfer(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        address _token,
 | 
			
		||||
        uint256 _amount,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        uint64 _nonce,
 | 
			
		||||
        uint32 _maxSlippage,
 | 
			
		||||
        bytes memory _message,
 | 
			
		||||
        address _messageBus,
 | 
			
		||||
        uint256 _fee
 | 
			
		||||
    ) internal returns (bytes32) {
 | 
			
		||||
        return
 | 
			
		||||
            sendMessageWithLiquidityBridgeTransfer(
 | 
			
		||||
                _receiver,
 | 
			
		||||
                _token,
 | 
			
		||||
                _amount,
 | 
			
		||||
                _dstChainId,
 | 
			
		||||
                _nonce,
 | 
			
		||||
                _maxSlippage,
 | 
			
		||||
                _message,
 | 
			
		||||
                _messageBus,
 | 
			
		||||
                _fee
 | 
			
		||||
            );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Sends a message to an app on another chain via MessageBus with an associated liquidity bridge transfer.
 | 
			
		||||
     * @param _receiver The address of the destination app contract.
 | 
			
		||||
     * @param _token The address of the token to be sent.
 | 
			
		||||
     * @param _amount The amount of tokens to be sent.
 | 
			
		||||
     * @param _dstChainId The destination chain ID.
 | 
			
		||||
     * @param _nonce A number input to guarantee uniqueness of transferId. Can be timestamp in practice.
 | 
			
		||||
     * @param _maxSlippage The max slippage accepted, given as percentage in point (pip). Eg. 5000 means 0.5%.
 | 
			
		||||
     *        Must be greater than minimalMaxSlippage. Receiver is guaranteed to receive at least
 | 
			
		||||
     *        (100% - max slippage percentage) * amount or the transfer can be refunded.
 | 
			
		||||
     * @param _message Arbitrary message bytes to be decoded by the destination app contract.
 | 
			
		||||
     *        If message is empty, only the token transfer will be sent
 | 
			
		||||
     * @param _messageBus The address of the MessageBus on this chain.
 | 
			
		||||
     * @param _fee The fee amount to pay to MessageBus.
 | 
			
		||||
     * @return The transfer ID.
 | 
			
		||||
     */
 | 
			
		||||
    function sendMessageWithLiquidityBridgeTransfer(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        address _token,
 | 
			
		||||
        uint256 _amount,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        uint64 _nonce,
 | 
			
		||||
        uint32 _maxSlippage,
 | 
			
		||||
        bytes memory _message,
 | 
			
		||||
        address _messageBus,
 | 
			
		||||
        uint256 _fee
 | 
			
		||||
    ) internal returns (bytes32) {
 | 
			
		||||
        address bridge = IMessageBus(_messageBus).liquidityBridge();
 | 
			
		||||
        SmartApprove.smartApprove(_token, _amount, bridge);
 | 
			
		||||
        IBridge(bridge).send(
 | 
			
		||||
            _receiver,
 | 
			
		||||
            _token,
 | 
			
		||||
            _amount,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _nonce,
 | 
			
		||||
            _maxSlippage
 | 
			
		||||
        );
 | 
			
		||||
        bytes32 transferId = keccak256(
 | 
			
		||||
            abi.encodePacked(
 | 
			
		||||
                address(this),
 | 
			
		||||
                _receiver,
 | 
			
		||||
                _token,
 | 
			
		||||
                _amount,
 | 
			
		||||
                _dstChainId,
 | 
			
		||||
                _nonce,
 | 
			
		||||
                uint64(block.chainid)
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
        if (_message.length > 0) {
 | 
			
		||||
            IMessageBus(_messageBus).sendMessageWithTransfer{value: _fee}(
 | 
			
		||||
                _receiver,
 | 
			
		||||
                _dstChainId,
 | 
			
		||||
                bridge,
 | 
			
		||||
                transferId,
 | 
			
		||||
                _message
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        return transferId;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,74 @@
 | 
			
		|||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
pragma solidity >=0.8.9;
 | 
			
		||||
 | 
			
		||||
library MsgDataTypes {
 | 
			
		||||
    // bridge operation type at the sender side (src chain)
 | 
			
		||||
    enum BridgeSendType {
 | 
			
		||||
        Null,
 | 
			
		||||
        Liquidity,
 | 
			
		||||
        PegDeposit,
 | 
			
		||||
        PegBurn,
 | 
			
		||||
        PegV2Deposit,
 | 
			
		||||
        PegV2Burn,
 | 
			
		||||
        PegV2BurnFrom
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // bridge operation type at the receiver side (dst chain)
 | 
			
		||||
    enum TransferType {
 | 
			
		||||
        Null,
 | 
			
		||||
        LqRelay, // relay through liquidity bridge
 | 
			
		||||
        LqWithdraw, // withdraw from liquidity bridge
 | 
			
		||||
        PegMint, // mint through pegged token bridge
 | 
			
		||||
        PegWithdraw, // withdraw from original token vault
 | 
			
		||||
        PegV2Mint, // mint through pegged token bridge v2
 | 
			
		||||
        PegV2Withdraw // withdraw from original token vault v2
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enum MsgType {
 | 
			
		||||
        MessageWithTransfer,
 | 
			
		||||
        MessageOnly
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enum TxStatus {
 | 
			
		||||
        Null,
 | 
			
		||||
        Success,
 | 
			
		||||
        Fail,
 | 
			
		||||
        Fallback,
 | 
			
		||||
        Pending // transient state within a transaction
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct TransferInfo {
 | 
			
		||||
        TransferType t;
 | 
			
		||||
        address sender;
 | 
			
		||||
        address receiver;
 | 
			
		||||
        address token;
 | 
			
		||||
        uint256 amount;
 | 
			
		||||
        uint64 wdseq; // only needed for LqWithdraw (refund)
 | 
			
		||||
        uint64 srcChainId;
 | 
			
		||||
        bytes32 refId;
 | 
			
		||||
        bytes32 srcTxHash; // src chain msg tx hash
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct RouteInfo {
 | 
			
		||||
        address sender;
 | 
			
		||||
        address receiver;
 | 
			
		||||
        uint64 srcChainId;
 | 
			
		||||
        bytes32 srcTxHash; // src chain msg tx hash
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct MsgWithTransferExecutionParams {
 | 
			
		||||
        bytes message;
 | 
			
		||||
        TransferInfo transfer;
 | 
			
		||||
        bytes[] sigs;
 | 
			
		||||
        address[] signers;
 | 
			
		||||
        uint256[] powers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct BridgeTransferParams {
 | 
			
		||||
        bytes request;
 | 
			
		||||
        bytes[] sigs;
 | 
			
		||||
        address[] signers;
 | 
			
		||||
        uint256[] powers;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										162
									
								
								Interchain-message/contracts/test/MessageBusSender.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								Interchain-message/contracts/test/MessageBusSender.sol
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,162 @@
 | 
			
		|||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
pragma solidity >=0.8.9;
 | 
			
		||||
 | 
			
		||||
interface ISigsVerifier {
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Verifies that a message is signed by a quorum among the signers.
 | 
			
		||||
     * @param _msg signed message
 | 
			
		||||
     * @param _sigs list of signatures sorted by signer addresses in ascending order
 | 
			
		||||
     * @param _signers sorted list of current signers
 | 
			
		||||
     * @param _powers powers of current signers
 | 
			
		||||
     */
 | 
			
		||||
    function verifySigs(
 | 
			
		||||
        bytes memory _msg,
 | 
			
		||||
        bytes[] calldata _sigs,
 | 
			
		||||
        address[] calldata _signers,
 | 
			
		||||
        uint256[] calldata _powers
 | 
			
		||||
    ) external view;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
contract MessageBusSender {
 | 
			
		||||
    ISigsVerifier public immutable sigsVerifier;
 | 
			
		||||
 | 
			
		||||
    uint256 public feeBase;
 | 
			
		||||
    uint256 public feePerByte;
 | 
			
		||||
    mapping(address => uint256) public withdrawnFees;
 | 
			
		||||
 | 
			
		||||
    event Message(
 | 
			
		||||
        address indexed sender,
 | 
			
		||||
        address receiver,
 | 
			
		||||
        uint256 dstChainId,
 | 
			
		||||
        bytes message,
 | 
			
		||||
        uint256 fee
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    event MessageWithTransfer(
 | 
			
		||||
        address indexed sender,
 | 
			
		||||
        address receiver,
 | 
			
		||||
        uint256 dstChainId,
 | 
			
		||||
        address bridge,
 | 
			
		||||
        bytes32 srcTransferId,
 | 
			
		||||
        bytes message,
 | 
			
		||||
        uint256 fee
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    event FeeBaseUpdated(uint256 feeBase);
 | 
			
		||||
    event FeePerByteUpdated(uint256 feePerByte);
 | 
			
		||||
 | 
			
		||||
    constructor(ISigsVerifier _sigsVerifier) {
 | 
			
		||||
        sigsVerifier = _sigsVerifier;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Sends a message to a contract on another chain.
 | 
			
		||||
     * Sender needs to make sure the uniqueness of the message Id, which is computed as
 | 
			
		||||
     * hash(type.MessageOnly, sender, receiver, srcChainId, srcTxHash, dstChainId, message).
 | 
			
		||||
     * If messages with the same Id are sent, only one of them will succeed at dst chain.
 | 
			
		||||
     * A fee is charged in the native gas token.
 | 
			
		||||
     * @param _receiver The address of the destination app contract.
 | 
			
		||||
     * @param _dstChainId The destination chain ID.
 | 
			
		||||
     * @param _message Arbitrary message bytes to be decoded by the destination app contract.
 | 
			
		||||
     */
 | 
			
		||||
    function sendMessage(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        uint256 _dstChainId,
 | 
			
		||||
        bytes calldata _message
 | 
			
		||||
    ) external payable {
 | 
			
		||||
        require(_dstChainId != block.chainid, "Invalid chainId");
 | 
			
		||||
        uint256 minFee = calcFee(_message);
 | 
			
		||||
        require(msg.value >= minFee, "Insufficient fee");
 | 
			
		||||
        emit Message(msg.sender, _receiver, _dstChainId, _message, msg.value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Sends a message associated with a transfer to a contract on another chain.
 | 
			
		||||
     * If messages with the same srcTransferId are sent, only one of them will succeed.
 | 
			
		||||
     * A fee is charged in the native token.
 | 
			
		||||
     * @param _receiver The address of the destination app contract.
 | 
			
		||||
     * @param _dstChainId The destination chain ID.
 | 
			
		||||
     * @param _srcBridge The bridge contract to send the transfer with.
 | 
			
		||||
     * @param _srcTransferId The transfer ID.
 | 
			
		||||
     * @param _dstChainId The destination chain ID.
 | 
			
		||||
     * @param _message Arbitrary message bytes to be decoded by the destination app contract.
 | 
			
		||||
     */
 | 
			
		||||
    function sendMessageWithTransfer(
 | 
			
		||||
        address _receiver,
 | 
			
		||||
        uint256 _dstChainId,
 | 
			
		||||
        address _srcBridge,
 | 
			
		||||
        bytes32 _srcTransferId,
 | 
			
		||||
        bytes calldata _message
 | 
			
		||||
    ) external payable {
 | 
			
		||||
        require(_dstChainId != block.chainid, "Invalid chainId");
 | 
			
		||||
        uint256 minFee = calcFee(_message);
 | 
			
		||||
        require(msg.value >= minFee, "Insufficient fee");
 | 
			
		||||
        // SGN needs to verify
 | 
			
		||||
        // 1. msg.sender matches sender of the src transfer
 | 
			
		||||
        // 2. dstChainId matches dstChainId of the src transfer
 | 
			
		||||
        // 3. bridge is either liquidity bridge, peg src vault, or peg dst bridge
 | 
			
		||||
        emit MessageWithTransfer(
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            _receiver,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            _srcBridge,
 | 
			
		||||
            _srcTransferId,
 | 
			
		||||
            _message,
 | 
			
		||||
            msg.value
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Withdraws message fee in the form of native gas token.
 | 
			
		||||
     * @param _account The address receiving the fee.
 | 
			
		||||
     * @param _cumulativeFee The cumulative fee credited to the account. Tracked by SGN.
 | 
			
		||||
     * @param _sigs The list of signatures sorted by signing addresses in ascending order. A withdrawal must be
 | 
			
		||||
     * signed-off by +2/3 of the sigsVerifier's current signing power to be delivered.
 | 
			
		||||
     * @param _signers The sorted list of signers.
 | 
			
		||||
     * @param _powers The signing powers of the signers.
 | 
			
		||||
     */
 | 
			
		||||
    function withdrawFee(
 | 
			
		||||
        address _account,
 | 
			
		||||
        uint256 _cumulativeFee,
 | 
			
		||||
        bytes[] calldata _sigs,
 | 
			
		||||
        address[] calldata _signers,
 | 
			
		||||
        uint256[] calldata _powers
 | 
			
		||||
    ) external {
 | 
			
		||||
        bytes32 domain = keccak256(
 | 
			
		||||
            abi.encodePacked(block.chainid, address(this), "withdrawFee")
 | 
			
		||||
        );
 | 
			
		||||
        sigsVerifier.verifySigs(
 | 
			
		||||
            abi.encodePacked(domain, _account, _cumulativeFee),
 | 
			
		||||
            _sigs,
 | 
			
		||||
            _signers,
 | 
			
		||||
            _powers
 | 
			
		||||
        );
 | 
			
		||||
        uint256 amount = _cumulativeFee - withdrawnFees[_account];
 | 
			
		||||
        require(amount > 0, "No new amount to withdraw");
 | 
			
		||||
        withdrawnFees[_account] = _cumulativeFee;
 | 
			
		||||
        (bool sent, ) = _account.call{value: amount, gas: 50000}("");
 | 
			
		||||
        require(sent, "failed to withdraw fee");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice Calculates the required fee for the message.
 | 
			
		||||
     * @param _message Arbitrary message bytes to be decoded by the destination app contract.
 | 
			
		||||
     @ @return The required fee.
 | 
			
		||||
     */
 | 
			
		||||
    function calcFee(bytes calldata _message) public view returns (uint256) {
 | 
			
		||||
        return feeBase + _message.length * feePerByte;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // -------------------- Admin --------------------
 | 
			
		||||
 | 
			
		||||
    function setFeePerByte(uint256 _fee) external {
 | 
			
		||||
        feePerByte = _fee;
 | 
			
		||||
        emit FeePerByteUpdated(feePerByte);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setFeeBase(uint256 _fee) external {
 | 
			
		||||
        feeBase = _fee;
 | 
			
		||||
        emit FeeBaseUpdated(feeBase);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										97
									
								
								Interchain-message/contracts/test/TestERC20.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								Interchain-message/contracts/test/TestERC20.sol
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,97 @@
 | 
			
		|||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
pragma solidity >=0.8.9;
 | 
			
		||||
 | 
			
		||||
contract TestERC20 {
 | 
			
		||||
    mapping(address => uint256) public balanceOf;
 | 
			
		||||
    mapping(address => mapping(address => uint256)) public allowance;
 | 
			
		||||
 | 
			
		||||
    event Transfer(address indexed from, address indexed to, uint256 value);
 | 
			
		||||
 | 
			
		||||
    event Approval(
 | 
			
		||||
        address indexed owner,
 | 
			
		||||
        address indexed spender,
 | 
			
		||||
        uint256 value
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    constructor() {
 | 
			
		||||
        mint(msg.sender, 100000000000 ether);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function decimals() external pure returns (uint256) {
 | 
			
		||||
        return 18;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function mint(address to, uint256 amount) public {
 | 
			
		||||
        uint256 balanceNext = balanceOf[to] + amount;
 | 
			
		||||
        require(balanceNext >= amount, "overflow balance");
 | 
			
		||||
        balanceOf[to] = balanceNext;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function transfer(address recipient, uint256 amount)
 | 
			
		||||
        external
 | 
			
		||||
        returns (bool)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 balanceBefore = balanceOf[msg.sender];
 | 
			
		||||
        require(balanceBefore >= amount, "insufficient balance");
 | 
			
		||||
        balanceOf[msg.sender] = balanceBefore - amount;
 | 
			
		||||
 | 
			
		||||
        uint256 balanceRecipient = balanceOf[recipient];
 | 
			
		||||
        require(
 | 
			
		||||
            balanceRecipient + amount >= balanceRecipient,
 | 
			
		||||
            "recipient balance overflow"
 | 
			
		||||
        );
 | 
			
		||||
        if (!isDeflationary) {
 | 
			
		||||
            balanceOf[recipient] = balanceRecipient + amount;
 | 
			
		||||
        } else {
 | 
			
		||||
            balanceOf[recipient] =
 | 
			
		||||
                balanceRecipient +
 | 
			
		||||
                (amount - (amount * 5) / 100);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        emit Transfer(msg.sender, recipient, amount);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function approve(address spender, uint256 amount) external returns (bool) {
 | 
			
		||||
        allowance[msg.sender][spender] = amount;
 | 
			
		||||
        emit Approval(msg.sender, spender, amount);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool isDeflationary = false;
 | 
			
		||||
 | 
			
		||||
    function setDefl() external {
 | 
			
		||||
        isDeflationary = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function transferFrom(
 | 
			
		||||
        address sender,
 | 
			
		||||
        address recipient,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    ) external returns (bool) {
 | 
			
		||||
        uint256 allowanceBefore = allowance[sender][msg.sender];
 | 
			
		||||
        require(allowanceBefore >= amount, "allowance insufficient");
 | 
			
		||||
 | 
			
		||||
        allowance[sender][msg.sender] = allowanceBefore - amount;
 | 
			
		||||
 | 
			
		||||
        uint256 balanceRecipient = balanceOf[recipient];
 | 
			
		||||
        require(
 | 
			
		||||
            balanceRecipient + amount >= balanceRecipient,
 | 
			
		||||
            "overflow balance recipient"
 | 
			
		||||
        );
 | 
			
		||||
        if (!isDeflationary) {
 | 
			
		||||
            balanceOf[recipient] = balanceRecipient + amount;
 | 
			
		||||
        } else {
 | 
			
		||||
            balanceOf[recipient] =
 | 
			
		||||
                balanceRecipient +
 | 
			
		||||
                (amount - (amount * 5) / 100);
 | 
			
		||||
        }
 | 
			
		||||
        uint256 balanceSender = balanceOf[sender];
 | 
			
		||||
        require(balanceSender >= amount, "underflow balance sender");
 | 
			
		||||
        balanceOf[sender] = balanceSender - amount;
 | 
			
		||||
 | 
			
		||||
        emit Transfer(sender, recipient, amount);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										47
									
								
								Interchain-message/contracts/test/TestMessages.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								Interchain-message/contracts/test/TestMessages.sol
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,47 @@
 | 
			
		|||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
pragma solidity >=0.8.9;
 | 
			
		||||
 | 
			
		||||
import "../message/apps/SwapBase.sol";
 | 
			
		||||
 | 
			
		||||
contract TestMessages is SwapBase {
 | 
			
		||||
    constructor() {}
 | 
			
		||||
 | 
			
		||||
    function getMessage(
 | 
			
		||||
        SwapInfoDest memory _dstSwap,
 | 
			
		||||
        uint64 _nonce,
 | 
			
		||||
        uint64 _dstChainId
 | 
			
		||||
    ) public pure returns (bytes memory) {
 | 
			
		||||
        bytes memory message = abi.encode(
 | 
			
		||||
            SwapRequestDest({
 | 
			
		||||
                swap: _dstSwap,
 | 
			
		||||
                nonce: _nonce,
 | 
			
		||||
                dstChainId: _dstChainId
 | 
			
		||||
            })
 | 
			
		||||
        );
 | 
			
		||||
        return message;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getID(
 | 
			
		||||
        uint64 _chainId,
 | 
			
		||||
        uint64 _dstChainId,
 | 
			
		||||
        SwapInfoDest memory _dstSwap,
 | 
			
		||||
        uint64 _nonce
 | 
			
		||||
    ) public pure returns (bytes32) {
 | 
			
		||||
        bytes memory message = abi.encode(
 | 
			
		||||
            SwapRequestDest({
 | 
			
		||||
                swap: _dstSwap,
 | 
			
		||||
                nonce: _nonce,
 | 
			
		||||
                dstChainId: _dstChainId
 | 
			
		||||
            })
 | 
			
		||||
        );
 | 
			
		||||
        bytes32 id = SwapBase._computeSwapRequestId(
 | 
			
		||||
            _dstSwap.receiverEOA,
 | 
			
		||||
            _chainId,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            message
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return id;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										64
									
								
								Interchain-message/contracts/test/WETH9.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								Interchain-message/contracts/test/WETH9.sol
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,64 @@
 | 
			
		|||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
pragma solidity >=0.8.9;
 | 
			
		||||
 | 
			
		||||
contract WETH9 {
 | 
			
		||||
    string public name = "Wrapped Ether";
 | 
			
		||||
    string public symbol = "WETH";
 | 
			
		||||
    uint8 public decimals = 18;
 | 
			
		||||
 | 
			
		||||
    event Approval(address indexed src, address indexed guy, uint256 wad);
 | 
			
		||||
    event Transfer(address indexed src, address indexed dst, uint256 wad);
 | 
			
		||||
    event Deposit(address indexed dst, uint256 wad);
 | 
			
		||||
    event Withdrawal(address indexed src, uint256 wad);
 | 
			
		||||
 | 
			
		||||
    mapping(address => uint256) public balanceOf;
 | 
			
		||||
    mapping(address => mapping(address => uint256)) public allowance;
 | 
			
		||||
 | 
			
		||||
    function deposit() public payable {
 | 
			
		||||
        balanceOf[msg.sender] += msg.value;
 | 
			
		||||
        emit Deposit(msg.sender, msg.value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function withdraw(uint256 wad) public {
 | 
			
		||||
        require(balanceOf[msg.sender] >= wad);
 | 
			
		||||
        balanceOf[msg.sender] -= wad;
 | 
			
		||||
        payable(msg.sender).transfer(wad);
 | 
			
		||||
        emit Withdrawal(msg.sender, wad);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function mint(uint256 amount) public {
 | 
			
		||||
        uint256 balanceNext = balanceOf[msg.sender] + amount;
 | 
			
		||||
        require(balanceNext >= amount, "overflow balance");
 | 
			
		||||
        balanceOf[msg.sender] = balanceNext;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function totalSupply() public view returns (uint256) {
 | 
			
		||||
        return address(this).balance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function approve(address guy, uint256 wad) public returns (bool) {
 | 
			
		||||
        allowance[msg.sender][guy] = wad;
 | 
			
		||||
        emit Approval(msg.sender, guy, wad);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function transfer(address dst, uint256 wad) public returns (bool) {
 | 
			
		||||
        return transferFrom(msg.sender, dst, wad);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function transferFrom(
 | 
			
		||||
        address src,
 | 
			
		||||
        address dst,
 | 
			
		||||
        uint256 wad
 | 
			
		||||
    ) public returns (bool) {
 | 
			
		||||
        require(balanceOf[src] >= wad);
 | 
			
		||||
 | 
			
		||||
        balanceOf[src] -= wad;
 | 
			
		||||
        balanceOf[dst] += wad;
 | 
			
		||||
 | 
			
		||||
        emit Transfer(src, dst, wad);
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								Interchain-message/deployments/Readme.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								Interchain-message/deployments/Readme.md
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
**Deployments**
 | 
			
		||||
 | 
			
		||||
Ethereum
 | 
			
		||||
[0x53dC7535028e2fcaCa0d847AD108b9240C0801b1](https://etherscan.io/address/0x53dc7535028e2fcaca0d847ad108b9240c0801b1)
 | 
			
		||||
 | 
			
		||||
Fantom
 | 
			
		||||
[0x6B362d1C67D7E4Ff1467dFA38dE642f9D125E8Ad](https://ftmscan.com/address/0x6B362d1C67D7E4Ff1467dFA38dE642f9D125E8Ad)
 | 
			
		||||
 | 
			
		||||
BNB
 | 
			
		||||
[0x8523F3DC779bF2df1151906E933b9225A439Db85](https://bscscan.com/address/0x8523F3DC779bF2df1151906E933b9225A439Db85)
 | 
			
		||||
 | 
			
		||||
Polygon
 | 
			
		||||
[0x0F43F9B778100951Ba18812E8D23E8245df17699](https://polygonscan.com/address/0x0F43F9B778100951Ba18812E8D23E8245df17699)
 | 
			
		||||
 | 
			
		||||
Avalanche
 | 
			
		||||
[0xd82bf61411Ce2F6bd46Fd1e3b0459979809D4787](https://snowtrace.io/address/0xd82bf61411Ce2F6bd46Fd1e3b0459979809D4787)
 | 
			
		||||
 | 
			
		||||
Arbitrum
 | 
			
		||||
[0x53dC7535028e2fcaCa0d847AD108b9240C0801b1](https://arbiscan.io/address/0x53dC7535028e2fcaCa0d847AD108b9240C0801b1)
 | 
			
		||||
 | 
			
		||||
Aurora
 | 
			
		||||
[0x53dC7535028e2fcaCa0d847AD108b9240C0801b1](https://aurorascan.dev/address/0x53dC7535028e2fcaCa0d847AD108b9240C0801b1)
 | 
			
		||||
							
								
								
									
										28
									
								
								Interchain-message/executor/config/cbridge.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								Interchain-message/executor/config/cbridge.toml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
[[multichain]]
 | 
			
		||||
chainID = 5
 | 
			
		||||
name = "Goerli"
 | 
			
		||||
gateway = "https://goerli.infura.io/v3/b44c0379c63b443cb6021964cec0481f" # fill in your Goerli rpc provider url
 | 
			
		||||
# cBridge (liquidity bridge) contract address. Executor relies on events from this
 | 
			
		||||
# contract to double check and make sure funds are transfered to the destination
 | 
			
		||||
# before it attempts messages on the destination chain
 | 
			
		||||
cbridge = "0x358234B325EF9eA8115291A8b81b7d33A2Fa762D"
 | 
			
		||||
# MessageBus contract address. Executor relies this to keep a message execution
 | 
			
		||||
# history (just so you can debug or help out angry customers).
 | 
			
		||||
msgbus = "0x942E8e0e4b021F55b89660c886146e0Ec57F4b5B"
 | 
			
		||||
blkinterval = 15 # polling interval
 | 
			
		||||
blkdelay = 5 # how many blocks confirmations are required
 | 
			
		||||
maxblkdelta = 5000 # max number of blocks per poll request
 | 
			
		||||
 | 
			
		||||
[[multichain]]
 | 
			
		||||
chainID = 97
 | 
			
		||||
name = "BSC Testnet"
 | 
			
		||||
gateway = "https://data-seed-prebsc-2-s3.binance.org:8545/"
 | 
			
		||||
cbridge = "0xf89354F314faF344Abd754924438bA798E306DF2"
 | 
			
		||||
msgbus = "0xAd204986D6cB67A5Bc76a3CB8974823F43Cb9AAA"
 | 
			
		||||
blkinterval = 3
 | 
			
		||||
blkdelay = 8
 | 
			
		||||
maxblkdelta = 5000
 | 
			
		||||
# on some EVM chains the gas estimation can be off. the below fields 
 | 
			
		||||
# are added to make up for the inconsistancies.
 | 
			
		||||
addgasgwei = 2 # add 2 gwei to gas price
 | 
			
		||||
addgasestimateratio = 0.3 # multiply gas limit by this ratio
 | 
			
		||||
							
								
								
									
										25
									
								
								Interchain-message/executor/config/executor.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Interchain-message/executor/config/executor.toml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
[executor]
 | 
			
		||||
# since we don't want the executor to execute messages that are not sent by our
 | 
			
		||||
# SimpleBatchTransfer contract, the following items are added to filter only
 | 
			
		||||
# the ones we care about
 | 
			
		||||
[[executor.contracts]]
 | 
			
		||||
chainid = 5 # Goerli
 | 
			
		||||
address = "0x96C8a3cad47D0249cF20dD5C6B0Fa0c711a310f5"
 | 
			
		||||
[[executor.contracts]]
 | 
			
		||||
chainid = 97 # Bsc testnet
 | 
			
		||||
address = "0xD3F24401591C9e205A938288280C65Da7e5E74f0"
 | 
			
		||||
 | 
			
		||||
[sgnd]
 | 
			
		||||
# SGN testnet node0 grpc. executor reads available messages from this endpoint
 | 
			
		||||
sgn_grpc = "35.165.81.166:9090" 
 | 
			
		||||
# SGN testnet gateway grpc. all tx operations to the SGN is delegated through 
 | 
			
		||||
# a gateway in this test phase
 | 
			
		||||
gateway_grpc = "35.165.81.166:20000" 
 | 
			
		||||
 | 
			
		||||
[eth]
 | 
			
		||||
# Fully qualified absolute path only, "~" would not work
 | 
			
		||||
signer_keystore = ""
 | 
			
		||||
signer_passphrase = ""
 | 
			
		||||
 | 
			
		||||
[db]
 | 
			
		||||
url = "localhost:26257"
 | 
			
		||||
							
								
								
									
										0
									
								
								Interchain-message/executor/eth-ks/signer.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								Interchain-message/executor/eth-ks/signer.json
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										155
									
								
								Interchain-message/hardhat.config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								Interchain-message/hardhat.config.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,155 @@
 | 
			
		|||
import '@typechain/hardhat';
 | 
			
		||||
import '@nomiclabs/hardhat-ethers';
 | 
			
		||||
import '@nomiclabs/hardhat-waffle';
 | 
			
		||||
import '@nomiclabs/hardhat-etherscan';
 | 
			
		||||
import 'hardhat-contract-sizer';
 | 
			
		||||
import 'hardhat-gas-reporter';
 | 
			
		||||
import '@openzeppelin/hardhat-upgrades';
 | 
			
		||||
 | 
			
		||||
import { SolcUserConfig } from 'hardhat/types'
 | 
			
		||||
 | 
			
		||||
import * as dotenv from 'dotenv';
 | 
			
		||||
import {float} from "hardhat/internal/core/params/argumentTypes";
 | 
			
		||||
dotenv.config();
 | 
			
		||||
const DEFAULT_PRIVATE_KEY = process.env.MNEMONIC || '1000000000000000000000000000000000000000000000000000000000000000';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const DEFAULT_COMPILER_SETTINGS: SolcUserConfig = {
 | 
			
		||||
  version: '0.8.15',
 | 
			
		||||
  settings: {
 | 
			
		||||
    optimizer: {
 | 
			
		||||
      enabled: true,
 | 
			
		||||
      runs: 200,
 | 
			
		||||
    },
 | 
			
		||||
    metadata: {
 | 
			
		||||
      bytecodeHash: 'none',
 | 
			
		||||
    },
 | 
			
		||||
    evmVersion: "istanbul",
 | 
			
		||||
  },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  networks: {
 | 
			
		||||
    hardhat: {
 | 
			
		||||
      chainId: 137,
 | 
			
		||||
      forking: {
 | 
			
		||||
        url: `https://polygon-rpc.com`,
 | 
			
		||||
        blockNumber: 27081600 // hardcode block number to increase performance of the local cache
 | 
			
		||||
      },
 | 
			
		||||
      allowUnlimitedContractSize: true,
 | 
			
		||||
      loggingEnabled: false,
 | 
			
		||||
      accounts:{
 | 
			
		||||
        count:100
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    eth: {
 | 
			
		||||
      url: `https://mainnet.infura.io/v3/${process.env.INFURA_ID_PROJECT}`,
 | 
			
		||||
      chainId: 1,
 | 
			
		||||
      accounts: [`0x${DEFAULT_PRIVATE_KEY}`],
 | 
			
		||||
      gasPrice: 20000000000
 | 
			
		||||
    },
 | 
			
		||||
    ropsten: {
 | 
			
		||||
      url: `https://ropsten.infura.io/v3/${process.env.INFURA_ID_PROJECT}`,
 | 
			
		||||
      chainId: 3,
 | 
			
		||||
      accounts: [`0x${DEFAULT_PRIVATE_KEY}`]
 | 
			
		||||
    },
 | 
			
		||||
    rinkeby: {
 | 
			
		||||
      url: `https://rinkeby.infura.io/v3/${process.env.INFURA_ID_PROJECT}`,
 | 
			
		||||
      accounts: [`0x${DEFAULT_PRIVATE_KEY}`]
 | 
			
		||||
    },
 | 
			
		||||
    goerli: {
 | 
			
		||||
      url: `https://goerli.infura.io/v3/${process.env.INFURA_ID_PROJECT}`,
 | 
			
		||||
      chainId: 5,
 | 
			
		||||
      accounts: [`0x${DEFAULT_PRIVATE_KEY}`]
 | 
			
		||||
    },
 | 
			
		||||
    kovan: {
 | 
			
		||||
      url: `https://kovan.infura.io/v3/${process.env.INFURA_ID_PROJECT}`,
 | 
			
		||||
      chainId: 42,
 | 
			
		||||
      accounts: [`0x${DEFAULT_PRIVATE_KEY}`]
 | 
			
		||||
    },
 | 
			
		||||
    bscTest: {
 | 
			
		||||
      url: `https://data-seed-prebsc-2-s3.binance.org:8545`,
 | 
			
		||||
      chainId: 97,
 | 
			
		||||
      accounts: [`0x${DEFAULT_PRIVATE_KEY}`]
 | 
			
		||||
    },
 | 
			
		||||
    bsc: {
 | 
			
		||||
      url: `https://bsc-dataseed.binance.org/`,
 | 
			
		||||
      chainId: 56,
 | 
			
		||||
      accounts: [`0x${DEFAULT_PRIVATE_KEY}`]
 | 
			
		||||
    },
 | 
			
		||||
    polygonMumbai: {
 | 
			
		||||
      url: `https://rpc-mumbai.maticvigil.com`,
 | 
			
		||||
      chainId: 80001,
 | 
			
		||||
      accounts: [`0x${DEFAULT_PRIVATE_KEY}`]
 | 
			
		||||
    },
 | 
			
		||||
    polygon: {
 | 
			
		||||
      url: `https://polygon-rpc.com`,
 | 
			
		||||
      chainId: 137,
 | 
			
		||||
      accounts: [`0x${DEFAULT_PRIVATE_KEY}`]
 | 
			
		||||
    },
 | 
			
		||||
    avalanche: {
 | 
			
		||||
      url: `https://api.avax.network/ext/bc/C/rpc`,
 | 
			
		||||
      chainId: 43114,
 | 
			
		||||
      accounts: [`0x${DEFAULT_PRIVATE_KEY}`]
 | 
			
		||||
    },
 | 
			
		||||
    fantom: {
 | 
			
		||||
      url: `https://rpc.ftm.tools/`,
 | 
			
		||||
      chainId: 250,
 | 
			
		||||
      accounts: [`0x${DEFAULT_PRIVATE_KEY}`]
 | 
			
		||||
    },
 | 
			
		||||
    arbitrum: {
 | 
			
		||||
      url: `https://arb1.arbitrum.io/rpc`,
 | 
			
		||||
      chainId: 42161,
 | 
			
		||||
      accounts: [`0x${DEFAULT_PRIVATE_KEY}`]
 | 
			
		||||
    },
 | 
			
		||||
    aurora: {
 | 
			
		||||
      url: `https://mainnet.aurora.dev`,
 | 
			
		||||
      chainId: 1313161554,
 | 
			
		||||
      accounts: [`0x${DEFAULT_PRIVATE_KEY}`],
 | 
			
		||||
      gasPrice: 80000000 //0.08 gwei
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  etherscan: {
 | 
			
		||||
    apiKey: {
 | 
			
		||||
      mainnet: process.env.ETHERSCAN_API_KEY,
 | 
			
		||||
      ropsten: process.env.ETHERSCAN_API_KEY,
 | 
			
		||||
      rinkeby: process.env.ETHERSCAN_API_KEY,
 | 
			
		||||
      goerli: process.env.ETHERSCAN_API_KEY,
 | 
			
		||||
      kovan: process.env.ETHERSCAN_API_KEY,
 | 
			
		||||
      // binance smart chain
 | 
			
		||||
      bsc: process.env.BSCSCAN_API_KEY,
 | 
			
		||||
      bscTestnet: process.env.BSCSCAN_API_KEY,
 | 
			
		||||
      // fantom mainnet
 | 
			
		||||
      opera: process.env.FANTOMSCAN_API_KEY,
 | 
			
		||||
      ftmTestnet: process.env.FANTOMSCAN_API_KEY,
 | 
			
		||||
      // polygon
 | 
			
		||||
      polygon: process.env.POLYGONSCAN_API_KEY,
 | 
			
		||||
      polygonMumbai: process.env.POLYGONSCAN_API_KEY,
 | 
			
		||||
      // avalanche
 | 
			
		||||
      avalanche: process.env.AVALANCHE_API_KEY,
 | 
			
		||||
      avalancheFujiTestnet: process.env.AVALANCHE_API_KEY,
 | 
			
		||||
      // arbitrum
 | 
			
		||||
      arbitrumOne: process.env.ARBITRUM_API_KEY,
 | 
			
		||||
      arbitrumTestnet: process.env.ARBITRUM_API_KEY,
 | 
			
		||||
      aurora: process.env.AURORA_API_KEY
 | 
			
		||||
    },
 | 
			
		||||
    //apiKey: `${process.env.AURORA_API_KEY}`,
 | 
			
		||||
  },
 | 
			
		||||
  solidity: {
 | 
			
		||||
    compilers: [DEFAULT_COMPILER_SETTINGS]
 | 
			
		||||
  },
 | 
			
		||||
  contractSizer: {
 | 
			
		||||
    alphaSort: false,
 | 
			
		||||
    disambiguatePaths: true,
 | 
			
		||||
    runOnCompile: false
 | 
			
		||||
  },
 | 
			
		||||
  typechain: {
 | 
			
		||||
    outDir: 'typechain',
 | 
			
		||||
    target: 'ethers-v5'
 | 
			
		||||
  },
 | 
			
		||||
  gasReporter: {
 | 
			
		||||
    enabled: process.env.REPORT_GAS === 'true' ? true : false,
 | 
			
		||||
    noColors: true,
 | 
			
		||||
    outputFile: 'reports/gas_usage/summary.txt'
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43016
									
								
								Interchain-message/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										43016
									
								
								Interchain-message/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										54
									
								
								Interchain-message/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								Interchain-message/package.json
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,54 @@
 | 
			
		|||
{
 | 
			
		||||
  "name": "sample-hardhat-project",
 | 
			
		||||
  "version": "1.0.0",
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "lint": "./node_modules/.bin/solhint -f table contracts/**/*.sol && eslint test/** ",
 | 
			
		||||
    "format": "prettier --write contracts/**/*.sol && eslint test/** --fix",
 | 
			
		||||
    "test": "npx hardhat test"
 | 
			
		||||
  },
 | 
			
		||||
  "license": "ISC",
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@nomiclabs/hardhat-ethers": "^2.0.3",
 | 
			
		||||
    "@nomiclabs/hardhat-waffle": "^2.0.1",
 | 
			
		||||
    "@openzeppelin/contracts": "^4.5.0",
 | 
			
		||||
    "@truffle/hdwallet-provider": "^1.5.1",
 | 
			
		||||
    "@typechain/ethers-v5": "^8.0.5",
 | 
			
		||||
    "@typechain/hardhat": "^3.0.0",
 | 
			
		||||
    "dotenv": "^10.0.0",
 | 
			
		||||
    "ganache-core": "^2.13.2",
 | 
			
		||||
    "hardhat": "^2.7.0",
 | 
			
		||||
    "keythereum": "^1.2.0",
 | 
			
		||||
    "rubic-bridge-base": "^1.4.4",
 | 
			
		||||
    "truffle-plugin-verify": "^0.5.15",
 | 
			
		||||
    "web3": "^1.6.0"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@nomiclabs/hardhat-etherscan": "^3.0.3",
 | 
			
		||||
    "@openzeppelin/contracts-upgradeable": "^4.5.2",
 | 
			
		||||
    "@openzeppelin/hardhat-upgrades": "^1.17.0",
 | 
			
		||||
    "@openzeppelin/test-helpers": "^0.5.15",
 | 
			
		||||
    "@types/jest": "^27.0.3",
 | 
			
		||||
    "@types/mocha": "^9.0.0",
 | 
			
		||||
    "@typescript-eslint/eslint-plugin": "^4.33.0",
 | 
			
		||||
    "@typescript-eslint/parser": "^4.33.0",
 | 
			
		||||
    "@uniswap/v2-periphery": "^1.1.0-beta.0",
 | 
			
		||||
    "@uniswap/v3-periphery": "^1.4.0",
 | 
			
		||||
    "chai": "^4.3.4",
 | 
			
		||||
    "eslint": "^7.32.0",
 | 
			
		||||
    "eslint-config-airbnb-base": "^14.2.1",
 | 
			
		||||
    "eslint-config-airbnb-typescript": "^14.0.0",
 | 
			
		||||
    "eslint-config-prettier": "^8.3.0",
 | 
			
		||||
    "eslint-plugin-import": "^2.24.2",
 | 
			
		||||
    "eslint-plugin-prettier": "^4.0.0",
 | 
			
		||||
    "eslint-plugin-unused-imports": "^1.1.5",
 | 
			
		||||
    "eth-gas-reporter": "^0.2.25",
 | 
			
		||||
    "hardhat-contract-sizer": "^2.5.1",
 | 
			
		||||
    "hardhat-gas-reporter": "^1.0.8",
 | 
			
		||||
    "prettier": "^2.5.1",
 | 
			
		||||
    "prettier-plugin-solidity": "^1.0.0-beta.18",
 | 
			
		||||
    "solhint": "^3.3.6",
 | 
			
		||||
    "solhint-plugin-prettier": "^0.0.5",
 | 
			
		||||
    "ts-node": "^10.4.0",
 | 
			
		||||
    "typescript": "^4.5.2"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								Interchain-message/reports/contract_sizes.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Interchain-message/reports/contract_sizes.txt
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										43
									
								
								Interchain-message/reports/gas_usage/summary.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								Interchain-message/reports/gas_usage/summary.txt
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,43 @@
 | 
			
		|||
·--------------------------------------------------------|---------------------------|-------------|-----------------------------·
 | 
			
		||||
|                  Solc version: 0.8.15                  ·  Optimizer enabled: true  ·  Runs: 200  ·  Block limit: 30000000 gas  │
 | 
			
		||||
·························································|···························|·············|······························
 | 
			
		||||
|  Methods                                                                                                                       │
 | 
			
		||||
··················|······································|·············|·············|·············|···············|··············
 | 
			
		||||
|  Contract       ·  Method                              ·  Min        ·  Max        ·  Avg        ·  # calls      ·  eur (avg)  │
 | 
			
		||||
··················|······································|·············|·············|·············|···············|··············
 | 
			
		||||
|  RubicRouterV2  ·  bridgeWithSwap                      ·          -  ·          -  ·     262215  ·            2  ·          -  │
 | 
			
		||||
··················|······································|·············|·············|·············|···············|··············
 | 
			
		||||
|  RubicRouterV2  ·  bridgeWithSwapNative                ·          -  ·          -  ·     250042  ·            2  ·          -  │
 | 
			
		||||
··················|······································|·············|·············|·············|···············|··············
 | 
			
		||||
|  RubicRouterV2  ·  executeMessageWithTransfer          ·     142780  ·     316447  ·     245409  ·           24  ·          -  │
 | 
			
		||||
··················|······································|·············|·············|·············|···············|··············
 | 
			
		||||
|  RubicRouterV2  ·  executeMessageWithTransferFallback  ·     171487  ·     173352  ·     172410  ·            6  ·          -  │
 | 
			
		||||
··················|······································|·············|·············|·············|···············|··············
 | 
			
		||||
|  RubicRouterV2  ·  executeMessageWithTransferRefund    ·     115069  ·     116933  ·     115991  ·            6  ·          -  │
 | 
			
		||||
··················|······································|·············|·············|·············|···············|··············
 | 
			
		||||
|  RubicRouterV2  ·  setGasFeeOfBlockchain               ·          -  ·          -  ·      48537  ·            5  ·          -  │
 | 
			
		||||
··················|······································|·············|·············|·············|···············|··············
 | 
			
		||||
|  RubicRouterV2  ·  setIntegratorInfo                   ·          -  ·          -  ·      50507  ·            6  ·          -  │
 | 
			
		||||
··················|······································|·············|·············|·············|···············|··············
 | 
			
		||||
|  RubicRouterV2  ·  setMaxTokenAmount                   ·      51120  ·      51132  ·      51121  ·           11  ·          -  │
 | 
			
		||||
··················|······································|·············|·············|·············|···············|··············
 | 
			
		||||
|  RubicRouterV2  ·  sweepTokens                         ·      53410  ·      58597  ·      56004  ·            2  ·          -  │
 | 
			
		||||
··················|······································|·············|·············|·············|···············|··············
 | 
			
		||||
|  RubicRouterV2  ·  transferWithSwapV2                  ·     364621  ·     369290  ·     366956  ·            4  ·          -  │
 | 
			
		||||
··················|······································|·············|·············|·············|···············|··············
 | 
			
		||||
|  RubicRouterV2  ·  transferWithSwapV2Native            ·          -  ·          -  ·     357606  ·            2  ·          -  │
 | 
			
		||||
··················|······································|·············|·············|·············|···············|··············
 | 
			
		||||
|  RubicRouterV2  ·  transferWithSwapV3                  ·          -  ·          -  ·     379021  ·            2  ·          -  │
 | 
			
		||||
··················|······································|·············|·············|·············|···············|··············
 | 
			
		||||
|  RubicRouterV2  ·  transferWithSwapV3Native            ·          -  ·          -  ·     358774  ·            2  ·          -  │
 | 
			
		||||
··················|······································|·············|·············|·············|···············|··············
 | 
			
		||||
|  TestERC20      ·  approve                             ·      46712  ·      58446  ·      52579  ·            6  ·          -  │
 | 
			
		||||
··················|······································|·············|·············|·············|···············|··············
 | 
			
		||||
|  TestERC20      ·  transfer                            ·      34527  ·      63540  ·      57057  ·           35  ·          -  │
 | 
			
		||||
··················|······································|·············|·············|·············|···············|··············
 | 
			
		||||
|  Deployments                                           ·                                         ·  % of limit   ·             │
 | 
			
		||||
·························································|·············|·············|·············|···············|··············
 | 
			
		||||
|  RubicRouterV2                                         ·          -  ·          -  ·    5286604  ·       17.6 %  ·          -  │
 | 
			
		||||
·························································|·············|·············|·············|···············|··············
 | 
			
		||||
|  TestMessages                                          ·          -  ·          -  ·    2319848  ·        7.7 %  ·          -  │
 | 
			
		||||
·--------------------------------------------------------|-------------|-------------|-------------|---------------|-------------·
 | 
			
		||||
							
								
								
									
										93
									
								
								Interchain-message/scripts/deploy/deploy.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								Interchain-message/scripts/deploy/deploy.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,93 @@
 | 
			
		|||
const hre = require("hardhat");
 | 
			
		||||
 | 
			
		||||
async function main() {
 | 
			
		||||
  const CrossChainSwap = await hre.ethers.getContractFactory("RubicRouterV2");
 | 
			
		||||
  /*
 | 
			
		||||
   * constructor
 | 
			
		||||
   *     address _messageBus,
 | 
			
		||||
   *     address _supportedDex,
 | 
			
		||||
   *     address _nativeWrap
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  // BNB Chain 56
 | 
			
		||||
  // MessageBus 0x223fB0CeB2C6e5310264EFe38151d7D083db91f1
 | 
			
		||||
  // BNB native token address in BSC: 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c
 | 
			
		||||
  // USDC token address in BSC: 0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d
 | 
			
		||||
  // SUSHI: 0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506
 | 
			
		||||
 | 
			
		||||
  // const CrossChainSwapDeploy = await CrossChainSwap.deploy(
 | 
			
		||||
  //     '0x223fB0CeB2C6e5310264EFe38151d7D083db91f1',
 | 
			
		||||
  //     '0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506',
 | 
			
		||||
  //     '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c'
 | 
			
		||||
  // );
 | 
			
		||||
 | 
			
		||||
  // MATIC Polygon 137
 | 
			
		||||
  // MessageBus 0x265B25e22bcd7f10a5bD6E6410F10537Cc7567e8
 | 
			
		||||
  // MATIC native token address in BSC: 0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270
 | 
			
		||||
  // USDC token address in BSC: 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174
 | 
			
		||||
  // SUSHI: 0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506
 | 
			
		||||
 | 
			
		||||
  // MATIC Polygon Testnet 80001
 | 
			
		||||
  // MessageBus 0x7d43AABC515C356145049227CeE54B608342c0ad
 | 
			
		||||
  // MATIC native token address:
 | 
			
		||||
  // USDC token address:
 | 
			
		||||
  // SUSHI: 0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506
 | 
			
		||||
 | 
			
		||||
  // const CrossChainSwapDeploy = await CrossChainSwap.deploy(
 | 
			
		||||
  //     '0x265B25e22bcd7f10a5bD6E6410F10537Cc7567e8',
 | 
			
		||||
  //     '0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506',
 | 
			
		||||
  //     '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270');
 | 
			
		||||
 | 
			
		||||
  // BNB TEST 97
 | 
			
		||||
  // MessageBus 0xAd204986D6cB67A5Bc76a3CB8974823F43Cb9AAA
 | 
			
		||||
  // WBNB native token address in BSC: 0x094616F0BdFB0b526bD735Bf66Eca0Ad254ca81F
 | 
			
		||||
  // USDC token address in BSC: 0x9744ae566c64B6B6f7F9A4dD50f7496Df6Fef990
 | 
			
		||||
  // SUSHI: 0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506
 | 
			
		||||
 | 
			
		||||
  const CrossChainSwapDeploy = await CrossChainSwap.deploy(
 | 
			
		||||
      '0xAd204986D6cB67A5Bc76a3CB8974823F43Cb9AAA',
 | 
			
		||||
      ['0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506'],
 | 
			
		||||
      '0x094616F0BdFB0b526bD735Bf66Eca0Ad254ca81F'
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  // GOERLI TEST 5
 | 
			
		||||
  // MessageBus 0x942E8e0e4b021F55b89660c886146e0Ec57F4b5B
 | 
			
		||||
  // WETH native token address in BSC: 0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6
 | 
			
		||||
  // USDC token address in BSC: 0xCe7F7c709E8c74D8ad069Ed28abF25ddC43b32a9
 | 
			
		||||
  // SUSHI: 0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506
 | 
			
		||||
 | 
			
		||||
  // const CrossChainSwapDeploy = await CrossChainSwap.deploy('0x942E8e0e4b021F55b89660c886146e0Ec57F4b5B', '0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506', '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6');
 | 
			
		||||
 | 
			
		||||
  // AVALANCHE 43114
 | 
			
		||||
  // MessageBus 0x7d43AABC515C356145049227CeE54B608342c0ad
 | 
			
		||||
  // WAVAX native token address in AVALANCHE: 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7
 | 
			
		||||
  // USDC token address in AVALANCHE: 0xA7D7079b0FEaD91F3e65f86E8915Cb59c1a4C664
 | 
			
		||||
  // SUSHI: 0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506
 | 
			
		||||
 | 
			
		||||
  // const CrossChainSwapDeploy = await CrossChainSwap.deploy('0x7d43AABC515C356145049227CeE54B608342c0ad', '0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506', '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  await CrossChainSwapDeploy.deployed();
 | 
			
		||||
 | 
			
		||||
  console.log("CrossChainSwapDeploy deployed to:", CrossChainSwapDeploy.address);
 | 
			
		||||
 | 
			
		||||
  await new Promise(r => setTimeout(r, 10000));
 | 
			
		||||
 | 
			
		||||
  await hre.run("verify:verify", {
 | 
			
		||||
    address: CrossChainSwapDeploy.address,
 | 
			
		||||
    constructorArguments: [
 | 
			
		||||
        '0xAd204986D6cB67A5Bc76a3CB8974823F43Cb9AAA',
 | 
			
		||||
      ['0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506'],
 | 
			
		||||
      '0x094616F0BdFB0b526bD735Bf66Eca0Ad254ca81F'
 | 
			
		||||
    ],
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// We recommend this pattern to be able to use async/await everywhere
 | 
			
		||||
// and properly handle errors.
 | 
			
		||||
main()
 | 
			
		||||
  .then(() => process.exit(0))
 | 
			
		||||
  .catch((error) => {
 | 
			
		||||
    console.error(error);
 | 
			
		||||
    process.exit(1);
 | 
			
		||||
  });
 | 
			
		||||
							
								
								
									
										72
									
								
								Interchain-message/scripts/deploy/deployAVAX.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								Interchain-message/scripts/deploy/deployAVAX.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,72 @@
 | 
			
		|||
import { ethers } from 'hardhat';
 | 
			
		||||
 | 
			
		||||
const hre = require('hardhat');
 | 
			
		||||
 | 
			
		||||
async function main() {
 | 
			
		||||
    const CrossChainSwap = await hre.ethers.getContractFactory('RubicRouterV2');
 | 
			
		||||
    /*
 | 
			
		||||
     * constructor
 | 
			
		||||
     *    address _messageBus,
 | 
			
		||||
     *    address[] memory _supportedDEXes,
 | 
			
		||||
     *    address _nativeWrap
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    // AVALANCHE 43114
 | 
			
		||||
    // MessageBus 0x5a926eeeAFc4D217ADd17e9641e8cE23Cd01Ad57
 | 
			
		||||
    // WAVAX native token address in AVALANCHE: 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7
 | 
			
		||||
    // USDC token address in AVALANCHE: 0xA7D7079b0FEaD91F3e65f86E8915Cb59c1a4C664
 | 
			
		||||
    // SUSHI: 0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506
 | 
			
		||||
 | 
			
		||||
    const CrossChainSwapDeploy = await CrossChainSwap.deploy(
 | 
			
		||||
        ethers.utils.parseEther('1').div('1000'),
 | 
			
		||||
        '3000', // 0.3%
 | 
			
		||||
        [
 | 
			
		||||
            '0xE54Ca86531e17Ef3616d22Ca28b0D458b6C89106',
 | 
			
		||||
            '0x60aE616a2155Ee3d9A68541Ba4544862310933d4',
 | 
			
		||||
            '0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506'
 | 
			
		||||
        ],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        '0x503cef47ce5e37aa62544a363bef3c9b62d42116',
 | 
			
		||||
        '0x5a926eeeAFc4D217ADd17e9641e8cE23Cd01Ad57',
 | 
			
		||||
        '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    await CrossChainSwapDeploy.deployed();
 | 
			
		||||
 | 
			
		||||
    console.log('CrossChainSwapDeploy deployed to:', CrossChainSwapDeploy.address);
 | 
			
		||||
    await new Promise(r => setTimeout(r, 10000));
 | 
			
		||||
 | 
			
		||||
    await hre.run('verify:verify', {
 | 
			
		||||
        address: CrossChainSwapDeploy.address,
 | 
			
		||||
        constructorArguments: [
 | 
			
		||||
            ethers.utils.parseEther('1').div('1000'),
 | 
			
		||||
            '3000', // 0.3%
 | 
			
		||||
            [
 | 
			
		||||
                '0xE54Ca86531e17Ef3616d22Ca28b0D458b6C89106',
 | 
			
		||||
                '0x60aE616a2155Ee3d9A68541Ba4544862310933d4',
 | 
			
		||||
                '0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506'
 | 
			
		||||
            ],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            '0x503cef47ce5e37aa62544a363bef3c9b62d42116',
 | 
			
		||||
            '0x5a926eeeAFc4D217ADd17e9641e8cE23Cd01Ad57',
 | 
			
		||||
            '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7'
 | 
			
		||||
        ]
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// We recommend this pattern to be able to use async/await everywhere
 | 
			
		||||
// and properly handle errors.
 | 
			
		||||
main()
 | 
			
		||||
    .then(() => process.exit(0))
 | 
			
		||||
    .catch(error => {
 | 
			
		||||
        console.error(error);
 | 
			
		||||
        process.exit(1);
 | 
			
		||||
    });
 | 
			
		||||
							
								
								
									
										72
									
								
								Interchain-message/scripts/deploy/deployArbitrum.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								Interchain-message/scripts/deploy/deployArbitrum.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,72 @@
 | 
			
		|||
import { ethers } from 'hardhat';
 | 
			
		||||
 | 
			
		||||
const hre = require('hardhat');
 | 
			
		||||
 | 
			
		||||
async function main() {
 | 
			
		||||
    const CrossChainSwap = await hre.ethers.getContractFactory('RubicRouterV2');
 | 
			
		||||
    /*
 | 
			
		||||
     * constructor
 | 
			
		||||
     *    address _messageBus,
 | 
			
		||||
     *    address[] memory _supportedDEXes,
 | 
			
		||||
     *    address _nativeWrap
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    // ETH Arbitrum 42161
 | 
			
		||||
    // MessageBus 0x3Ad9d0648CDAA2426331e894e980D0a5Ed16257f
 | 
			
		||||
    // ETH native token address in ARBITRUM: 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1
 | 
			
		||||
    // USDC token address: 0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8
 | 
			
		||||
    // SUSHI:
 | 
			
		||||
 | 
			
		||||
    const CrossChainSwapDeploy = await CrossChainSwap.deploy(
 | 
			
		||||
        ethers.utils.parseEther('1').div('100'),
 | 
			
		||||
        '0',
 | 
			
		||||
        [
 | 
			
		||||
            '0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506',
 | 
			
		||||
            '0xe592427a0aece92de3edee1f18e0157c05861564',
 | 
			
		||||
            '0x1111111254fb6c44bAC0beD2854e76F90643097d'
 | 
			
		||||
        ],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        '0x503cef47ce5e37aa62544a363bef3c9b62d42116',
 | 
			
		||||
        '0x3Ad9d0648CDAA2426331e894e980D0a5Ed16257f',
 | 
			
		||||
        '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    await CrossChainSwapDeploy.deployed();
 | 
			
		||||
 | 
			
		||||
    console.log('CrossChainSwapDeploy deployed to:', CrossChainSwapDeploy.address);
 | 
			
		||||
    await new Promise(r => setTimeout(r, 10000));
 | 
			
		||||
 | 
			
		||||
    await hre.run('verify:verify', {
 | 
			
		||||
        address: CrossChainSwapDeploy.address,
 | 
			
		||||
        constructorArguments: [
 | 
			
		||||
            ethers.utils.parseEther('1').div('100'),
 | 
			
		||||
            '0',
 | 
			
		||||
            [
 | 
			
		||||
                '0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506',
 | 
			
		||||
                '0xe592427a0aece92de3edee1f18e0157c05861564',
 | 
			
		||||
                '0x1111111254fb6c44bAC0beD2854e76F90643097d'
 | 
			
		||||
            ],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            '0x503cef47ce5e37aa62544a363bef3c9b62d42116',
 | 
			
		||||
            '0x3Ad9d0648CDAA2426331e894e980D0a5Ed16257f',
 | 
			
		||||
            '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1'
 | 
			
		||||
        ]
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// We recommend this pattern to be able to use async/await everywhere
 | 
			
		||||
// and properly handle errors.
 | 
			
		||||
main()
 | 
			
		||||
    .then(() => process.exit(0))
 | 
			
		||||
    .catch(error => {
 | 
			
		||||
        console.error(error);
 | 
			
		||||
        process.exit(1);
 | 
			
		||||
    });
 | 
			
		||||
							
								
								
									
										69
									
								
								Interchain-message/scripts/deploy/deployAurora.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								Interchain-message/scripts/deploy/deployAurora.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,69 @@
 | 
			
		|||
const hre = require('hardhat');
 | 
			
		||||
const { ethers } = require('hardhat');
 | 
			
		||||
 | 
			
		||||
async function main() {
 | 
			
		||||
    const CrossChainSwap = await hre.ethers.getContractFactory('RubicRouterV2');
 | 
			
		||||
    /*
 | 
			
		||||
     * constructor
 | 
			
		||||
     *    address _messageBus,
 | 
			
		||||
     *    address[] memory _supportedDEXes,
 | 
			
		||||
     *    address _nativeWrap
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    // ETH Aurora 1313161554
 | 
			
		||||
    // MessageBus 0xc1a2D967DfAa6A10f3461bc21864C23C1DD51EeA
 | 
			
		||||
    // ETH native token address : 0xC9BdeEd33CD01541e1eeD10f90519d2C06Fe3feB
 | 
			
		||||
    // USDC token address: 0xB12BFcA5A55806AaF64E99521918A4bf0fC40802
 | 
			
		||||
    // SUSHI:
 | 
			
		||||
 | 
			
		||||
    const CrossChainSwapDeploy = await CrossChainSwap.deploy(
 | 
			
		||||
        ethers.utils.parseEther('1').div('1000'),
 | 
			
		||||
        '0', // 0.3%
 | 
			
		||||
        [
 | 
			
		||||
            '0x2CB45Edb4517d5947aFdE3BEAbF95A582506858B',
 | 
			
		||||
            '0xa3a1eF5Ae6561572023363862e238aFA84C72ef5'
 | 
			
		||||
        ],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        '0x503cef47ce5e37aa62544a363bef3c9b62d42116',
 | 
			
		||||
        '0xc1a2D967DfAa6A10f3461bc21864C23C1DD51EeA',
 | 
			
		||||
        '0xC9BdeEd33CD01541e1eeD10f90519d2C06Fe3feB'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    await CrossChainSwapDeploy.deployed();
 | 
			
		||||
 | 
			
		||||
    console.log('CrossChainSwapDeploy deployed to:', CrossChainSwapDeploy.address);
 | 
			
		||||
    await new Promise(r => setTimeout(r, 10000));
 | 
			
		||||
 | 
			
		||||
    await hre.run('verify:verify', {
 | 
			
		||||
        address: CrossChainSwapDeploy.address,
 | 
			
		||||
        constructorArguments: [
 | 
			
		||||
            ethers.utils.parseEther('1').div('1000'),
 | 
			
		||||
            '0', // 0.3%
 | 
			
		||||
            [
 | 
			
		||||
                '0x2CB45Edb4517d5947aFdE3BEAbF95A582506858B',
 | 
			
		||||
                '0xa3a1eF5Ae6561572023363862e238aFA84C72ef5'
 | 
			
		||||
            ],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            '0x503cef47ce5e37aa62544a363bef3c9b62d42116',
 | 
			
		||||
            '0xc1a2D967DfAa6A10f3461bc21864C23C1DD51EeA',
 | 
			
		||||
            '0xC9BdeEd33CD01541e1eeD10f90519d2C06Fe3feB'
 | 
			
		||||
        ]
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// We recommend this pattern to be able to use async/await everywhere
 | 
			
		||||
// and properly handle errors.
 | 
			
		||||
main()
 | 
			
		||||
    .then(() => process.exit(0))
 | 
			
		||||
    .catch(error => {
 | 
			
		||||
        console.error(error);
 | 
			
		||||
        process.exit(1);
 | 
			
		||||
    });
 | 
			
		||||
							
								
								
									
										67
									
								
								Interchain-message/scripts/deploy/deployBSC.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								Interchain-message/scripts/deploy/deployBSC.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,67 @@
 | 
			
		|||
const hre = require('hardhat');
 | 
			
		||||
import { ethers } from 'hardhat';
 | 
			
		||||
 | 
			
		||||
async function main() {
 | 
			
		||||
    const CrossChainSwap = await hre.ethers.getContractFactory('RubicRouterV2');
 | 
			
		||||
 | 
			
		||||
    // BNB Chain 56
 | 
			
		||||
    // MessageBus 0x95714818fdd7a5454F73Da9c777B3ee6EbAEEa6B
 | 
			
		||||
    // BNB native token address in BSC: 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c
 | 
			
		||||
    // USDC token address in BSC: 0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d
 | 
			
		||||
    // SUSHI: 0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506
 | 
			
		||||
 | 
			
		||||
    const CrossChainSwapDeploy = await CrossChainSwap.deploy(
 | 
			
		||||
        ethers.utils.parseEther('1').div('1000'),
 | 
			
		||||
        '3000', // 0.3%
 | 
			
		||||
        [
 | 
			
		||||
            '0x10ed43c718714eb63d5aa57b78b54704e256024e',
 | 
			
		||||
            '0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506',
 | 
			
		||||
            '0xcF0feBd3f17CEf5b47b0cD257aCf6025c5BFf3b7',
 | 
			
		||||
            '0x1111111254fb6c44bAC0beD2854e76F90643097d'
 | 
			
		||||
        ],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        '0x503cef47ce5e37aa62544a363bef3c9b62d42116',
 | 
			
		||||
        '0x95714818fdd7a5454F73Da9c777B3ee6EbAEEa6B',
 | 
			
		||||
        '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    await CrossChainSwapDeploy.deployed();
 | 
			
		||||
 | 
			
		||||
    console.log('CrossChainSwapDeploy deployed to:', CrossChainSwapDeploy.address);
 | 
			
		||||
    await new Promise(r => setTimeout(r, 10000));
 | 
			
		||||
 | 
			
		||||
    await hre.run('verify:verify', {
 | 
			
		||||
        address: CrossChainSwapDeploy.address,
 | 
			
		||||
        constructorArguments: [
 | 
			
		||||
            ethers.utils.parseEther('1').div('1000'),
 | 
			
		||||
            '3000', // 0.3%
 | 
			
		||||
            [
 | 
			
		||||
                '0x10ed43c718714eb63d5aa57b78b54704e256024e',
 | 
			
		||||
                '0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506',
 | 
			
		||||
                '0xcF0feBd3f17CEf5b47b0cD257aCf6025c5BFf3b7',
 | 
			
		||||
                '0x1111111254fb6c44bAC0beD2854e76F90643097d'
 | 
			
		||||
            ],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            '0x503cef47ce5e37aa62544a363bef3c9b62d42116',
 | 
			
		||||
            '0x95714818fdd7a5454F73Da9c777B3ee6EbAEEa6B',
 | 
			
		||||
            '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c'
 | 
			
		||||
        ]
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// We recommend this pattern to be able to use async/await everywhere
 | 
			
		||||
// and properly handle errors.
 | 
			
		||||
main()
 | 
			
		||||
    .then(() => process.exit(0))
 | 
			
		||||
    .catch(error => {
 | 
			
		||||
        console.error(error);
 | 
			
		||||
        process.exit(1);
 | 
			
		||||
    });
 | 
			
		||||
							
								
								
									
										74
									
								
								Interchain-message/scripts/deploy/deployEth.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								Interchain-message/scripts/deploy/deployEth.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,74 @@
 | 
			
		|||
import { ethers } from 'hardhat';
 | 
			
		||||
 | 
			
		||||
const hre = require('hardhat');
 | 
			
		||||
 | 
			
		||||
async function main() {
 | 
			
		||||
    const CrossChainSwap = await hre.ethers.getContractFactory('RubicRouterV2');
 | 
			
		||||
    /*
 | 
			
		||||
     * constructor
 | 
			
		||||
     *    address _messageBus,
 | 
			
		||||
     *    address[] memory _supportedDEXes,
 | 
			
		||||
     *    address _nativeWrap
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    // ETH 1
 | 
			
		||||
    // MessageBus 0x4066D196A423b2b3B8B054f4F40efB47a74E200C
 | 
			
		||||
    // WETH native token address in ETHEREUM: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
 | 
			
		||||
    // USDC token address in Eth: 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
 | 
			
		||||
    // SUSHI: 0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F
 | 
			
		||||
 | 
			
		||||
    const CrossChainSwapDeploy = await CrossChainSwap.deploy(
 | 
			
		||||
        ethers.utils.parseEther('1').div('1000'),
 | 
			
		||||
        '3000', // 0.3%
 | 
			
		||||
        [
 | 
			
		||||
            '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
 | 
			
		||||
            '0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F',
 | 
			
		||||
            '0xE592427A0AEce92De3Edee1F18E0157C05861564',
 | 
			
		||||
            '0x1111111254fb6c44bAC0beD2854e76F90643097d'
 | 
			
		||||
        ],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        '0x503cef47ce5e37aa62544a363bef3c9b62d42116',
 | 
			
		||||
        '0x4066D196A423b2b3B8B054f4F40efB47a74E200C',
 | 
			
		||||
        '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    await CrossChainSwapDeploy.deployed();
 | 
			
		||||
 | 
			
		||||
    console.log('CrossChainSwapDeploy deployed to:', CrossChainSwapDeploy.address);
 | 
			
		||||
    await new Promise(r => setTimeout(r, 10000));
 | 
			
		||||
 | 
			
		||||
    await hre.run('verify:verify', {
 | 
			
		||||
        address: CrossChainSwapDeploy.address,
 | 
			
		||||
        constructorArguments: [
 | 
			
		||||
            ethers.utils.parseEther('1').div('1000'),
 | 
			
		||||
            '3000', // 0.3%
 | 
			
		||||
            [
 | 
			
		||||
                '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
 | 
			
		||||
                '0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F',
 | 
			
		||||
                '0xE592427A0AEce92De3Edee1F18E0157C05861564',
 | 
			
		||||
                '0x1111111254fb6c44bAC0beD2854e76F90643097d'
 | 
			
		||||
            ],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            '0x503cef47ce5e37aa62544a363bef3c9b62d42116',
 | 
			
		||||
            '0x4066D196A423b2b3B8B054f4F40efB47a74E200C',
 | 
			
		||||
            '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
 | 
			
		||||
        ]
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// We recommend this pattern to be able to use async/await everywhere
 | 
			
		||||
// and properly handle errors.
 | 
			
		||||
main()
 | 
			
		||||
    .then(() => process.exit(0))
 | 
			
		||||
    .catch(error => {
 | 
			
		||||
        console.error(error);
 | 
			
		||||
        process.exit(1);
 | 
			
		||||
    });
 | 
			
		||||
							
								
								
									
										74
									
								
								Interchain-message/scripts/deploy/deployFantom.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								Interchain-message/scripts/deploy/deployFantom.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,74 @@
 | 
			
		|||
import { ethers } from 'hardhat';
 | 
			
		||||
 | 
			
		||||
const hre = require('hardhat');
 | 
			
		||||
 | 
			
		||||
async function main() {
 | 
			
		||||
    const CrossChainSwap = await hre.ethers.getContractFactory('RubicRouterV2');
 | 
			
		||||
    /*
 | 
			
		||||
     * constructor
 | 
			
		||||
     *    address _messageBus,
 | 
			
		||||
     *    address[] memory _supportedDEXes,
 | 
			
		||||
     *    address _nativeWrap
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    // FTM Fantom 250
 | 
			
		||||
    // MessageBus 0xFF4E183a0Ceb4Fa98E63BbF8077B929c8E5A2bA4
 | 
			
		||||
    // FTM native token address in BSC: 0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83
 | 
			
		||||
    // USDC token address in BSC: 0x04068DA6C83AFCFA0e13ba15A6696662335D5B75
 | 
			
		||||
    // SUSHI: 0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506
 | 
			
		||||
 | 
			
		||||
    const CrossChainSwapDeploy = await CrossChainSwap.deploy(
 | 
			
		||||
        ethers.utils.parseEther('1').div('1000'),
 | 
			
		||||
        '3000', // 0.3%
 | 
			
		||||
        [
 | 
			
		||||
            '0xf491e7b69e4244ad4002bc14e878a34207e38c29',
 | 
			
		||||
            '0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506',
 | 
			
		||||
            '0x16327E3FbDaCA3bcF7E38F5Af2599D2DDc33aE52',
 | 
			
		||||
            '0x1111111254fb6c44bac0bed2854e76f90643097d'
 | 
			
		||||
        ],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        '0x503cef47ce5e37aa62544a363bef3c9b62d42116',
 | 
			
		||||
        '0xFF4E183a0Ceb4Fa98E63BbF8077B929c8E5A2bA4',
 | 
			
		||||
        '0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    await CrossChainSwapDeploy.deployed();
 | 
			
		||||
 | 
			
		||||
    console.log('CrossChainSwapDeploy deployed to:', CrossChainSwapDeploy.address);
 | 
			
		||||
    await new Promise(r => setTimeout(r, 10000));
 | 
			
		||||
 | 
			
		||||
    await hre.run('verify:verify', {
 | 
			
		||||
        address: CrossChainSwapDeploy.address,
 | 
			
		||||
        constructorArguments: [
 | 
			
		||||
            ethers.utils.parseEther('1').div('1000'),
 | 
			
		||||
            '3000', // 0.3%
 | 
			
		||||
            [
 | 
			
		||||
                '0xf491e7b69e4244ad4002bc14e878a34207e38c29',
 | 
			
		||||
                '0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506',
 | 
			
		||||
                '0x16327E3FbDaCA3bcF7E38F5Af2599D2DDc33aE52',
 | 
			
		||||
                '0x1111111254fb6c44bac0bed2854e76f90643097d'
 | 
			
		||||
            ],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            [],
 | 
			
		||||
            '0x503cef47ce5e37aa62544a363bef3c9b62d42116',
 | 
			
		||||
            '0xFF4E183a0Ceb4Fa98E63BbF8077B929c8E5A2bA4',
 | 
			
		||||
            '0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83'
 | 
			
		||||
        ]
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// We recommend this pattern to be able to use async/await everywhere
 | 
			
		||||
// and properly handle errors.
 | 
			
		||||
main()
 | 
			
		||||
    .then(() => process.exit(0))
 | 
			
		||||
    .catch(error => {
 | 
			
		||||
        console.error(error);
 | 
			
		||||
        process.exit(1);
 | 
			
		||||
    });
 | 
			
		||||
							
								
								
									
										71
									
								
								Interchain-message/scripts/deploy/deployPoly.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								Interchain-message/scripts/deploy/deployPoly.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,71 @@
 | 
			
		|||
const hre = require('hardhat');
 | 
			
		||||
import { ethers } from 'hardhat';
 | 
			
		||||
 | 
			
		||||
async function main() {
 | 
			
		||||
    const CrossChainSwap = await hre.ethers.getContractFactory('RubicRouterV2');
 | 
			
		||||
 | 
			
		||||
    // MATIC Polygon 137
 | 
			
		||||
    // MessageBus 0xaFDb9C40C7144022811F034EE07Ce2E110093fe6
 | 
			
		||||
    // MATIC native token address in BSC: 0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270
 | 
			
		||||
    // USDC token address in BSC: 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174
 | 
			
		||||
    // SUSHI: 0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506
 | 
			
		||||
 | 
			
		||||
    const CrossChainSwapDeploy = await CrossChainSwap.deploy(
 | 
			
		||||
        ethers.utils.parseEther('1').div('100'),
 | 
			
		||||
        '3000', // 0.3%
 | 
			
		||||
        [
 | 
			
		||||
            '0xa5e0829caced8ffdd4de3c43696c57f7d7a678ff',
 | 
			
		||||
            '0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506',
 | 
			
		||||
            '0xC0788A3aD43d79aa53B09c2EaCc313A787d1d607',
 | 
			
		||||
            '0x1111111254fb6c44bAC0beD2854e76F90643097d',
 | 
			
		||||
            '0x89D6B81A1Ef25894620D05ba843d83B0A296239e',
 | 
			
		||||
            '0xE592427A0AEce92De3Edee1F18E0157C05861564'
 | 
			
		||||
        ],
 | 
			
		||||
        ['0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174'],
 | 
			
		||||
        ['10000000'],
 | 
			
		||||
        ['200000000'],
 | 
			
		||||
        ['56'],
 | 
			
		||||
        ['500'],
 | 
			
		||||
        '0x00009cc27c811a3e0FdD2Fd737afCc721B67eE8e',
 | 
			
		||||
        '0xaFDb9C40C7144022811F034EE07Ce2E110093fe6',
 | 
			
		||||
        '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270'
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    await CrossChainSwapDeploy.deployed();
 | 
			
		||||
 | 
			
		||||
    console.log('CrossChainSwapDeploy deployed to:', CrossChainSwapDeploy.address);
 | 
			
		||||
    await new Promise(r => setTimeout(r, 10000));
 | 
			
		||||
 | 
			
		||||
    await hre.run('verify:verify', {
 | 
			
		||||
        address: CrossChainSwapDeploy.address,
 | 
			
		||||
        constructorArguments: [
 | 
			
		||||
            ethers.utils.parseEther('1').div('100'),
 | 
			
		||||
            '3000', // 0.3%
 | 
			
		||||
            [
 | 
			
		||||
                '0xa5e0829caced8ffdd4de3c43696c57f7d7a678ff',
 | 
			
		||||
                '0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506',
 | 
			
		||||
                '0xC0788A3aD43d79aa53B09c2EaCc313A787d1d607',
 | 
			
		||||
                '0x1111111254fb6c44bAC0beD2854e76F90643097d',
 | 
			
		||||
                '0x89D6B81A1Ef25894620D05ba843d83B0A296239e',
 | 
			
		||||
                '0xE592427A0AEce92De3Edee1F18E0157C05861564'
 | 
			
		||||
            ],
 | 
			
		||||
            ['0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174'],
 | 
			
		||||
            ['10000000'],
 | 
			
		||||
            ['200000000'],
 | 
			
		||||
            ['56'],
 | 
			
		||||
            ['500'],
 | 
			
		||||
            '0x00009cc27c811a3e0FdD2Fd737afCc721B67eE8e',
 | 
			
		||||
            '0xaFDb9C40C7144022811F034EE07Ce2E110093fe6',
 | 
			
		||||
            '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270'
 | 
			
		||||
        ]
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// We recommend this pattern to be able to use async/await everywhere
 | 
			
		||||
// and properly handle errors.
 | 
			
		||||
main()
 | 
			
		||||
    .then(() => process.exit(0))
 | 
			
		||||
    .catch(error => {
 | 
			
		||||
        console.error(error);
 | 
			
		||||
        process.exit(1);
 | 
			
		||||
    });
 | 
			
		||||
							
								
								
									
										7
									
								
								Interchain-message/scripts/privateKey.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								Interchain-message/scripts/privateKey.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
var keythereum = require("keythereum");
 | 
			
		||||
var datadir = "./";
 | 
			
		||||
var address= "503cef47ce5e37aa62544a363bef3c9b62d42116";
 | 
			
		||||
const password = "";
 | 
			
		||||
var keyObject = keythereum.importFromFile(address, datadir);
 | 
			
		||||
var privateKey = keythereum.recover(password, keyObject);
 | 
			
		||||
console.log(privateKey.toString('hex'));
 | 
			
		||||
							
								
								
									
										77
									
								
								Interchain-message/scripts/sendTx/avaxToFantomBridge.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								Interchain-message/scripts/sendTx/avaxToFantomBridge.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,77 @@
 | 
			
		|||
const hre = require("hardhat");
 | 
			
		||||
 | 
			
		||||
async function main() {
 | 
			
		||||
    const CrossChainSwap = await hre.ethers.getContractFactory("SwapMain");
 | 
			
		||||
    /*
 | 
			
		||||
    * constructor
 | 
			
		||||
    *    address _messageBus,
 | 
			
		||||
    *    address[] memory _supportedDEXes,
 | 
			
		||||
    *    address _nativeWrap
 | 
			
		||||
    */
 | 
			
		||||
 | 
			
		||||
    // AVALANCHE 43114
 | 
			
		||||
    // MessageBus 0x5a926eeeAFc4D217ADd17e9641e8cE23Cd01Ad57
 | 
			
		||||
    // WAVAX native token address in AVALANCHE: 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7
 | 
			
		||||
    // USDC token address in AVALANCHE: 0xA7D7079b0FEaD91F3e65f86E8915Cb59c1a4C664
 | 
			
		||||
    // SUSHI: 0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506
 | 
			
		||||
 | 
			
		||||
    // FTM Fantom 250
 | 
			
		||||
    // MessageBus 0xFF4E183a0Ceb4Fa98E63BbF8077B929c8E5A2bA4
 | 
			
		||||
    // FTM native token address in BSC: 0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83
 | 
			
		||||
    // USDC token address in BSC: 0x04068DA6C83AFCFA0e13ba15A6696662335D5B75
 | 
			
		||||
    // SUSHI: 0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506
 | 
			
		||||
 | 
			
		||||
    const address = '';
 | 
			
		||||
 | 
			
		||||
    const crossChainSwap = await CrossChainSwap.attach(address);
 | 
			
		||||
 | 
			
		||||
    // src bridge --- dst swap
 | 
			
		||||
    await crossChainSwap.bridgeWithSwap(
 | 
			
		||||
        0x93f56C28b66Fa3EEF980ab11a8a0E9D09c6576f5,
 | 
			
		||||
        21000000000000000000,
 | 
			
		||||
        43114,
 | 
			
		||||
        '0x04068DA6C83AFCFA0e13ba15A6696662335D5B75',
 | 
			
		||||
        ['0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506',
 | 
			
		||||
            '0x0000000000000000000000000000000000000000',
 | 
			
		||||
            '1',
 | 
			
		||||
            ['0xA7D7079b0FEaD91F3e65f86E8915Cb59c1a4C664', '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7'],
 | 
			
		||||
            '0x',
 | 
			
		||||
            '999999999999999',
 | 
			
		||||
            '0'
 | 
			
		||||
        ],
 | 
			
		||||
        1000000,
 | 
			
		||||
        true,
 | 
			
		||||
        {value: 21.00001}
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // src bridge --- dst bridge
 | 
			
		||||
    await crossChainSwap.bridgeWithSwap(
 | 
			
		||||
        0x93f56C28b66Fa3EEF980ab11a8a0E9D09c6576f5,
 | 
			
		||||
        21000000000000000000,
 | 
			
		||||
        43114,
 | 
			
		||||
        '0x04068DA6C83AFCFA0e13ba15A6696662335D5B75',
 | 
			
		||||
        ['0x0000000000000000000000000000000000000000', // no need in dex
 | 
			
		||||
            '0x0000000000000000000000000000000000000000', // without integrator
 | 
			
		||||
            '4', // bridge
 | 
			
		||||
            ['0xA7D7079b0FEaD91F3e65f86E8915Cb59c1a4C664'],
 | 
			
		||||
            '0x', // no need in bytes data
 | 
			
		||||
            '0', // no need in deadline
 | 
			
		||||
            '0' // no need in amountOut min
 | 
			
		||||
        ],
 | 
			
		||||
        1000000,
 | 
			
		||||
        true,
 | 
			
		||||
        {value: 21.00001}
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    await new Promise(r => setTimeout(r, 10000));
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// We recommend this pattern to be able to use async/await everywhere
 | 
			
		||||
// and properly handle errors.
 | 
			
		||||
main()
 | 
			
		||||
    .then(() => process.exit(0))
 | 
			
		||||
    .catch((error) => {
 | 
			
		||||
        console.error(error);
 | 
			
		||||
        process.exit(1);
 | 
			
		||||
    });
 | 
			
		||||
							
								
								
									
										61
									
								
								Interchain-message/scripts/sendTx/avaxToFantomNativeV2.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								Interchain-message/scripts/sendTx/avaxToFantomNativeV2.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,61 @@
 | 
			
		|||
const hre = require("hardhat");
 | 
			
		||||
 | 
			
		||||
async function main() {
 | 
			
		||||
    const CrossChainSwap = await hre.ethers.getContractFactory("SwapMain");
 | 
			
		||||
    /*
 | 
			
		||||
    * constructor
 | 
			
		||||
    *    address _messageBus,
 | 
			
		||||
    *    address[] memory _supportedDEXes,
 | 
			
		||||
    *    address _nativeWrap
 | 
			
		||||
    */
 | 
			
		||||
 | 
			
		||||
    // AVALANCHE 43114
 | 
			
		||||
    // MessageBus 0x5a926eeeAFc4D217ADd17e9641e8cE23Cd01Ad57
 | 
			
		||||
    // WAVAX native token address in AVALANCHE: 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7
 | 
			
		||||
    // USDC token address in AVALANCHE: 0xA7D7079b0FEaD91F3e65f86E8915Cb59c1a4C664
 | 
			
		||||
    // SUSHI: 0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506
 | 
			
		||||
 | 
			
		||||
    // FTM Fantom 250
 | 
			
		||||
    // MessageBus 0xFF4E183a0Ceb4Fa98E63BbF8077B929c8E5A2bA4
 | 
			
		||||
    // FTM native token address in BSC: 0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83
 | 
			
		||||
    // USDC token address in BSC: 0x04068DA6C83AFCFA0e13ba15A6696662335D5B75
 | 
			
		||||
    // SUSHI: 0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506
 | 
			
		||||
 | 
			
		||||
    const address = '';
 | 
			
		||||
 | 
			
		||||
    const crossChainSwap = await CrossChainSwap.attach(address);
 | 
			
		||||
 | 
			
		||||
    await crossChainSwap.transferWithSwapV2Native(
 | 
			
		||||
        0x93f56C28b66Fa3EEF980ab11a8a0E9D09c6576f5,
 | 
			
		||||
        21000000000000000000,
 | 
			
		||||
        43114,
 | 
			
		||||
        ['0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506',
 | 
			
		||||
            ['0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83', '0x04068DA6C83AFCFA0e13ba15A6696662335D5B75'],
 | 
			
		||||
            '999999999999999',
 | 
			
		||||
            '0'
 | 
			
		||||
        ],
 | 
			
		||||
        ['0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506',
 | 
			
		||||
            '0x0000000000000000000000000000000000000000',
 | 
			
		||||
            '1',
 | 
			
		||||
            ['0xA7D7079b0FEaD91F3e65f86E8915Cb59c1a4C664', '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7'],
 | 
			
		||||
            '0x',
 | 
			
		||||
            '999999999999999',
 | 
			
		||||
            '0'
 | 
			
		||||
        ],
 | 
			
		||||
        1000000,
 | 
			
		||||
        true,
 | 
			
		||||
        {value: 21.00001}
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    await new Promise(r => setTimeout(r, 10000));
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// We recommend this pattern to be able to use async/await everywhere
 | 
			
		||||
// and properly handle errors.
 | 
			
		||||
main()
 | 
			
		||||
    .then(() => process.exit(0))
 | 
			
		||||
    .catch((error) => {
 | 
			
		||||
        console.error(error);
 | 
			
		||||
        process.exit(1);
 | 
			
		||||
    });
 | 
			
		||||
							
								
								
									
										478
									
								
								Interchain-message/test/RubicCrossChainBridge.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										478
									
								
								Interchain-message/test/RubicCrossChainBridge.spec.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,478 @@
 | 
			
		|||
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);
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										611
									
								
								Interchain-message/test/RubicCrossChainV2.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										611
									
								
								Interchain-message/test/RubicCrossChainV2.spec.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,611 @@
 | 
			
		|||
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,
 | 
			
		||||
    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';
 | 
			
		||||
import { getRouterV2 } from './shared/utils';
 | 
			
		||||
import { calcCryptoFees, calcTokenFees } from 'rubic-bridge-base/lib';
 | 
			
		||||
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('RubicCrossChainV2', () => {
 | 
			
		||||
    let wallet: Wallet, other: Wallet;
 | 
			
		||||
    let swapToken: TestERC20;
 | 
			
		||||
    let transitToken: TestERC20;
 | 
			
		||||
    let swapMain: RubicRouterV2;
 | 
			
		||||
    let router: string;
 | 
			
		||||
    let wnative: WETH9;
 | 
			
		||||
 | 
			
		||||
    let testMessagesContract: TestMessages;
 | 
			
		||||
 | 
			
		||||
    let loadFixture: ReturnType<typeof createFixtureLoader>;
 | 
			
		||||
 | 
			
		||||
    async function callTransferWithSwapV2Native(
 | 
			
		||||
        amountOutMinimum: BigNumberish,
 | 
			
		||||
        {
 | 
			
		||||
            receiver = null,
 | 
			
		||||
            amountIn = DEFAULT_AMOUNT_IN,
 | 
			
		||||
            dstChainID = DST_CHAIN_ID,
 | 
			
		||||
            srcDEX = router,
 | 
			
		||||
            srcPath = [wnative.address, transitToken.address],
 | 
			
		||||
            nativeIn = null,
 | 
			
		||||
            integrator = INTEGRATOR,
 | 
			
		||||
            nativeOut = true
 | 
			
		||||
        } = {}
 | 
			
		||||
    ): Promise<ContractTransaction> {
 | 
			
		||||
        const { totalCryptoFee } = await calcCryptoFees({
 | 
			
		||||
            bridge: swapMain,
 | 
			
		||||
            integrator,
 | 
			
		||||
            dstChainID
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return swapMain.transferWithSwapV2Native(
 | 
			
		||||
            receiver === null ? wallet.address : receiver,
 | 
			
		||||
            amountIn,
 | 
			
		||||
            dstChainID,
 | 
			
		||||
            {
 | 
			
		||||
                dex: srcDEX,
 | 
			
		||||
                path: srcPath,
 | 
			
		||||
                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 ? amountIn.add(totalCryptoFee).add(MESSAGE_BUS_FEE) : nativeIn
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async function callTransferWithSwapV2(
 | 
			
		||||
        amountOutMinimum: BigNumberish,
 | 
			
		||||
        {
 | 
			
		||||
            receiver = null,
 | 
			
		||||
            amountIn = DEFAULT_AMOUNT_IN,
 | 
			
		||||
            dstChainID = DST_CHAIN_ID,
 | 
			
		||||
            srcDEX = router,
 | 
			
		||||
            srcPath = [wnative.address, transitToken.address],
 | 
			
		||||
            nativeIn = null,
 | 
			
		||||
            integrator = INTEGRATOR,
 | 
			
		||||
            nativeOut = true
 | 
			
		||||
        } = {}
 | 
			
		||||
    ): Promise<ContractTransaction> {
 | 
			
		||||
        const { totalCryptoFee } = await calcCryptoFees({
 | 
			
		||||
            bridge: swapMain,
 | 
			
		||||
            integrator,
 | 
			
		||||
            dstChainID
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return swapMain.transferWithSwapV2(
 | 
			
		||||
            receiver === null ? wallet.address : receiver,
 | 
			
		||||
            amountIn,
 | 
			
		||||
            dstChainID,
 | 
			
		||||
            {
 | 
			
		||||
                dex: srcDEX,
 | 
			
		||||
                path: srcPath,
 | 
			
		||||
                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 getAmountOutMin(
 | 
			
		||||
        amountIn = DEFAULT_AMOUNT_IN,
 | 
			
		||||
        path = [wnative.address, transitToken.address]
 | 
			
		||||
    ) {
 | 
			
		||||
        const routerV2 = await getRouterV2(wallet, router);
 | 
			
		||||
 | 
			
		||||
        return (await routerV2.getAmountsOut(amountIn, path))[1];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // async function getAmountIn(
 | 
			
		||||
    //     amountOut = DEFAULT_AMOUNT_OUT_MIN,
 | 
			
		||||
    //     path = [transitToken.address, swapToken.address]
 | 
			
		||||
    // ) {
 | 
			
		||||
    //     const routerV2 = await getRouterV2(wallet, router);
 | 
			
		||||
    //     return (await routerV2.getAmountsIn(amountOut, path))[0];
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    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,
 | 
			
		||||
    //         receiverEOA = other.address,
 | 
			
		||||
    //         integrator = INTEGRATOR,
 | 
			
		||||
    //         version = VERSION_V2,
 | 
			
		||||
    //         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, 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('#transferWithSwapV2Native', () => {
 | 
			
		||||
            it('Should swap native to token and transfer through Celer', async () => {
 | 
			
		||||
                await swapMain.setMaxTokenAmount(
 | 
			
		||||
                    transitToken.address,
 | 
			
		||||
                    ethers.utils.parseEther('1000')
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                const amountOutMin = await getAmountOutMin(
 | 
			
		||||
                    ethers.BigNumber.from('20000000000000000000')
 | 
			
		||||
                );
 | 
			
		||||
                const _amountIn = ethers.BigNumber.from('20000000000000000000');
 | 
			
		||||
 | 
			
		||||
                await expect(
 | 
			
		||||
                    callTransferWithSwapV2Native(amountOutMin, {
 | 
			
		||||
                        amountIn: _amountIn,
 | 
			
		||||
                        srcPath: [wnative.address, transitToken.address]
 | 
			
		||||
                    })
 | 
			
		||||
                ).to.emit(swapMain, 'CrossChainRequestSent');
 | 
			
		||||
            });
 | 
			
		||||
            it('Should swap native to token and fail transfer through Celer', async () => {
 | 
			
		||||
                await swapMain.setMaxTokenAmount(
 | 
			
		||||
                    transitToken.address,
 | 
			
		||||
                    ethers.utils.parseEther('1000')
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                const amountOutMin = await getAmountOutMin();
 | 
			
		||||
 | 
			
		||||
                await expect(
 | 
			
		||||
                    callTransferWithSwapV2Native(amountOutMin, {
 | 
			
		||||
                        srcPath: [wnative.address, transitToken.address]
 | 
			
		||||
                    })
 | 
			
		||||
                ).to.be.revertedWith('amount too small');
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
        describe('#transferWithSwapV2', () => {
 | 
			
		||||
            it('Should swap token to transitToken and transfer through Сeler', async () => {
 | 
			
		||||
                await swapToken.approve(swapMain.address, ethers.constants.MaxUint256);
 | 
			
		||||
                await swapMain.setMaxTokenAmount(
 | 
			
		||||
                    transitToken.address,
 | 
			
		||||
                    ethers.utils.parseEther('1000')
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                const amountOutMin = await getAmountOutMin(DEFAULT_AMOUNT_IN, [
 | 
			
		||||
                    swapToken.address,
 | 
			
		||||
                    transitToken.address
 | 
			
		||||
                ]);
 | 
			
		||||
 | 
			
		||||
                //const ID = await getID(testMessagesContract, (await swapMain.nonce()).add('1'));
 | 
			
		||||
                await expect(
 | 
			
		||||
                    callTransferWithSwapV2(amountOutMin, {
 | 
			
		||||
                        srcPath: [swapToken.address, transitToken.address]
 | 
			
		||||
                    })
 | 
			
		||||
                ).to.emit(swapMain, 'CrossChainRequestSent');
 | 
			
		||||
                //.withArgs(ID, DST_CHAIN_ID, DEFAULT_AMOUNT_IN, swapToken.address);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('Should swap token to native and transfer through Сeler', async () => {
 | 
			
		||||
                await swapToken.approve(swapMain.address, ethers.constants.MaxUint256);
 | 
			
		||||
                await swapMain.setMaxTokenAmount(wnative.address, ethers.utils.parseEther('10000'));
 | 
			
		||||
 | 
			
		||||
                // amountIn is 100$
 | 
			
		||||
                const amountOutMin = await getAmountOutMin(DEFAULT_AMOUNT_IN_USDC, [
 | 
			
		||||
                    swapToken.address,
 | 
			
		||||
                    wnative.address
 | 
			
		||||
                ]);
 | 
			
		||||
 | 
			
		||||
                //const ID = await getID(testMessagesContract, (await swapMain.nonce()).add('1'));
 | 
			
		||||
 | 
			
		||||
                await expect(
 | 
			
		||||
                    callTransferWithSwapV2(amountOutMin, {
 | 
			
		||||
                        srcPath: [swapToken.address, wnative.address]
 | 
			
		||||
                    })
 | 
			
		||||
                ).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');
 | 
			
		||||
 | 
			
		||||
                    message = await getMessage(testMessagesContract, nonce, DST_CHAIN_ID, {
 | 
			
		||||
                        path: [transitToken.address, swapToken.address],
 | 
			
		||||
                        amountOutMinimum: ethers.BigNumber.from('200000000000000000') // 0.2 eth for 1000$ is min
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
                it('should successfully swap V2 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);
 | 
			
		||||
 | 
			
		||||
                    const { feeAmount } = await calcTokenFees({
 | 
			
		||||
                        bridge: swapMain,
 | 
			
		||||
                        amountWithFee: ethers.BigNumber.from('1000000000')
 | 
			
		||||
                    });
 | 
			
		||||
                    // take only platform comission in transit token
 | 
			
		||||
                    await expect(Number(tokenBalanceAfter)).to.be.eq(feeAmount);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                it('should fail swap V2 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);
 | 
			
		||||
 | 
			
		||||
                    message = await getMessage(testMessagesContract, nonce, DST_CHAIN_ID, {
 | 
			
		||||
                        path: [transitToken.address, swapToken.address],
 | 
			
		||||
                        amountOutMinimum: ethers.BigNumber.from('2000000000000000000') // 2 eth for 1000$ is minOut, too much
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    //const 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 { 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')
 | 
			
		||||
                        }); // 0.3 %
 | 
			
		||||
 | 
			
		||||
                        message = await getMessage(testMessagesContract, nonce, DST_CHAIN_ID, {
 | 
			
		||||
                            path: [transitToken.address, swapToken.address],
 | 
			
		||||
                            integrator: INTEGRATOR,
 | 
			
		||||
                            amountOutMinimum: ethers.BigNumber.from('200000000000000000') // 0.2 eth for 1000$ is minOut, too much
 | 
			
		||||
                        });
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    it('should successfully swapV2 token to token 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);
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    it('should successfully swapV2 token to native 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);
 | 
			
		||||
 | 
			
		||||
                        message = await getMessage(testMessagesContract, nonce, DST_CHAIN_ID, {
 | 
			
		||||
                            path: [transitToken.address, wnative.address],
 | 
			
		||||
                            integrator: INTEGRATOR,
 | 
			
		||||
                            amountOutMinimum: ethers.BigNumber.from('20000000000000000') // 0.02 eth for 1000$ is minOut
 | 
			
		||||
                        });
 | 
			
		||||
 | 
			
		||||
                        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 V2 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);
 | 
			
		||||
 | 
			
		||||
                        message = await getMessage(testMessagesContract, nonce, DST_CHAIN_ID, {
 | 
			
		||||
                            path: [transitToken.address, swapToken.address],
 | 
			
		||||
                            integrator: INTEGRATOR,
 | 
			
		||||
                            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);
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										547
									
								
								Interchain-message/test/RubicCrossChainV3.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										547
									
								
								Interchain-message/test/RubicCrossChainV3.spec.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,547 @@
 | 
			
		|||
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);
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										368
									
								
								Interchain-message/test/RubicFallback.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										368
									
								
								Interchain-message/test/RubicFallback.spec.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,368 @@
 | 
			
		|||
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,
 | 
			
		||||
    VERSION,
 | 
			
		||||
    ZERO_ADDRESS,
 | 
			
		||||
    DEFAULT_AMOUNT_OUT_MIN,
 | 
			
		||||
    EXECUTOR_ADDRESS,
 | 
			
		||||
    INTEGRATOR,
 | 
			
		||||
    DEFAULT_AMOUNT_IN_USDC
 | 
			
		||||
} 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('RubicFallback', () => {
 | 
			
		||||
    let wallet: Wallet, other: Wallet;
 | 
			
		||||
    let swapToken: TestERC20;
 | 
			
		||||
    let transitToken: TestERC20;
 | 
			
		||||
    let swapMain: RubicRouterV2;
 | 
			
		||||
    let router: string;
 | 
			
		||||
    let routerV3: string;
 | 
			
		||||
    let wnative: WETH9;
 | 
			
		||||
    let chainId: number;
 | 
			
		||||
 | 
			
		||||
    let testMessagesContract: TestMessages;
 | 
			
		||||
 | 
			
		||||
    let loadFixture: ReturnType<typeof createFixtureLoader>;
 | 
			
		||||
 | 
			
		||||
    async function getMessage(
 | 
			
		||||
        messagesContract: TestMessages,
 | 
			
		||||
        _nonce: BigNumberish,
 | 
			
		||||
        dstChainId: BigNumberish,
 | 
			
		||||
        {
 | 
			
		||||
            dex = router,
 | 
			
		||||
            receiverEOA = other.address,
 | 
			
		||||
            integrator = INTEGRATOR,
 | 
			
		||||
            version = VERSION,
 | 
			
		||||
            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 encodePath(tokens): Promise<string> {
 | 
			
		||||
        return tokens[0] + '000bb8' + tokens[1].slice(2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async function getID(
 | 
			
		||||
        messagesContract: TestMessages,
 | 
			
		||||
        _nonce: BigNumberish,
 | 
			
		||||
        {
 | 
			
		||||
            dex = router,
 | 
			
		||||
            receiverEOA = other.address,
 | 
			
		||||
            integrator = ZERO_ADDRESS,
 | 
			
		||||
            version = VERSION,
 | 
			
		||||
            path = [wnative.address, transitToken.address],
 | 
			
		||||
            pathV3 = '0x',
 | 
			
		||||
            deadline = DEADLINE,
 | 
			
		||||
            amountOutMinimum = DEFAULT_AMOUNT_OUT_MIN,
 | 
			
		||||
            _receiver = wallet.address,
 | 
			
		||||
            nativeOut = false,
 | 
			
		||||
            _srcChainId = chainId,
 | 
			
		||||
            _dstChainId = DST_CHAIN_ID
 | 
			
		||||
        } = {}
 | 
			
		||||
    ): Promise<string> {
 | 
			
		||||
        return messagesContract.getID(
 | 
			
		||||
            _srcChainId,
 | 
			
		||||
            _dstChainId,
 | 
			
		||||
            {
 | 
			
		||||
                dex,
 | 
			
		||||
                nativeOut,
 | 
			
		||||
                receiverEOA,
 | 
			
		||||
                integrator,
 | 
			
		||||
                version,
 | 
			
		||||
                path,
 | 
			
		||||
                pathV3,
 | 
			
		||||
                deadline,
 | 
			
		||||
                amountOutMinimum
 | 
			
		||||
            },
 | 
			
		||||
            _nonce
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async function callExecuteMessageWithTransferFallback({
 | 
			
		||||
        sender = ZERO_ADDRESS,
 | 
			
		||||
        tokenIn = transitToken.address,
 | 
			
		||||
        amountIn = DEFAULT_AMOUNT_IN_USDC,
 | 
			
		||||
        srcChainID = chainId,
 | 
			
		||||
        message = '0x',
 | 
			
		||||
        executor = EXECUTOR_ADDRESS
 | 
			
		||||
    } = {}): Promise<ContractTransaction> {
 | 
			
		||||
        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);
 | 
			
		||||
 | 
			
		||||
        return _swapMain.executeMessageWithTransferFallback(
 | 
			
		||||
            sender,
 | 
			
		||||
            tokenIn,
 | 
			
		||||
            amountIn,
 | 
			
		||||
            srcChainID,
 | 
			
		||||
            message,
 | 
			
		||||
            executor
 | 
			
		||||
            // { value: nativeIn === null ? cryptoFee.add(ethers.utils.parseEther('0.01')) : nativeIn }
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async function callExecuteMessageWithTransferRefund({
 | 
			
		||||
        tokenIn = transitToken.address,
 | 
			
		||||
        amountIn = DEFAULT_AMOUNT_IN_USDC,
 | 
			
		||||
        message = '0x',
 | 
			
		||||
        executor = EXECUTOR_ADDRESS
 | 
			
		||||
    } = {}): Promise<ContractTransaction> {
 | 
			
		||||
        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);
 | 
			
		||||
 | 
			
		||||
        return _swapMain.executeMessageWithTransferRefund(tokenIn, amountIn, message, executor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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, 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('#Fallback and refund tests', () => {
 | 
			
		||||
        describe('#executeMessageWithTransferFallback', () => {
 | 
			
		||||
            beforeEach('Setup for target executions', async () => {
 | 
			
		||||
                // transfer 1000 USDC
 | 
			
		||||
                await transitToken.transfer(swapMain.address, ethers.BigNumber.from('1000000000'));
 | 
			
		||||
            });
 | 
			
		||||
            describe('Fallback should emit correct event in dst chain', async () => {
 | 
			
		||||
                let nonce: BN;
 | 
			
		||||
                let message: string;
 | 
			
		||||
 | 
			
		||||
                beforeEach('setup before fallback', async () => {
 | 
			
		||||
                    nonce = (await swapMain.nonce()).add('1');
 | 
			
		||||
 | 
			
		||||
                    message = await getMessage(testMessagesContract, nonce, DST_CHAIN_ID, {
 | 
			
		||||
                        dex: ZERO_ADDRESS,
 | 
			
		||||
                        version: 2,
 | 
			
		||||
                        path: [transitToken.address],
 | 
			
		||||
                        amountOutMinimum: ethers.BigNumber.from('0')
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                it('Should successfully fallback token with failed bridge', async () => {
 | 
			
		||||
                    // const ID = await getID(
 | 
			
		||||
                    //     testMessagesContract,
 | 
			
		||||
                    //     (await swapMain.nonce()).add('1'),
 | 
			
		||||
                    //     {
 | 
			
		||||
                    //         dex: ZERO_ADDRESS,
 | 
			
		||||
                    //         version: 2,
 | 
			
		||||
                    //         path: [transitToken.address],
 | 
			
		||||
                    //         amountOutMinimum: ethers.BigNumber.from('0')
 | 
			
		||||
                    //     }
 | 
			
		||||
                    // );
 | 
			
		||||
 | 
			
		||||
                    const balanceBefore = await transitToken.balanceOf(wallet.address);
 | 
			
		||||
 | 
			
		||||
                    await expect(
 | 
			
		||||
                        await callExecuteMessageWithTransferFallback({
 | 
			
		||||
                            message: message
 | 
			
		||||
                        })
 | 
			
		||||
                    ).to.emit(swapMain, 'CrossChainProcessed');
 | 
			
		||||
                    //.withArgs(ID, DEFAULT_AMOUNT_IN_USDC, '3');
 | 
			
		||||
                    const balanceAfter = await transitToken.balanceOf(wallet.address);
 | 
			
		||||
                    await expect(balanceBefore).to.be.eq(balanceAfter);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                it('Should successfully fallback token with failed V3', async () => {
 | 
			
		||||
                    nonce = (await swapMain.nonce()).add('1');
 | 
			
		||||
 | 
			
		||||
                    const path = await encodePath([transitToken.address, swapToken.address]);
 | 
			
		||||
 | 
			
		||||
                    message = await getMessage(testMessagesContract, nonce, DST_CHAIN_ID, {
 | 
			
		||||
                        dex: routerV3,
 | 
			
		||||
                        version: 1,
 | 
			
		||||
                        pathV3: path
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    const balanceBefore = await transitToken.balanceOf(wallet.address);
 | 
			
		||||
 | 
			
		||||
                    await expect(
 | 
			
		||||
                        await callExecuteMessageWithTransferFallback({
 | 
			
		||||
                            message: message
 | 
			
		||||
                        })
 | 
			
		||||
                    ).to.emit(swapMain, 'CrossChainProcessed');
 | 
			
		||||
                    const balanceAfter = await transitToken.balanceOf(wallet.address);
 | 
			
		||||
                    await expect(balanceBefore).to.be.eq(balanceAfter);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                it('Should successfully fallback token with failed V2', async () => {
 | 
			
		||||
                    nonce = (await swapMain.nonce()).add('1');
 | 
			
		||||
 | 
			
		||||
                    message = await getMessage(testMessagesContract, nonce, DST_CHAIN_ID, {
 | 
			
		||||
                        dex: router,
 | 
			
		||||
                        version: 0,
 | 
			
		||||
                        path: [transitToken.address, swapToken.address]
 | 
			
		||||
                    });
 | 
			
		||||
                    const balanceBefore = await transitToken.balanceOf(wallet.address);
 | 
			
		||||
                    await expect(
 | 
			
		||||
                        await callExecuteMessageWithTransferFallback({
 | 
			
		||||
                            message: message
 | 
			
		||||
                        })
 | 
			
		||||
                    ).to.emit(swapMain, 'CrossChainProcessed');
 | 
			
		||||
                    const balanceAfter = await transitToken.balanceOf(wallet.address);
 | 
			
		||||
                    await expect(balanceBefore).to.be.eq(balanceAfter);
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            describe('#executeMessageWithTransferRefund', () => {
 | 
			
		||||
                beforeEach('Setup for target executions', async () => {
 | 
			
		||||
                    // transfer 1000 USDC
 | 
			
		||||
                    await transitToken.transfer(swapMain.address, '1000000000');
 | 
			
		||||
                });
 | 
			
		||||
                describe('Refund should emit correct event in src chain', async () => {
 | 
			
		||||
                    let nonce: BN;
 | 
			
		||||
                    let message: string;
 | 
			
		||||
 | 
			
		||||
                    it('Should successfully refund token with failed bridge', async () => {
 | 
			
		||||
                        nonce = (await swapMain.nonce()).add('1');
 | 
			
		||||
 | 
			
		||||
                        message = await getMessage(testMessagesContract, nonce, DST_CHAIN_ID, {
 | 
			
		||||
                            dex: ZERO_ADDRESS,
 | 
			
		||||
                            version: 2,
 | 
			
		||||
                            path: [transitToken.address],
 | 
			
		||||
                            amountOutMinimum: ethers.BigNumber.from('0')
 | 
			
		||||
                        });
 | 
			
		||||
 | 
			
		||||
                        // const ID = await getID(
 | 
			
		||||
                        //     testMessagesContract,
 | 
			
		||||
                        //     (await swapMain.nonce()).add('1'),
 | 
			
		||||
                        //     {
 | 
			
		||||
                        //         dex: ZERO_ADDRESS,
 | 
			
		||||
                        //         version: 2,
 | 
			
		||||
                        //         path: [transitToken.address],
 | 
			
		||||
                        //         amountOutMinimum: ethers.BigNumber.from('0')
 | 
			
		||||
                        //     }
 | 
			
		||||
                        // );
 | 
			
		||||
 | 
			
		||||
                        const balanceBefore = await transitToken.balanceOf(wallet.address);
 | 
			
		||||
 | 
			
		||||
                        await expect(
 | 
			
		||||
                            await callExecuteMessageWithTransferRefund({
 | 
			
		||||
                                message: message
 | 
			
		||||
                            })
 | 
			
		||||
                        ).to.emit(swapMain, 'CrossChainProcessed');
 | 
			
		||||
                        // .withArgs(ID, DEFAULT_AMOUNT_IN_USDC, '3');
 | 
			
		||||
 | 
			
		||||
                        const balanceAfter = await transitToken.balanceOf(wallet.address);
 | 
			
		||||
                        await expect(balanceBefore.add(DEFAULT_AMOUNT_IN_USDC)).to.be.eq(
 | 
			
		||||
                            balanceAfter
 | 
			
		||||
                        );
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    it('Should successfully refund token with failed V3', async () => {
 | 
			
		||||
                        nonce = (await swapMain.nonce()).add('1');
 | 
			
		||||
 | 
			
		||||
                        const path = await encodePath([transitToken.address, swapToken.address]);
 | 
			
		||||
 | 
			
		||||
                        message = await getMessage(testMessagesContract, nonce, DST_CHAIN_ID, {
 | 
			
		||||
                            dex: routerV3,
 | 
			
		||||
                            version: 1,
 | 
			
		||||
                            pathV3: path
 | 
			
		||||
                        });
 | 
			
		||||
                        const balanceBefore = await transitToken.balanceOf(wallet.address);
 | 
			
		||||
 | 
			
		||||
                        await expect(
 | 
			
		||||
                            await callExecuteMessageWithTransferRefund({
 | 
			
		||||
                                message: message
 | 
			
		||||
                            })
 | 
			
		||||
                        ).to.emit(swapMain, 'CrossChainProcessed');
 | 
			
		||||
                        const balanceAfter = await transitToken.balanceOf(wallet.address);
 | 
			
		||||
                        await expect(balanceBefore.add(DEFAULT_AMOUNT_IN_USDC)).to.be.eq(
 | 
			
		||||
                            balanceAfter
 | 
			
		||||
                        );
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    it('Should successfully refund token with failed V2', async () => {
 | 
			
		||||
                        nonce = (await swapMain.nonce()).add('1');
 | 
			
		||||
 | 
			
		||||
                        message = await getMessage(testMessagesContract, nonce, DST_CHAIN_ID, {
 | 
			
		||||
                            dex: router,
 | 
			
		||||
                            version: 0,
 | 
			
		||||
                            path: [transitToken.address, swapToken.address]
 | 
			
		||||
                        });
 | 
			
		||||
                        const balanceBefore = await transitToken.balanceOf(wallet.address);
 | 
			
		||||
                        await expect(
 | 
			
		||||
                            await callExecuteMessageWithTransferRefund({
 | 
			
		||||
                                message: message
 | 
			
		||||
                            })
 | 
			
		||||
                        ).to.emit(swapMain, 'CrossChainProcessed');
 | 
			
		||||
                        const balanceAfter = await transitToken.balanceOf(wallet.address);
 | 
			
		||||
                        await expect(balanceBefore.add(DEFAULT_AMOUNT_IN_USDC)).to.be.eq(
 | 
			
		||||
                            balanceAfter
 | 
			
		||||
                        );
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										121
									
								
								Interchain-message/test/RubicSettings.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								Interchain-message/test/RubicSettings.spec.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,121 @@
 | 
			
		|||
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 { DEFAULT_AMOUNT_IN_USDC, DEFAULT_AMOUNT_IN } 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('RubicSettings', () => {
 | 
			
		||||
    let wallet: Wallet, other: Wallet;
 | 
			
		||||
    let swapToken: TestERC20;
 | 
			
		||||
    let transitToken: TestERC20;
 | 
			
		||||
    let swapMain: RubicRouterV2;
 | 
			
		||||
    let router: string;
 | 
			
		||||
    let routerV3: string;
 | 
			
		||||
    let wnative: WETH9;
 | 
			
		||||
    // let chainId: number;
 | 
			
		||||
 | 
			
		||||
    let testMessagesContract: TestMessages;
 | 
			
		||||
 | 
			
		||||
    let loadFixture: ReturnType<typeof createFixtureLoader>;
 | 
			
		||||
 | 
			
		||||
    before('create fixture loader', async () => {
 | 
			
		||||
        [wallet, other] = await (ethers as any).getSigners();
 | 
			
		||||
        loadFixture = createFixtureLoader([wallet, other]);
 | 
			
		||||
        // chainId = (await ethers.provider.getNetwork()).chainId;
 | 
			
		||||
 | 
			
		||||
        await hre.network.provider.request({
 | 
			
		||||
            method: 'hardhat_impersonateAccount',
 | 
			
		||||
            params: [TEST_BUS]
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    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('#Contract utility tests', () => {
 | 
			
		||||
        describe('#sweepTokens', () => {
 | 
			
		||||
            beforeEach('Setup for target executions', async () => {
 | 
			
		||||
                // transfer 1000 USDC
 | 
			
		||||
                await transitToken.transfer(swapMain.address, ethers.BigNumber.from('1000000000'));
 | 
			
		||||
 | 
			
		||||
                // create bus and send 1 weth to router
 | 
			
		||||
                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'));
 | 
			
		||||
 | 
			
		||||
                await wnative.connect(bus).transfer(swapMain.address, ethers.utils.parseEther('1'));
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('Should successfully sweep tokens', async () => {
 | 
			
		||||
                const balanceBefore = await transitToken.balanceOf(wallet.address);
 | 
			
		||||
 | 
			
		||||
                await swapMain.sweepTokens(transitToken.address, DEFAULT_AMOUNT_IN_USDC);
 | 
			
		||||
 | 
			
		||||
                const balanceAfter = await transitToken.balanceOf(wallet.address);
 | 
			
		||||
                await expect(balanceBefore.add(DEFAULT_AMOUNT_IN_USDC)).to.be.eq(balanceAfter);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('Should successfully sweep native', async () => {
 | 
			
		||||
                const balanceBefore = await wnative.balanceOf(swapMain.address);
 | 
			
		||||
 | 
			
		||||
                await swapMain.sweepTokens(wnative.address, DEFAULT_AMOUNT_IN);
 | 
			
		||||
 | 
			
		||||
                const balanceAfter = await wnative.balanceOf(swapMain.address);
 | 
			
		||||
                await expect(balanceBefore.sub(DEFAULT_AMOUNT_IN)).to.be.eq(balanceAfter);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('Should successfully fail sweepTokens', async () => {
 | 
			
		||||
                await expect(
 | 
			
		||||
                    swapMain
 | 
			
		||||
                        .connect(other)
 | 
			
		||||
                        .sweepTokens(transitToken.address, DEFAULT_AMOUNT_IN_USDC)
 | 
			
		||||
                ).to.be.revertedWith('BridgeBase: not a manager');
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('Should successfully fail sweepTokens', async () => {
 | 
			
		||||
                await expect(
 | 
			
		||||
                    swapMain.connect(other).sweepTokens(wnative.address, DEFAULT_AMOUNT_IN)
 | 
			
		||||
                ).to.be.revertedWith('BridgeBase: not a manager');
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										17
									
								
								Interchain-message/test/shared/consts.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								Interchain-message/test/shared/consts.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
import { ethers } from 'hardhat';
 | 
			
		||||
 | 
			
		||||
export const DEADLINE = '9999999999999999';
 | 
			
		||||
export const DST_CHAIN_ID = 5;
 | 
			
		||||
export const VERSION_V2 = 0;
 | 
			
		||||
export const VERSION_V3 = 1;
 | 
			
		||||
export const VERSION = 2;
 | 
			
		||||
export const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
 | 
			
		||||
export const INTEGRATOR = '0x23a05b3673DFBf0d1Ce9Bfa6407eD0DbD068aF2D'; // random address
 | 
			
		||||
export const feeDecimals = 10 ** 6;
 | 
			
		||||
export const FIXED_CRYPTO_FEE = ethers.utils.parseEther('1');
 | 
			
		||||
export const EXECUTOR_ADDRESS = '0x503CEF47CE5e37AA62544A363BEF3C9b62d42116';
 | 
			
		||||
export const MESSAGE_BUS_FEE = ethers.utils.parseEther('1').div('100');
 | 
			
		||||
export const DEFAULT_AMOUNT_IN = ethers.utils.parseEther('1');
 | 
			
		||||
export const DEFAULT_AMOUNT_OUT_MIN = ethers.utils.parseEther('1');
 | 
			
		||||
export const DEFAULT_AMOUNT_IN_USDC = ethers.BigNumber.from('100000000');
 | 
			
		||||
export const DEFAULT_AMOUNT_IN_SWAPTOKEN = ethers.BigNumber.from('100000000000000000000');
 | 
			
		||||
							
								
								
									
										123
									
								
								Interchain-message/test/shared/fixtures.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								Interchain-message/test/shared/fixtures.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,123 @@
 | 
			
		|||
import { Fixture } from 'ethereum-waffle';
 | 
			
		||||
import { ethers, network } from 'hardhat';
 | 
			
		||||
import { TestERC20 } from '../../typechain';
 | 
			
		||||
import { RubicRouterV2 } from '../../typechain';
 | 
			
		||||
import { WETH9 } from '../../typechain';
 | 
			
		||||
import { TestMessages } from '../../typechain';
 | 
			
		||||
import { MessageBusSender } from '../../typechain';
 | 
			
		||||
import TokenJSON from '../../artifacts/contracts/test/TestERC20.sol/TestERC20.json';
 | 
			
		||||
import WETHJSON from '../../artifacts/contracts/test/WETH9.sol/WETH9.json';
 | 
			
		||||
import MessageBusJSON from '../../artifacts/contracts/test/MessageBusSender.sol/MessageBusSender.json';
 | 
			
		||||
import { expect } from 'chai';
 | 
			
		||||
import { DST_CHAIN_ID, EXECUTOR_ADDRESS, FIXED_CRYPTO_FEE } from './consts';
 | 
			
		||||
 | 
			
		||||
const envConfig = require('dotenv').config();
 | 
			
		||||
const {
 | 
			
		||||
    ROUTERS_POLYGON: TEST_ROUTERS,
 | 
			
		||||
    NATIVE_POLYGON: TEST_NATIVE,
 | 
			
		||||
    BUS_POLYGON_MAIN: TEST_BUS,
 | 
			
		||||
    TRANSIT_POLYGON: TEST_TRANSIT,
 | 
			
		||||
    SWAP_TOKEN_POLYGON: TEST_SWAP_TOKEN
 | 
			
		||||
} = envConfig.parsed || {};
 | 
			
		||||
 | 
			
		||||
interface SwapContractFixture {
 | 
			
		||||
    swapMain: RubicRouterV2;
 | 
			
		||||
    swapToken: TestERC20;
 | 
			
		||||
    transitToken: TestERC20;
 | 
			
		||||
    wnative: WETH9;
 | 
			
		||||
    router: string;
 | 
			
		||||
    routerV3: string;
 | 
			
		||||
    testMessagesContract: TestMessages;
 | 
			
		||||
    messageBus: MessageBusSender;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const swapContractFixtureInFork: Fixture<SwapContractFixture> = async function (
 | 
			
		||||
    wallets
 | 
			
		||||
): Promise<SwapContractFixture> {
 | 
			
		||||
    const tokenFactory = ethers.ContractFactory.fromSolidity(TokenJSON);
 | 
			
		||||
    let transitToken = tokenFactory.attach(TEST_TRANSIT) as TestERC20;
 | 
			
		||||
    transitToken = transitToken.connect(wallets[0]);
 | 
			
		||||
 | 
			
		||||
    const swapTokenFactory = ethers.ContractFactory.fromSolidity(TokenJSON);
 | 
			
		||||
    let swapToken = swapTokenFactory.attach(TEST_SWAP_TOKEN) as TestERC20;
 | 
			
		||||
    swapToken = swapToken.connect(wallets[0]);
 | 
			
		||||
 | 
			
		||||
    const wnativeFactory = ethers.ContractFactory.fromSolidity(WETHJSON);
 | 
			
		||||
    let wnative = wnativeFactory.attach(TEST_NATIVE) as WETH9;
 | 
			
		||||
    wnative = wnative.connect(wallets[0]);
 | 
			
		||||
 | 
			
		||||
    const RubicRouterV2Factory = await ethers.getContractFactory('RubicRouterV2');
 | 
			
		||||
 | 
			
		||||
    const availableRouters = TEST_ROUTERS.split(',');
 | 
			
		||||
    const router = availableRouters[0];
 | 
			
		||||
    const routerV3 = availableRouters[1];
 | 
			
		||||
 | 
			
		||||
    const swapMain = (await RubicRouterV2Factory.deploy(
 | 
			
		||||
        FIXED_CRYPTO_FEE,
 | 
			
		||||
        '6000',
 | 
			
		||||
        availableRouters,
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        [],
 | 
			
		||||
        EXECUTOR_ADDRESS,
 | 
			
		||||
        TEST_BUS,
 | 
			
		||||
        TEST_NATIVE
 | 
			
		||||
    )) as RubicRouterV2;
 | 
			
		||||
 | 
			
		||||
    await swapMain.setGasFeeOfBlockchain(DST_CHAIN_ID, ethers.utils.parseEther('2').div('100'));
 | 
			
		||||
 | 
			
		||||
    const testMessagesFactory = await ethers.getContractFactory('TestMessages');
 | 
			
		||||
    const testMessagesContract = (await testMessagesFactory.deploy()) as TestMessages;
 | 
			
		||||
 | 
			
		||||
    const messageBusFactory = ethers.ContractFactory.fromSolidity(MessageBusJSON);
 | 
			
		||||
    let messageBus = messageBusFactory.attach(TEST_BUS) as MessageBusSender;
 | 
			
		||||
    messageBus = messageBus.connect(wallets[0]);
 | 
			
		||||
 | 
			
		||||
    const abiCoder = ethers.utils.defaultAbiCoder;
 | 
			
		||||
 | 
			
		||||
    const storageBalancePositionTransit = ethers.utils.keccak256(
 | 
			
		||||
        abiCoder.encode(['address'], [wallets[0].address]) +
 | 
			
		||||
            abiCoder.encode(['uint256'], [0]).slice(2, 66)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const storageBalancePositionSwap = ethers.utils.keccak256(
 | 
			
		||||
        abiCoder.encode(['address'], [wallets[0].address]) +
 | 
			
		||||
            abiCoder.encode(['uint256'], [0]).slice(2, 66)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    await network.provider.send('hardhat_setStorageAt', [
 | 
			
		||||
        transitToken.address,
 | 
			
		||||
        storageBalancePositionTransit,
 | 
			
		||||
        abiCoder.encode(['uint256'], [ethers.utils.parseEther('100000')])
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    await network.provider.send('hardhat_setStorageAt', [
 | 
			
		||||
        swapToken.address,
 | 
			
		||||
        storageBalancePositionSwap,
 | 
			
		||||
        abiCoder.encode(['uint256'], [ethers.utils.parseEther('100000')])
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    expect(await transitToken.balanceOf(wallets[0].address)).to.eq(
 | 
			
		||||
        ethers.utils.parseEther('100000')
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    expect(await swapToken.balanceOf(wallets[0].address)).to.eq(ethers.utils.parseEther('100000'));
 | 
			
		||||
 | 
			
		||||
    await network.provider.send('hardhat_setBalance', [
 | 
			
		||||
        wallets[0].address,
 | 
			
		||||
        '0x152D02C7E14AF6800000' // 100000 eth
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        swapMain,
 | 
			
		||||
        swapToken,
 | 
			
		||||
        transitToken,
 | 
			
		||||
        wnative,
 | 
			
		||||
        router,
 | 
			
		||||
        routerV3,
 | 
			
		||||
        testMessagesContract,
 | 
			
		||||
        messageBus
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										63
									
								
								Interchain-message/test/shared/utils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								Interchain-message/test/shared/utils.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,63 @@
 | 
			
		|||
import { IUniswapV2Router02 } from '../../typechain';
 | 
			
		||||
import { IUniswapRouterV3 } from '../../typechain';
 | 
			
		||||
import UniV2JSON from '@uniswap/v2-periphery/build/UniswapV2Router02.json';
 | 
			
		||||
import UniV3JSON from '@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json';
 | 
			
		||||
import { ethers } from 'hardhat';
 | 
			
		||||
import { Wallet } from '@ethersproject/wallet';
 | 
			
		||||
 | 
			
		||||
export const getRouterV2 = async function (
 | 
			
		||||
    wallet: Wallet,
 | 
			
		||||
    routerAddress: string
 | 
			
		||||
): Promise<IUniswapV2Router02> {
 | 
			
		||||
    const routerFactory = ethers.ContractFactory.fromSolidity(UniV2JSON);
 | 
			
		||||
    let router = routerFactory.attach(routerAddress) as IUniswapV2Router02;
 | 
			
		||||
    router = router.connect(wallet);
 | 
			
		||||
 | 
			
		||||
    return router;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// not used
 | 
			
		||||
// export const createPoolV2 = async function (
 | 
			
		||||
//     wallet: Wallet,
 | 
			
		||||
//     routerAddress: string,
 | 
			
		||||
//     token: string,
 | 
			
		||||
//     tokenAmount = ethers.utils.parseEther('100')
 | 
			
		||||
// ): Promise<IUniswapV2Router02> {
 | 
			
		||||
//     const router = await getRouterV2(wallet, routerAddress);
 | 
			
		||||
//
 | 
			
		||||
//     await router.addLiquidityETH(
 | 
			
		||||
//         token,
 | 
			
		||||
//         tokenAmount,
 | 
			
		||||
//         tokenAmount,
 | 
			
		||||
//         ethers.utils.parseEther('100'),
 | 
			
		||||
//         await router.signer.getAddress(),
 | 
			
		||||
//         DEADLINE,
 | 
			
		||||
//         { value: ethers.utils.parseEther('100') }
 | 
			
		||||
//     );
 | 
			
		||||
//
 | 
			
		||||
//     return router;
 | 
			
		||||
// };
 | 
			
		||||
 | 
			
		||||
export const getRouterV3 = async function (
 | 
			
		||||
    wallet: Wallet,
 | 
			
		||||
    routerAddressV3: string
 | 
			
		||||
): Promise<IUniswapRouterV3> {
 | 
			
		||||
    const routerFactoryV3 = ethers.ContractFactory.fromSolidity(UniV3JSON);
 | 
			
		||||
    let routerV3 = routerFactoryV3.attach(routerAddressV3) as IUniswapRouterV3;
 | 
			
		||||
    routerV3 = routerV3.connect(wallet);
 | 
			
		||||
 | 
			
		||||
    return routerV3;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function hexStringToByteArray(hexString) {
 | 
			
		||||
    if (hexString.length % 2 !== 0) {
 | 
			
		||||
        // eslint-disable-next-line @typescript-eslint/no-throw-literal
 | 
			
		||||
        throw 'Must have an even number of hex digits to convert to bytes';
 | 
			
		||||
    }
 | 
			
		||||
    var numBytes = hexString.length / 2;
 | 
			
		||||
    var byteArray = new Uint8Array(numBytes);
 | 
			
		||||
    for (var i = 0; i < numBytes; i++) {
 | 
			
		||||
        byteArray[i] = parseInt(hexString.substr(i * 2, 2), 16);
 | 
			
		||||
    }
 | 
			
		||||
    return byteArray;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								Interchain-message/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								Interchain-message/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
{
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
    "target": "es2018",
 | 
			
		||||
    "module": "commonjs",
 | 
			
		||||
    "strict": true,
 | 
			
		||||
    "esModuleInterop": true,
 | 
			
		||||
    "resolveJsonModule": true,
 | 
			
		||||
    "outDir": "dist",
 | 
			
		||||
    "typeRoots": ["./typechain", "./node_modules/@types", "./types"],
 | 
			
		||||
    "types": ["@nomiclabs/hardhat-ethers", "@nomiclabs/hardhat-waffle"],
 | 
			
		||||
    "noImplicitAny": false
 | 
			
		||||
  },
 | 
			
		||||
  "include": ["./test"],
 | 
			
		||||
  "files": ["./hardhat.config.ts"]
 | 
			
		||||
}
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
		Loading…
	
		Reference in New Issue
	
	Block a user