diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0d5285c..c5c5f2a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: with: node-version: ${{ matrix.node-version }} - name: Install dependencies - run: npm ci + run: npm i - name: Check lint run: npm run lint - name: Build diff --git a/.gitignore b/.gitignore index b1981c6..9e4c4a7 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,6 @@ dist config.json .nuxt docs + +examples/package-lock.json +package-lock.json diff --git a/examples/.env.example b/examples/.env.example index a15c6cf..2864b96 100644 --- a/examples/.env.example +++ b/examples/.env.example @@ -12,7 +12,10 @@ NETWORK=testnet # SEPOLIA DETAILS NETWORK_0_RPC= NETWORK_0_BRIDGE= +NETWORK_0_BRIDGE_EXTENSION= +NETWORK_0_WRAPPER= # CARDONA DETAILS NETWORK_1_RPC= NETWORK_1_BRIDGE= +NETWORK_1_BRIDGE_EXTENSION= diff --git a/examples/config.js b/examples/config.js index 149d2ae..92f986a 100644 --- a/examples/config.js +++ b/examples/config.js @@ -12,14 +12,17 @@ module.exports = { network: process.env.NETWORK || 'testnet', configuration: { 0: { - rpc: process.env.NETWORK_0_RPC || 'https://eth-sepolia.g.alchemy.com/v2/demo', + rpc: process.env.NETWORK_0_RPC || 'https://rpc.sepolia.org', bridgeAddress: process.env.NETWORK_0_BRIDGE || '0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582', - wrapperAddress: '0x0f04f8434bac2e1db8fca8a34d3e177b6c7ccaba', + bridgeExtensionAddress: process.env.NETWORK_0_BRIDGE_EXTENSION || '0x2311BFA86Ae27FC10E1ad3f805A2F9d22Fc8a6a1', + wrapperAddress: process.env.NETWORK_0_WRAPPER || '0x0f04f8434bac2e1db8fca8a34d3e177b6c7ccaba', + isEIP1559Supported: true }, 1: { rpc: process.env.NETWORK_1_RPC || 'https://rpc.cardona.zkevm-rpc.com', bridgeAddress: process.env.NETWORK_1_BRIDGE || '0x528e26b25a34a4A5d0dbDa1d57D318153d2ED582', + bridgeExtensionAddress: process.env.NETWORK_1_BRIDGE_EXTENSION || '0x2311BFA86Ae27FC10E1ad3f805A2F9d22Fc8a6a1', isEIP1559Supported: true }, }, diff --git a/examples/lxly/bridge_and_call/bridge_and_call.js b/examples/lxly/bridge_and_call/bridge_and_call.js new file mode 100644 index 0000000..e10916e --- /dev/null +++ b/examples/lxly/bridge_and_call/bridge_and_call.js @@ -0,0 +1,122 @@ +const { getLxLyClient, tokens, configuration, from } = require('../../utils_lxly'); + +// counter example smart contract on destination network. +const CounterABI = [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "count", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "increment", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "originAddress", + "type": "address" + }, + { + "internalType": "uint32", + "name": "originNetwork", + "type": "uint32" + }, + { + "internalType": "bytes", + "name": "metadata", + "type": "bytes" + } + ], + "name": "onMessageReceived", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } +] + +const execute = async () => { + const client = await getLxLyClient(); + + // set token as `eth`. + const token = "0x0000000000000000000000000000000000000000"; + // not bridging any token this time + const amount = "0x0"; + // because we are bridging from cardona. + const sourceNetwork = 1; + // sending to zkyoto + const destinationNetwork = 0; + // change it to the counter smart contract deployed on destination network. + const callAddress = "0x43854F7B2a37fA13182BBEA76E50FC8e3D298CF1"; + // if transaction fails, then the funds will be sent back to user's address on destination network. + const fallbackAddress = from; + // if true, then the global exit root will be updated. + const forceUpdateGlobalExitRoot = true; + // get the call Contract ABI instance. + const callContract = client.contract(CounterABI, callAddress, destinationNetwork); + // prepare the call data for the counter smart contract on destination chain. + const callData = await callContract.encodeAbi("increment", "0x4"); + + let result; + // Call bridgeAndCall function. + if (client.client.network === "testnet") { + console.log("testnet"); + result = await client.bridgeExtensions[sourceNetwork].bridgeAndCall( + token, + amount, + destinationNetwork, + callAddress, + fallbackAddress, + callData, + forceUpdateGlobalExitRoot, + permitData="0x0", // permitData is optional + ) + } else { + console.log("mainnet"); + result = await client.bridgeExtensions[sourceNetwork].bridgeAndCall( + token, + amount, + destinationNetwork, + callAddress, + fallbackAddress, + callData, + forceUpdateGlobalExitRoot, + ) + } + + console.log("result", result); + const txHash = await result.getTransactionHash(); + console.log("txHash", txHash); + const receipt = await result.getReceipt(); + console.log("receipt", receipt); +} + +execute().then(() => { +}).catch(err => { + console.error("err", err); +}).finally(_ => { + process.exit(0); +}); diff --git a/examples/lxly/bridge_and_call/claim_message.js b/examples/lxly/bridge_and_call/claim_message.js new file mode 100644 index 0000000..b213596 --- /dev/null +++ b/examples/lxly/bridge_and_call/claim_message.js @@ -0,0 +1,43 @@ +const { getLxLyClient, tokens, configuration, from, to } = require('../../utils_lxly'); + +const execute = async () => { + const client = await getLxLyClient(); + // example bridge txn hash from the source chain. + const bridgeTransactionHash = "0x6f312627ea607a39f494f49e8b40e9a71c61ad3173a6876f09dd9de7b540c040"; + // Source Network ID, in this example its 1 since its from cardona. + const sourceNetworkId = 1; + // Destination Network ID, in this example its 0 since its to sepolia. + const destinationNetworkId = 0; + // API for building payload for claim + // `bridgeIndex` is needed when there's multiple bridge events in a single txn. It is used to select the claim associated bridge event. + const result = + await client.bridgeUtil.buildPayloadForClaim(bridgeTransactionHash, sourceNetworkId, bridgeIndex=1) + // payload is then passed to `claimMessage` API + .then((payload) => { + return client.bridges[destinationNetworkId].claimMessage( + payload.smtProof, + payload.smtProofRollup, + payload.globalIndex, + payload.mainnetExitRoot, + payload.rollupExitRoot, + payload.originNetwork, + payload.originTokenAddress, + payload.destinationNetwork, + payload.destinationAddress, + payload.amount, + payload.metadata + ); + }); + + const txHash = await result.getTransactionHash(); + console.log("txHash", txHash); + const receipt = await result.getReceipt(); + console.log("receipt", receipt); +} + +execute().then(() => { +}).catch(err => { + console.error("err", err); +}).finally(_ => { + process.exit(0); +}); \ No newline at end of file diff --git a/examples/lxly/erc20/claim_asset.js b/examples/lxly/erc20/claim_asset.js index 2387445..187d4f0 100644 --- a/examples/lxly/erc20/claim_asset.js +++ b/examples/lxly/erc20/claim_asset.js @@ -1,12 +1,13 @@ const { getLxLyClient, tokens, configuration, from } = require('../../utils_lxly'); const execute = async () => { - const bridgeTransactionHash = "0x66f0e813ee4eead3709b2db5478e710e74f5d7460a0008d0022dbc7680e5d5ad"; - const client = await getLxLyClient('mainnet'); + const bridgeTransactionHash = "0x89e43e85eae56d42ae09a23f1c89c47e9815b7f88d05d4a9427ee13b4772e652"; + const client = await getLxLyClient('testnet'); - const token = client.erc20("0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0", 0); + const token = client.erc20(tokens[0].ether, 0); + const sourceNetworkId = 1; - const result = await token.claimAsset(bridgeTransactionHash, 1, {returnTransaction: true}); + const result = await token.claimAsset(bridgeTransactionHash, sourceNetworkId, {returnTransaction: true}); console.log("result", result); const txHash = await result.getTransactionHash(); console.log("txHash", txHash); diff --git a/examples/utils_lxly.js b/examples/utils_lxly.js index 9cd6335..a61eec9 100644 --- a/examples/utils_lxly.js +++ b/examples/utils_lxly.js @@ -8,7 +8,7 @@ const config = require('./config'); const SCALING_FACTOR = new bn(10).pow(new bn(18)); use(Web3ClientPlugin) -setProofApi('https://api-gateway.polygon.technology/api/v3/proof/mainnet') +setProofApi('https://api-gateway.polygon.technology/api/v3/proof/testnet') const getLxLyClient = async (network = 'testnet') => { const lxLyClient = new LxLyClient(); return await lxLyClient.init({ @@ -20,6 +20,7 @@ const getLxLyClient = async (network = 'testnet') => { configuration: { bridgeAddress: config.configuration[0].bridgeAddress, wrapperAddress: config.configuration[0].wrapperAddress, + bridgeExtensionAddress: config.configuration[0].bridgeExtensionAddress, isEIP1559Supported: true }, defaultConfig: { @@ -30,6 +31,7 @@ const getLxLyClient = async (network = 'testnet') => { provider: new HDWalletProvider([config.user1.privateKey], config.configuration[1].rpc), configuration: { bridgeAddress: config.configuration[1].bridgeAddress, + bridgeExtensionAddress: config.configuration[1].bridgeExtensionAddress, isEIP1559Supported: false }, defaultConfig: { diff --git a/package-lock.json b/package-lock.json index feccd0f..aaa1f83 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,16 @@ { "name": "@maticnetwork/lxlyjs", - "version": "2.2.1", + "version": "2.3.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@maticnetwork/lxlyjs", - "version": "2.2.1", + "version": "2.3.0", "license": "MIT", "dependencies": { "@ethereumjs/util": "^9.0.3", + "@maticnetwork/lxlyjs": "^2.3.0-beta.2", "assert": "^2.1.0", "buffer": "^6.0.3", "node-fetch": "^2.7.0", @@ -377,6 +378,21 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@maticnetwork/lxlyjs": { + "version": "2.3.0-beta.2", + "resolved": "https://registry.npmjs.org/@maticnetwork/lxlyjs/-/lxlyjs-2.3.0-beta.2.tgz", + "integrity": "sha512-i01lW+8MMCGEaM3bfwqnB1VRnJNwSEBDQMqgf81JRG4n9PBKDoCUCHpqTxDgC0Ae8CnrhnCY/M4cuLGGRQri9Q==", + "dependencies": { + "@ethereumjs/util": "^9.0.3", + "assert": "^2.1.0", + "buffer": "^6.0.3", + "node-fetch": "^2.7.0", + "stream": "^0.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/@noble/curves": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", @@ -5188,6 +5204,18 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "@maticnetwork/lxlyjs": { + "version": "2.3.0-beta.2", + "resolved": "https://registry.npmjs.org/@maticnetwork/lxlyjs/-/lxlyjs-2.3.0-beta.2.tgz", + "integrity": "sha512-i01lW+8MMCGEaM3bfwqnB1VRnJNwSEBDQMqgf81JRG4n9PBKDoCUCHpqTxDgC0Ae8CnrhnCY/M4cuLGGRQri9Q==", + "requires": { + "@ethereumjs/util": "^9.0.3", + "assert": "^2.1.0", + "buffer": "^6.0.3", + "node-fetch": "^2.7.0", + "stream": "^0.0.2" + } + }, "@noble/curves": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", diff --git a/package.json b/package.json index 2b65ae4..03bb0b1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@maticnetwork/lxlyjs", - "version": "2.3.0-beta.2", + "version": "2.3.1", "description": "Javascript developer library for interacting with Polygon LxLy Bridge", "main": "dist/lxly.node.js", "types": "dist/ts/index.d.ts", @@ -43,6 +43,7 @@ "homepage": "https://github.com/0xpolygon/lxly.js#readme", "dependencies": { "@ethereumjs/util": "^9.0.3", + "@maticnetwork/lxlyjs": "^2.3.0-beta.2", "assert": "^2.1.0", "buffer": "^6.0.3", "node-fetch": "^2.7.0", @@ -51,10 +52,10 @@ "devDependencies": { "@types/node-fetch": "^2.6.11", "@typescript-eslint/parser": "^7.3.1", - "husky": "^9.0.11", - "lint-staged": "^15.2.2", "copy-webpack-plugin": "^12.0.2", "cross-env": "^7.0.3", + "husky": "^9.0.11", + "lint-staged": "^15.2.2", "ts-loader": "^8.0.0", "tslint": "^6.1.3", "typescript": "^4.9.5", diff --git a/src/abis/mainnet/BridgeExtension.ts b/src/abis/mainnet/BridgeExtension.ts new file mode 100644 index 0000000..739a257 --- /dev/null +++ b/src/abis/mainnet/BridgeExtension.ts @@ -0,0 +1 @@ +export default [{"type":"constructor","inputs":[{"name":"bridge_","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"function","name":"bridge","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract PolygonZkEVMBridgeV2"}],"stateMutability":"view"},{"type":"function","name":"bridgeAndCall","inputs":[{"name":"token","type":"address","internalType":"address"},{"name":"amount","type":"uint256","internalType":"uint256"},{"name":"destinationNetwork","type":"uint32","internalType":"uint32"},{"name":"callAddress","type":"address","internalType":"address"},{"name":"fallbackAddress","type":"address","internalType":"address"},{"name":"callData","type":"bytes","internalType":"bytes"},{"name":"forceUpdateGlobalExitRoot","type":"bool","internalType":"bool"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"onMessageReceived","inputs":[{"name":"originAddress","type":"address","internalType":"address"},{"name":"originNetwork","type":"uint32","internalType":"uint32"},{"name":"data","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"payable"},{"type":"error","name":"AmountDoesNotMatchMsgValue","inputs":[]},{"type":"error","name":"InvalidDepositIndex","inputs":[]},{"type":"error","name":"OriginMustBeBridgeExtension","inputs":[]},{"type":"error","name":"SenderMustBeBridge","inputs":[]},{"type":"error","name":"UnclaimedAsset","inputs":[]}] \ No newline at end of file diff --git a/src/abis/mainnet/index.ts b/src/abis/mainnet/index.ts index 52f5f6e..957a2fd 100644 --- a/src/abis/mainnet/index.ts +++ b/src/abis/mainnet/index.ts @@ -5,6 +5,7 @@ import PolygonZkEVMGlobalExitRoot from "./PolygonZkEVMGlobalExitRoot"; import PolygonZkEVMGlobalExitRootL2 from "./PolygonZkEVMGlobalExitRootL2"; import ZkEVMBridgeAdapter from "./ZkEVMBridgeAdapter"; import ZkEVMWrapper from "./ZkEVMWrapper"; +import BridgeExtension from "./BridgeExtension"; import GasPorter from "./GasPorter"; export default { @@ -15,5 +16,6 @@ export default { PolygonZkEVMGlobalExitRoot, PolygonZkEVMGlobalExitRootL2, ZkEVMBridgeAdapter, - ZkEVMWrapper + ZkEVMWrapper, + BridgeExtension, } diff --git a/src/abis/testnet/BridgeExtension.ts b/src/abis/testnet/BridgeExtension.ts new file mode 100644 index 0000000..d294888 --- /dev/null +++ b/src/abis/testnet/BridgeExtension.ts @@ -0,0 +1,30 @@ +export default [ + { "type": "constructor", "inputs": [], "stateMutability": "nonpayable" }, + { "type": "function", "name": "bridge", + "inputs": [], + "outputs": [ + { "name": "", "type": "address", "internalType": "contract PolygonZkEVMBridgeV2" } + ], "stateMutability": "view" + }, + { "type": "function", "name": "bridgeAndCall", + "inputs": [ + { "name": "token", "type": "address", "internalType": "address" }, + { "name": "amount", "type": "uint256", "internalType": "uint256" }, + { "name": "permitData", "type": "bytes", "internalType": "bytes" }, + { "name": "destinationNetwork", "type": "uint32", "internalType": "uint32" }, + { "name": "callAddress", "type": "address", "internalType": "address" }, + { "name": "fallbackAddress", "type": "address", "internalType": "address" }, + { "name": "callData", "type": "bytes", "internalType": "bytes" }, + { "name": "forceUpdateGlobalExitRoot", "type": "bool", "internalType": "bool" } + ], "outputs": [], "stateMutability": "payable" + }, + { "type": "function", "name": "initialize", "inputs": [{ "name": "bridge_", "type": "address", "internalType": "address" }], "outputs": [], "stateMutability": "nonpayable" }, + { "type": "function", "name": "onMessageReceived", "inputs": [{ "name": "originAddress", "type": "address", "internalType": "address" }, { "name": "originNetwork", "type": "uint32", "internalType": "uint32" }, { "name": "data", "type": "bytes", "internalType": "bytes" }], "outputs": [], "stateMutability": "payable" }, + { "type": "event", "name": "Initialized", "inputs": [{ "name": "version", "type": "uint8", "indexed": false, "internalType": "uint8" }], "anonymous": false }, + { "type": "error", "name": "AmountDoesNotMatchMsgValue", "inputs": [] }, + { "type": "error", "name": "InvalidAddress", "inputs": [] }, + { "type": "error", "name": "InvalidDepositIndex", "inputs": [] }, + { "type": "error", "name": "OriginMustBeBridgeExtension", "inputs": [] }, + { "type": "error", "name": "SenderMustBeBridge", "inputs": [] }, + { "type": "error", "name": "UnclaimedAsset", "inputs": [] } +] \ No newline at end of file diff --git a/src/abis/testnet/index.ts b/src/abis/testnet/index.ts index 52f5f6e..4ec78a7 100644 --- a/src/abis/testnet/index.ts +++ b/src/abis/testnet/index.ts @@ -1,3 +1,4 @@ +import BridgeExtension from "./BridgeExtension"; import ERC20 from "./ERC20"; import PolygonZkEVM from "./PolygonZkEVM"; import PolygonZkEVMBridge from "./PolygonZkEVMBridge"; @@ -15,5 +16,6 @@ export default { PolygonZkEVMGlobalExitRoot, PolygonZkEVMGlobalExitRootL2, ZkEVMBridgeAdapter, - ZkEVMWrapper + ZkEVMWrapper, + BridgeExtension } diff --git a/src/config.ts b/src/config.ts index cac0f8f..4192d13 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,6 +1,6 @@ export const config = { BridgeService: { - testnet: 'https://proof-generator.polygon.technology/api/zkevm/cardona/', - mainnet: 'https://proof-generator.polygon.technology/api/zkevm/mainnet/' + testnet: 'https://api-gateway.polygon.technology/api/v3/proof/testnet/', + mainnet: 'https://api-gateway.polygon.technology/api/v3/proof/mainnet/' } } diff --git a/src/interfaces/bridge_extension.ts b/src/interfaces/bridge_extension.ts new file mode 100644 index 0000000..99a7ec8 --- /dev/null +++ b/src/interfaces/bridge_extension.ts @@ -0,0 +1,5 @@ +import { BridgeExtension } from "../lxly"; + +export interface IBridgeExtensions { + [key: number]: BridgeExtension; +} \ No newline at end of file diff --git a/src/interfaces/index.ts b/src/interfaces/index.ts index 8301e90..31e5f92 100644 --- a/src/interfaces/index.ts +++ b/src/interfaces/index.ts @@ -22,3 +22,4 @@ export * from "./bridge"; export * from "./gas_porter"; export * from "./gas_porters"; export * from "./wrappers"; +export * from "./bridge_extension"; diff --git a/src/lxly/bridge.ts b/src/lxly/bridge.ts index 1a0f229..d1d2efd 100644 --- a/src/lxly/bridge.ts +++ b/src/lxly/bridge.ts @@ -26,7 +26,7 @@ export class Bridge extends BaseToken { * @param {string} token Token address * @param {number} destinationNetwork Network at which tokens will be bridged * @param {string} destinationAddress Address to which tokens will be bridged - * @param {TYPE_AMOUNT} amountamount amount of tokens + * @param {TYPE_AMOUNT} amount amount of tokens * @param {string} [permitData] Permit data to avoid approve call * @param {ITransactionOption} [option] * diff --git a/src/lxly/bridge_extension.ts b/src/lxly/bridge_extension.ts new file mode 100644 index 0000000..782fea7 --- /dev/null +++ b/src/lxly/bridge_extension.ts @@ -0,0 +1,90 @@ +import { BaseToken, Web3SideChainClient, Converter, promiseResolve } from "../utils"; +import { IBaseClientConfig, ITransactionOption } from "../interfaces"; +import { TYPE_AMOUNT } from "../types"; +import { + ADDRESS_ZERO +} from '..'; + +export class BridgeExtension extends BaseToken { + + networkID_: number; + + constructor(client_: Web3SideChainClient, address: string, networkId: number) { + super({ + address: address, + name: 'BridgeExtension', + networkId: networkId + }, client_); + } + + method(methodName: string, ...args) { + return this.getContract().then(contract => { + return contract.method(methodName, ...args); + }); + } + + isEtherToken() { + return this.contractParam.address === ADDRESS_ZERO; + } + + /** + * bridge function to be called on that network from where token is to be transferred to a different network + * + * @param {string} token Token address + * @param {TYPE_AMOUNT} amount amount of tokens + * @param {number} destinationNetwork Network at which tokens will be bridged + * @param {string} callAddress Address to which tokens will be bridged + * @param {string} fallbackAddress Address to which tokens will be bridged if the execution fails. + * @param {string} callData Encoded function data of the smart contract at target callAddress + * @param {forceUpdateGlobalExitRoot} boolean boolean to force update global exit root + * @param {string} permitData Permit data to avoid approve call + * @param {ITransactionOption} [option] + * + * @returns + * @memberof BridgeExtension + */ + bridgeAndCall( + token: string, + amount: TYPE_AMOUNT, + destinationNetwork: number, + callAddress: string, + fallbackAddress: string, + calldata: string, + forceUpdateGlobalExitRoot: boolean, + permitData?: string, + option?: ITransactionOption, + ) { + if (this.isEtherToken()) { + option.value = Converter.toHex(amount); + } + + if (permitData === undefined) { + return this.method( + "bridgeAndCall", + token, + Converter.toHex(amount), + destinationNetwork, + callAddress, + fallbackAddress, + calldata, + forceUpdateGlobalExitRoot + ).then(method => { + return this.processWrite(method, option); + }); + } else { + return this.method( + "bridgeAndCall", + token, + Converter.toHex(amount), + permitData, + destinationNetwork, + callAddress, + fallbackAddress, + calldata, + forceUpdateGlobalExitRoot + ).then(method => { + return this.processWrite(method, option); + }); + } + } +} diff --git a/src/lxly/erc20.ts b/src/lxly/erc20.ts index cc555db..195a918 100644 --- a/src/lxly/erc20.ts +++ b/src/lxly/erc20.ts @@ -346,13 +346,14 @@ export class ERC20 extends Token { amount: TYPE_AMOUNT, userAddress: string, destinationNetworkId: number, - forceUpdateGlobalExitRoot = true + forceUpdateGlobalExitRoot = true, + option?: ITransactionOption ) { // should be allowed to be used only in root chain this.checkAdapterPresent("depositCustomERC20"); // should not be allowed to use for native asset this.checkForNonNative("depositCustomERC20"); - return this.bridgeAdapter.bridgeToken(userAddress, amount, destinationNetworkId, forceUpdateGlobalExitRoot); + return this.bridgeAdapter.bridgeToken(userAddress, amount, destinationNetworkId, forceUpdateGlobalExitRoot, option); } /** @@ -883,7 +884,7 @@ export class ERC20 extends Token { * @memberof ERC20 */ bridgeAssetAndGasWithPlotRoute(cargo: ICargo, option?: ITransactionOption) { - return this.getPlotRoute(cargo, option).then(data => { + return this.getPlotRoute(cargo).then(data => { return this.gasPorter.bridgeAssetAndGas( data.bridgeAssetAndGas.requestConversion, data.bridgeAssetAndGas.forceUpdateGlobalExitRoot, @@ -898,6 +899,7 @@ export class ERC20 extends Token { data.bridgeAssetAndGas.tokenAmount, data.bridgeAssetAndGas.tokenPermitData, { + ...option, value: data.msgValue } ); diff --git a/src/lxly/index.ts b/src/lxly/index.ts index 4512a27..8e65aea 100644 --- a/src/lxly/index.ts +++ b/src/lxly/index.ts @@ -2,6 +2,7 @@ import { ERC20 } from "./erc20"; import { Contract } from "./contract"; import { Bridge } from "./bridge"; import { BridgeUtil } from "./bridge_util"; +import { BridgeExtension } from "./bridge_extension"; import { BridgeClient, setProofApi } from "../utils"; import { IBaseClientConfig, IContracts, IWrappers, IGasPorters } from "../interfaces"; import { config as urlConfig } from "../config"; @@ -13,6 +14,7 @@ import { GasPorter } from "./gas_porter"; export * from "./bridge"; export * from "./bridge_util"; export * from "./wrapper"; +export * from "./bridge_extension"; export * from "./gas_porter"; export class LxLyClient extends BridgeClient { @@ -40,6 +42,14 @@ export class LxLyClient extends BridgeClient { ); } + if (value.configuration.bridgeExtensionAddress) { + this.bridgeExtensions[key] = new BridgeExtension( + this.client, + value.configuration.bridgeExtensionAddress, + Number(key) + ); + } + if (value.configuration.gasPorterAddress) { this.gasPorters[key] = new GasPorter( this.client, @@ -105,6 +115,7 @@ export class LxLyClient extends BridgeClient { bridge: this.bridges[networkId], bridgeUtil: this.bridgeUtil, wrapper: this.wrappers[networkId], + bridgeExtension: this.bridgeExtensions[networkId], gasPorter: this.gasPorters[networkId] } as IContracts; } diff --git a/src/utils/bridge_client.ts b/src/utils/bridge_client.ts index 0d1d4ea..d78ccf4 100644 --- a/src/utils/bridge_client.ts +++ b/src/utils/bridge_client.ts @@ -3,12 +3,15 @@ import { BridgeUtil } from "../lxly"; import { service } from "../services"; import { IBaseClientConfig } from ".."; import { IBridges } from "../interfaces"; +import { IBridgeExtensions } from "../interfaces/bridge_extension"; +import { BridgeExtension } from "../lxly/bridge_extension"; export class BridgeClient { client: Web3SideChainClient = new Web3SideChainClient(); bridgeUtil: BridgeUtil; bridges: IBridges = {}; + bridgeExtensions: IBridgeExtensions = {}; /** * check if the bridge is claimable