From 18be1b0a06820c92b7a98dec55013f080682ab23 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Wed, 10 Nov 2021 21:40:31 +0800 Subject: [PATCH 01/21] adapt web3subscribe Signed-off-by: Zhang Junyu --- clients/bridge/bridge.js | 6 +++--- clients/bridge/deposit.js | 2 +- clients/bridge/init.js | 2 +- clients/bridge/status.js | 2 +- clients/token/allowance.js | 2 +- clients/token/balance.js | 2 +- clients/token/mint-rio.js | 4 ++-- clients/token/mint.js | 4 ++-- clients/tx/nonce.js | 4 ++-- clients/tx/tx.js | 4 ++-- 10 files changed, 16 insertions(+), 16 deletions(-) diff --git a/clients/bridge/bridge.js b/clients/bridge/bridge.js index 0dc569a..b23cbce 100644 --- a/clients/bridge/bridge.js +++ b/clients/bridge/bridge.js @@ -1,7 +1,7 @@ const Web3 = require("web3"); const BigNumber = Web3.utils.BN; -const Client = require("web3subscriber/client"); -const PBinder = require("web3subscriber/pbinder"); +const Client = require("web3subscriber/src/client"); +const PBinder = require("web3subscriber/src/pbinder"); const ERC20 = require("../../build/contracts/IERC20.json"); const VERIFIER = require("../../build/contracts/Verifier.json"); @@ -211,7 +211,7 @@ class Bridge { } async close() { - this.web3.currentProvider.engine.stop(); + await this.web3.currentProvider.engine.stop(); } } diff --git a/clients/bridge/deposit.js b/clients/bridge/deposit.js index 666f8c1..b3b8cc3 100644 --- a/clients/bridge/deposit.js +++ b/clients/bridge/deposit.js @@ -1,6 +1,6 @@ const Web3 = require("web3") const FileSys = require("fs") -const Client = require("web3subscriber/client"); +const Client = require("web3subscriber/src/client"); const Config = require('../config'); const BridgeABI = require('./abi'); const TokenInfo = require("../../build/contracts/Token.json"); diff --git a/clients/bridge/init.js b/clients/bridge/init.js index 42b9ebd..9e4e236 100644 --- a/clients/bridge/init.js +++ b/clients/bridge/init.js @@ -1,5 +1,5 @@ const Web3 = require("web3"); -const Client = require("web3subscriber/client"); +const Client = require("web3subscriber/src/client"); const Config = require('../config'); const TokenInfo = require("../../build/contracts/Token.json"); const BridgeABI = require("./abi"); diff --git a/clients/bridge/status.js b/clients/bridge/status.js index 74dd034..5a63caa 100644 --- a/clients/bridge/status.js +++ b/clients/bridge/status.js @@ -1,6 +1,6 @@ const Web3 = require("web3") const FileSys = require("fs") -const Client = require("web3subscriber/client"); +const Client = require("web3subscriber/src/client"); const Config = require('../config'); const BridgeABI = require('./abi'); const TokenInfo = require("../../build/contracts/Token.json"); diff --git a/clients/token/allowance.js b/clients/token/allowance.js index 0c86a91..7a3157a 100644 --- a/clients/token/allowance.js +++ b/clients/token/allowance.js @@ -1,6 +1,6 @@ const Web3 = require("web3") const Config = require("../config") -const Client = require("web3subscriber/client") +const Client = require("web3subscriber/src/client") const TokenInfo = require("../../build/contracts/Token.json") const Utils = require("../utils"); const Secrets = require('../../.secrets'); diff --git a/clients/token/balance.js b/clients/token/balance.js index fba46e6..f431841 100644 --- a/clients/token/balance.js +++ b/clients/token/balance.js @@ -1,6 +1,6 @@ const Web3 = require("web3") const Config = require("../config") -const Client = require("web3subscriber/client") +const Client = require("web3subscriber/src/client") const TokenInfo = require("../../build/contracts/Token.json") const Utils = require("../utils"); const Secrets = require('../../.secrets'); diff --git a/clients/token/mint-rio.js b/clients/token/mint-rio.js index c7a60e1..9ed638d 100644 --- a/clients/token/mint-rio.js +++ b/clients/token/mint-rio.js @@ -1,8 +1,8 @@ const Web3 = require("web3") const FileSys = require("fs") const Config = require("../config") -const Client = require("web3subscriber/client") -const PBinder= require("web3subscriber/pbinder") +const Client = require("web3subscriber/src/client") +const PBinder= require("web3subscriber/src/pbinder") const TokenInfo = require("../../build/contracts/Rio.json") const Secrets = require('../../.secrets'); diff --git a/clients/token/mint.js b/clients/token/mint.js index ba72cbd..e213209 100644 --- a/clients/token/mint.js +++ b/clients/token/mint.js @@ -1,8 +1,8 @@ const Web3 = require("web3") const FileSys = require("fs") const Config = require("../config") -const Client = require("web3subscriber/client") -const PBinder= require("web3subscriber/pbinder") +const Client = require("web3subscriber/src/client") +const PBinder= require("web3subscriber/src/pbinder") const TokenInfo = require("../../build/contracts/Token.json") const Secrets = require('../../.secrets'); diff --git a/clients/tx/nonce.js b/clients/tx/nonce.js index ec919ea..91bf7f8 100644 --- a/clients/tx/nonce.js +++ b/clients/tx/nonce.js @@ -1,8 +1,8 @@ const Web3 = require("web3") const FileSys = require("fs") const Config = require("../config") -const Client = require("web3subscriber/client") -const PBinder= require("web3subscriber/pbinder") +const Client = require("web3subscriber/src/client") +const PBinder= require("web3subscriber/src/pbinder") const TokenInfo = require("../../build/contracts/Token.json") const Secrets = require('../../.secrets'); const BridgeABI = require("../bridge/abi"); diff --git a/clients/tx/tx.js b/clients/tx/tx.js index bc5297a..f019374 100644 --- a/clients/tx/tx.js +++ b/clients/tx/tx.js @@ -1,8 +1,8 @@ const Web3 = require("web3") const FileSys = require("fs") const Config = require("../config") -const Client = require("web3subscriber/client") -const PBinder= require("web3subscriber/pbinder") +const Client = require("web3subscriber/src/client") +const PBinder= require("web3subscriber/src/pbinder") const TokenInfo = require("../../build/contracts/Token.json") const Secrets = require('../../.secrets'); From 7d290cb55dd747a65723ee6dba287b8f23cbd992 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 11 Nov 2021 16:31:26 +0800 Subject: [PATCH 02/21] refactor bridge with typescript Signed-off-by: Zhang Junyu --- .gitignore | 6 + clients/bridge/abi.js | 12 -- clients/bridge/bridge.js | 239 ----------------------------------- clients/bridge/bridge.ts | 263 +++++++++++++++++++++++++++++++++++++++ clients/config.js | 90 -------------- clients/config.ts | 129 +++++++++++++++++++ clients/types/bridge.ts | 12 ++ package.json | 4 +- tsconfig.json | 71 +++++++++++ 9 files changed, 484 insertions(+), 342 deletions(-) delete mode 100644 clients/bridge/abi.js delete mode 100644 clients/bridge/bridge.js create mode 100644 clients/bridge/bridge.ts delete mode 100644 clients/config.js create mode 100644 clients/config.ts create mode 100644 clients/types/bridge.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index 215b9bd..dcbb419 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,9 @@ /tools/data /tools/testnet1 /package-lock.json +clients/config.js +clients/config.js.map +clients/bridge/bridge.js +clients/bridge/bridge.js.map +clients/types/bridge.js +clients/types/bridge.js.map diff --git a/clients/bridge/abi.js b/clients/bridge/abi.js deleted file mode 100644 index 0d129c1..0000000 --- a/clients/bridge/abi.js +++ /dev/null @@ -1,12 +0,0 @@ -const Web3 = require("web3") -const BigNumber = Web3.utils.BN; -const BridgeInfo = require("../../build/contracts/Bridge.json"); -const Bridge = require("./bridge"); - -async function getBridge (config, client_mode) { - return Bridge.getBridgeClient(config, BridgeInfo, client_mode); -}; - -module.exports = { - getBridge: getBridge, -} diff --git a/clients/bridge/bridge.js b/clients/bridge/bridge.js deleted file mode 100644 index b23cbce..0000000 --- a/clients/bridge/bridge.js +++ /dev/null @@ -1,239 +0,0 @@ -const Web3 = require("web3"); -const BigNumber = Web3.utils.BN; -const Client = require("web3subscriber/src/client"); -const PBinder = require("web3subscriber/src/pbinder"); -const ERC20 = require("../../build/contracts/IERC20.json"); -const VERIFIER = require("../../build/contracts/Verifier.json"); - -const L1ADDR_BITS = 160; -const Tokens = require("./tokenlist"); - -function hexcmp(x, y) { - const xx = new BigNumber(x, "hex"); - const yy = new BigNumber(y, "hex"); - return xx.eq(yy); -} - -function encode_l1address(address_hexstr, chex) { - let c = new BigNumber( - chex + "0000000000000000000000000000000000000000", - "hex" - ); - let a = new BigNumber(address_hexstr, 16); - return c.add(a); -} - -/* chain_id:dec * address:hex - */ -function decode_l1address(l1address) { - let uid = new BigNumber(l1address); - let chain_id = uid.shrn(L1ADDR_BITS); - let address_hex = uid.sub(chain_id.shln(L1ADDR_BITS)).toString(16); - //address is 160 thus we need to padding '0' at the begining - let prefix = Array(40 - address_hex.length + 1).join("0"); - address_hex = prefix + address_hex; - let chain_hex = chain_id.toString(10); - return [chain_hex, address_hex]; -} - -function extract_chain_info(all_tokens) { - let valid_tokens = all_tokens.filter((t) => t.token_uid != "0"); - valid_tokens = valid_tokens.map((token) => { - let [cid, address] = decode_l1address(token.token_uid); - return { - chainId: cid, - name: - Tokens.tokenInfo.find( - (x) => - hexcmp(x.address, address) && - x.chainId == x.chainId && - x.chainId == cid - )?.name || "unknown", - index: all_tokens.findIndex((x) => x.token_uid == token.token_uid), - address: address, - }; - }); - let chain_list = Array.from(new Set(valid_tokens.map((x) => x.chainId))); - let token_list = chain_list.map((chain_id) => ({ - chainId: chain_id, - chainName: Tokens.chainInfo[chain_id], - tokens: valid_tokens.filter((x) => x.chainId == chain_id), - })); - return token_list; -} - -class Bridge { - constructor(web3, config, account, bridge_info, chain_hex, client_mode) { - this.web3 = web3; - this.config = config; - this.chain_hex_id = chain_hex; - this.client_mode = client_mode; - this.account = account; - this.chain_name = config.chain_name; - } - - async init(web3, config, account, bridge_info) { - await this.switch_net(); - this.bridge = Client.getContract(web3, config, bridge_info, account); - console.log(`init_bridge on %s`, this.chain_name); - const bi = await this.getBridgeInfo(); - const tokens = await this.allTokens(); - this.metadata = { - bridgeInfo: bi, - tokens: tokens, - chainInfo: extract_chain_info(tokens), - }; - } - - getTokenInfo(idx) { - const token = this.metadata.tokens[idx]; - let [cid, addr] = decode_l1address(token.token_uid); - return { - chainId: cid, - chainName: Tokens.chainInfo[cid], - tokenAddress: addr, - tokenName: - Tokens.tokenInfo.find( - (x) => hexcmp(x.address, addr) && x.chainId == cid - )?.name || "unknown", - }; - } - - /* address must start with 0x */ - encode_l1address(address) { - console.assert(address.substring(0, 2) == "0x"); - let address_hex = address.substring(2); - let chex = this.chain_hex_id.substring(2); - return encode_l1address(address_hex, chex); - } - - async switch_net() { - let id = await this.web3.eth.net.getId(); - let id_hex = "0x" + new BigNumber(id).toString(16); - console.log("switch chain", id_hex, this.chain_hex_id); - if (id_hex != this.chain_hex_id && this.client_mode == true) { - try { - await this.web3.currentProvider.request({ - method: "wallet_switchEthereumChain", - params: [{ chainId: this.chain_hex_id }], - }); - } catch (e) { - if (e.code == 4902) { - try { - await this.web3.currentProvider.request({ - method: "wallet_addEthereumChain", - params: [ - { - chainId: this.chain_hex_id, - chainName: this.chain_name, - rpcUrls: [this.config.rpc_source], - }, - ], - }); - await this.web3.currentProvider.request({ - method: "wallet_switchEthereumChain", - params: [{ chainId: this.chain_hex_id }], - }); - } catch (e) { - throw new Error("Add Network Rejected by User."); - } - } else { - throw new Error("Can not switch to chain " + this.chain_hex_id); - } - } - } - id = await this.web3.eth.net.getId(); - console.log("switched", id_hex, this.chain_hex_id); - return true; - } - - async getBridgeInfo() { - await this.switch_net(); - let vinfo = await this.bridge.methods.getBridgeInfo().call(); - return vinfo; - } - - async allTokens() { - await this.switch_net(); - let vinfo = await this.bridge.methods.allTokens().call(); - return vinfo; - } - - async addToken(tokenid) { - await this.switch_net(); - let tx = await this.bridge.methods.addToken(tokenid).send(); - return tx; - } - - getMetaData() { - return this.metadata; - } - - verify(l2account, calldata, verifydata, vid, nonce, rid) { - let pbinder = new PBinder.PromiseBinder(); - let r = pbinder.return(async () => { - await this.switch_net(); - let rx = await pbinder.bind( - "Verify", - this.bridge.methods - .verify(l2account, calldata, verifydata, vid, nonce, rid) - .send() - ); - return rx; - }); - console.log(r); - return r; - } - - deposit(token_address, amount, l2account) { - let pbinder = new PBinder.PromiseBinder(); - let r = pbinder.return(async () => { - let c = await this.switch_net(); - let token = Client.getContractByAddress( - this.web3, - token_address, - ERC20, - this.account - ); - pbinder.snapshot("Approve"); - var rx = await pbinder.bind( - "Approve", - token.methods.approve(this.bridge.options.address, amount).send() - ); - pbinder.snapshot("Deposit"); - rx = await pbinder.bind( - "Deposit", - this.bridge.methods.deposit(token_address, amount, l2account).send() - ); - return rx; - }); - return r; - } - - async close() { - await this.web3.currentProvider.engine.stop(); - } -} - -async function getBridgeClient(config, bridge_info, client_mode) { - let web3 = await Client.initWeb3(config, client_mode); - let chain_id = config.device_id; - let chain_hex = "0x" + new BigNumber(chain_id).toString(16); - let account = await Client.getDefaultAccount(web3, config); - bridge = new Bridge( - web3, - config, - account, - bridge_info, - chain_hex, - client_mode - ); - await bridge.init(web3, config, account, bridge_info); - return bridge; -} - -module.exports = { - getBridgeClient: getBridgeClient, - encodeL1Address: encode_l1address, - decodeL1Address: decode_l1address, -}; diff --git a/clients/bridge/bridge.ts b/clients/bridge/bridge.ts new file mode 100644 index 0000000..987eb48 --- /dev/null +++ b/clients/bridge/bridge.ts @@ -0,0 +1,263 @@ +import BN from "bn.js"; +import { + DelphinusContract, + DelphinusWeb3, + Web3BrowsersMode, + Web3ProviderMode, +} from "web3subscriber/src/client"; +import { PromiseBinder } from "web3subscriber/src/pbinder"; +import { ChainConfig } from "../config"; +import { BridgeInfo, TokenInfo } from "../types/bridge"; + +const ERC20 = require("../../build/contracts/IERC20.json"); +const VERIFIER = require("../../build/contracts/Verifier.json"); +const BridgeContract = require("../../build/contracts/Bridge.json"); + +const L1ADDR_BITS = 160; +const Tokens = require("./tokenlist"); + +function hexcmp(x: string, y: string) { + const xx = new BN(x, "hex"); + const yy = new BN(y, "hex"); + return xx.eq(yy); +} + +export function encodeL1address(address_hexstr: string, chex: string) { + let c = new BN(chex + "0000000000000000000000000000000000000000", "hex"); + let a = new BN(address_hexstr, 16); + return c.add(a); +} + +/* chain_id:dec * address:hex + */ +function decodeL1address(l1address: string) { + let uid = new BN(l1address); + let chain_id = uid.shrn(L1ADDR_BITS); + let address_hex = uid.sub(chain_id.shln(L1ADDR_BITS)).toString(16); + //address is 160 thus we need to padding '0' at the begining + let prefix = Array(40 - address_hex.length + 1).join("0"); + address_hex = prefix + address_hex; + let chain_hex = chain_id.toString(10); + return [chain_hex, address_hex]; +} + +export class Bridge { + readonly web3: DelphinusWeb3; + private readonly config: ChainConfig; + private readonly bridgeInfo: any; + private bridgeContract?: DelphinusContract; + + constructor(config: ChainConfig, clientMode: boolean) { + if (clientMode) { + this.web3 = new Web3BrowsersMode(); + } else { + this.web3 = new Web3ProviderMode({ + provider: config.provider(), + closeProvider: config.close_provider, + monitorAccount: config.monitor_account, + }); + } + + this.config = config; + this.bridgeInfo = BridgeContract; + } + + getChainIdHex() { + return "0x" + new BN(this.config.device_id).toString(16); + } + + async init() { + const bridgeAddress = + this.bridgeInfo.networks[this.config.device_id].address; + + console.log(`init_bridge on %s`, this.config.chain_name); + + await this.web3.connect(); + await this.switchNet(); + + this.bridgeContract = await this.web3.getContract( + this.bridgeInfo, + bridgeAddress, + this.web3.getDefaultAccount() + ); + } + + private async switchNet() { + await this.web3.switchNet( + this.getChainIdHex(), + this.config.chain_name, + this.config.rpc_source + ); + } + + private async extractChainInfo() { + let tokenInfos = await this.allTokens(); + let tokens = tokenInfos.filter( + (t) => t.token_uid != "0" + ).map((token) => { + let [cid, address] = decodeL1address(token.token_uid); + return { + address: address, + name: + Tokens.tokenInfo.find( + (x: any) => hexcmp(x.address, address) && x.chainId == cid + )?.name || "unknown", + chainId: cid, + index: tokenInfos.findIndex( + (x: TokenInfo) => x.token_uid == token.token_uid + ), + }; + }); + let chain_list = Array.from(new Set(tokens.map((x) => x.chainId))); + let token_list = chain_list.map((chain_id) => ({ + chainId: chain_id, + chainName: Tokens.chainInfo[chain_id], + tokens: tokens.filter((x) => x.chainId == chain_id), + enable: true, + })); + return token_list; + } + + async getTokenInfo(idx: number) { + const token = (await this.allTokens())[idx]; + let [cid, addr] = decodeL1address(token.token_uid); + return { + chainId: cid, + chainName: Tokens.chainInfo[cid], + tokenAddress: addr, + tokenName: + Tokens.tokenInfo.find( + (x: any) => hexcmp(x.address, addr) && x.chainId == cid + )?.name || "unknown", + index: idx, + }; + } + + /** + * + * @param address address must start with 0x + * @returns + */ + encodeL1address(address: string) { + if (address.substring(0, 2) != "0x") { + throw "address must start with 0x"; + } + + const addressHex = address.substring(2); + const chex = this.getChainIdHex().substring(2); + return encodeL1address(addressHex, chex); + } + + async getMetaData() { + return { + bridgeInfo: await this.getBridgeInfo(), + tokens: await this.allTokens(), + chainInfo: await this.extractChainInfo(), + }; + } + + private async getBridgeContract() { + if (this.bridgeContract === undefined) { + throw "Bridge not initialized."; + } + + await this.switchNet(); + return this.bridgeContract; + } + + async getBridgeInfo(): Promise { + const contract = await this.getBridgeContract(); + + return await contract.getContractInstance().methods.getBridgeInfo().call(); + } + + async allTokens(): Promise { + const contract = await this.getBridgeContract(); + + return await contract.getContractInstance().methods.allTokens().call(); + } + + async addToken(tokenid: BN) { + const contract = await this.getBridgeContract(); + + return await contract + .getContractInstance() + .methods.addToken(tokenid) + .send(); + } + + verify( + l2account: string, + calldata: BN[], + verifydata: BN[], + vid: number, + nonce: number, + rid: BN + ) { + const pbinder = new PromiseBinder(); + + return pbinder.return(async () => { + const contract = await this.getBridgeContract(); + + return await pbinder.bind( + "Verify", + contract + .getContractInstance() + .methods.verify(l2account, calldata, verifydata, vid, nonce, rid) + .send() + ); + }); + } + + deposit(tokenAddress: string, amount: number, l2account: string) { + const pbinder = new PromiseBinder(); + + return pbinder.return(async () => { + const contract = await this.getBridgeContract(); + + const token = this.web3.getContract( + ERC20, + tokenAddress, + this.web3.getDefaultAccount() + ); + + pbinder.snapshot("Approve"); + await pbinder.bind( + "Approve", + token + .getContractInstance() + .methods.approve( + contract.getContractInstance().options.address, + amount + ) + .send() + ); + pbinder.snapshot("Deposit"); + return await pbinder.bind( + "Deposit", + contract + .getContractInstance() + .methods.deposit(tokenAddress, amount, l2account) + .send() + ); + }); + } + + async close() { + await this.web3.close(); + } +} + +export async function withBridgeClient( + config: ChainConfig, + clientMode: boolean, + cb: (_: Bridge) => Promise +) { + const bridge = new Bridge(config, clientMode); + await bridge.init(); + try { + return await cb(bridge); + } finally { + bridge.close(); + } +} diff --git a/clients/config.js b/clients/config.js deleted file mode 100644 index c723660..0000000 --- a/clients/config.js +++ /dev/null @@ -1,90 +0,0 @@ -const HDWalletProvider = require('@truffle/hdwallet-provider'); - -const Web3WsProvider = require('web3-providers-ws'); -const Web3HttpProvider = require('web3-providers-http'); - -const ws_options = { - timeout: 30000, // ms - - clientConfig: { - // Useful if requests are large - maxReceivedFrameSize: 100000000, // bytes - default: 1MiB - maxReceivedMessageSize: 100000000, // bytes - default: 8MiB - - // Useful to keep a connection alive - keepalive: true, - keepaliveInterval: 60000 // ms - }, - - // Enable auto reconnection - reconnect: { - auto: true, - delay: 5000, // ms - maxAttempts: 5, - onTimeout: true - } -}; - -const http_options = { - keepAlive: false, - timeout: 20000, // milliseconds, - withCredentials: false -}; - - -const ws_provider = (url) => { - let p = new Web3WsProvider(url, ws_options); - return p; -} - -const http_provider = (url) => { - let p = new Web3HttpProvider(url, http_options); - return p; -} - -module.exports = { - localtestnet1: () => {return { - provider: () => "ws://127.0.0.1:8546", - mongodb_url: "mongodb://localhost:27017", - ws_source: "ws://127.0.0.1:8546", - rpc_source: "ws://127.0.0.1:8545", - device_id: "15", - monitor_account: "0x6f6ef6dfe681b6593ddf27da3bfde22083aef88b", - chain_name: "localtestnet1", - }}, - localtestnet2: () => {return { - provider: () => "ws://127.0.0.1:8746", - mongodb_url: "mongodb://localhost:27017", - rpc_source: "http://127.0.0.1:8745", - ws_source: "ws://127.0.0.1:8746", - monitor_account: "0x6f6ef6dfe681b6593ddf27da3bfde22083aef88b", - device_id: "16", - chain_name: "localtestnet2", - }}, - bsctestnet: (secrets) => {return { - provider: () => new HDWalletProvider({ - privateKeys: [secrets.accounts.deployer.priv], - providerOrUrl: http_provider("https://bsc.getblock.io/testnet/?api_key="+secrets.getblock_key), - shareNonce: false - }), - mongodb_url: "mongodb://localhost:27017", - rpc_source: "https://bsc.getblock.io/testnet/?api_key=" + secrets.getblock_key, - ws_source: "wss://bsc.getblock.io/testnet/?api_key=" + secrets.getblock_key, - monitor_account: "0x6f6ef6dfe681b6593ddf27da3bfde22083aef88b", - device_id: "97", - chain_name: "bsctestnet", - }}, - ropsten: (secrets) => {return { - provider: () => new HDWalletProvider({ - privateKeys: [secrets.accounts.deployer.priv], - providerOrUrl: http_provider("https://ropsten.infura.io/v3/" + secrets.infura_id), - shareNonce: false - }), - mongodb_url: "mongodb://localhost:27017", - rpc_source: "https://ropsten.infura.io/v3/" + secrets.infura_id, - ws_source: "wss://ropsten.infura.io/ws/v3/" + secrets.infura_id, - monitor_account: "0x6f6ef6dfe681b6593ddf27da3bfde22083aef88b", - device_id: "3", - chain_name: "ropsten", - }} -} diff --git a/clients/config.ts b/clients/config.ts new file mode 100644 index 0000000..0a98e1d --- /dev/null +++ b/clients/config.ts @@ -0,0 +1,129 @@ +import { provider } from "web3-core"; + +const HDWalletProvider = require("@truffle/hdwallet-provider"); +const Web3WsProvider = require("web3-providers-ws"); +const Web3HttpProvider = require("web3-providers-http"); + +const ws_options = { + timeout: 30000, // ms + + clientConfig: { + // Useful if requests are large + maxReceivedFrameSize: 100000000, // bytes - default: 1MiB + maxReceivedMessageSize: 100000000, // bytes - default: 8MiB + + // Useful to keep a connection alive + keepalive: true, + keepaliveInterval: 60000, // ms + }, + + // Enable auto reconnection + reconnect: { + auto: true, + delay: 5000, // ms + maxAttempts: 5, + onTimeout: true, + }, +}; + +const http_options = { + keepAlive: false, + timeout: 20000, // milliseconds, + withCredentials: false, +}; + +const ws_provider = (url: string) => { + let p = new Web3WsProvider(url, ws_options); + return p; +}; + +const http_provider = (url: string) => { + let p = new Web3HttpProvider(url, http_options); + return p; +}; + +export interface ChainConfig { + provider: (_: void) => any; + close_provider: (provider: provider) => Promise; + mongodb_url: string; + ws_source: string; + rpc_source: string; + device_id: string; + monitor_account: string; + chain_name: string; +} + +export const EthConfig: Record ChainConfig> = { + localtestnet1: () => { + return { + provider: () => "ws://127.0.0.1:8546", + close_provider: async (provider: any) => { + await provider.connection.close(); + }, + mongodb_url: "mongodb://localhost:27017", + ws_source: "ws://127.0.0.1:8546", + rpc_source: "ws://127.0.0.1:8545", + device_id: "15", + monitor_account: "0x6f6ef6dfe681b6593ddf27da3bfde22083aef88b", + chain_name: "localtestnet1", + }; + }, + localtestnet2: () => { + return { + provider: () => "ws://127.0.0.1:8746", + close_provider: async (provider: any) => { + await provider.connection.close(); + }, + mongodb_url: "mongodb://localhost:27017", + rpc_source: "http://127.0.0.1:8745", + ws_source: "ws://127.0.0.1:8746", + monitor_account: "0x6f6ef6dfe681b6593ddf27da3bfde22083aef88b", + device_id: "16", + chain_name: "localtestnet2", + }; + }, + bsctestnet: (secrets: any) => { + return { + provider: () => + new HDWalletProvider({ + privateKeys: [secrets.accounts.deployer.priv], + providerOrUrl: http_provider( + "https://bsc.getblock.io/testnet/?api_key=" + secrets.getblock_key + ), + shareNonce: false, + }), + close_provider: async (provider: any) => { + await provider.engine.stop(); + }, + mongodb_url: "mongodb://localhost:27017", + rpc_source: + "https://bsc.getblock.io/testnet/?api_key=" + secrets.getblock_key, + ws_source: + "wss://bsc.getblock.io/testnet/?api_key=" + secrets.getblock_key, + monitor_account: "0x6f6ef6dfe681b6593ddf27da3bfde22083aef88b", + device_id: "97", + chain_name: "bsctestnet", + }; + }, + ropsten: (secrets: any) => { + return { + provider: () => + new HDWalletProvider({ + privateKeys: [secrets.accounts.deployer.priv], + providerOrUrl: http_provider( + "https://ropsten.infura.io/v3/" + secrets.infura_id + ), + shareNonce: false, + }), + close_provider: async (provider: any) => { + await provider.engine.stop(); + }, + mongodb_url: "mongodb://localhost:27017", + rpc_source: "https://ropsten.infura.io/v3/" + secrets.infura_id, + ws_source: "wss://ropsten.infura.io/ws/v3/" + secrets.infura_id, + monitor_account: "0x6f6ef6dfe681b6593ddf27da3bfde22083aef88b", + device_id: "3", + chain_name: "ropsten", + }; + }, +}; diff --git a/clients/types/bridge.ts b/clients/types/bridge.ts new file mode 100644 index 0000000..29bf23d --- /dev/null +++ b/clients/types/bridge.ts @@ -0,0 +1,12 @@ +export interface BridgeInfo { + chain_id: string; + amount_token: string; + amount_pool: string; + owner: string; + merkle_root: string; + rid: string; + } + + export interface TokenInfo { + token_uid: string; + } \ No newline at end of file diff --git a/package.json b/package.json index 8373deb..eeddef7 100644 --- a/package.json +++ b/package.json @@ -17,10 +17,12 @@ "scripts": { "dev": "npx truffle dev", "migrate1": "cp ./truffle-config1.js ./truffle-config.js && npx truffle migrate", - "migrate2": "cp ./truffle-config2.js ./truffle-config.js && npx truffle migrate" + "migrate2": "cp ./truffle-config2.js ./truffle-config.js && npx truffle migrate", + "prepare": "npx tsc" }, "devDependencies": { "@webpack-cli/serve": "^1.3.1", + "typescript": "^4.4.4", "webpack-cli": "^4.6.0" } } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..120a2a7 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,71 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "ES2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "rootDir": ".", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + + /* Advanced Options */ + "skipLibCheck": true, /* Skip type checking of declaration files. */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + } +} From 82215977cf3143c93e13bcc8a05d91e9eae6f659 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 11 Nov 2021 17:47:14 +0800 Subject: [PATCH 03/21] export events' type of contract --- .gitignore | 4 ++-- clients/types/events.ts | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 clients/types/events.ts diff --git a/.gitignore b/.gitignore index dcbb419..4c711ce 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,5 @@ clients/config.js clients/config.js.map clients/bridge/bridge.js clients/bridge/bridge.js.map -clients/types/bridge.js -clients/types/bridge.js.map +clients/types/*.js +clients/types/*.js.map diff --git a/clients/types/events.ts b/clients/types/events.ts new file mode 100644 index 0000000..ffdb178 --- /dev/null +++ b/clients/types/events.ts @@ -0,0 +1,18 @@ +export interface Deposit { + l1token: string; + l2account: string; + amount: string; + nonce: string; + } + + export interface SwapAck { + l2account: string; + rid: string; + } + + export interface WithDraw { + l1account: string; + l2account: string; + amount: string; + nonce: string; + } From 5306a182bbd4b307ab2ec6583a202f0f3dcc877a Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 11 Nov 2021 22:04:08 +0800 Subject: [PATCH 04/21] rewrite init.js with typescript --- .gitignore | 2 ++ clients/bridge/init.js | 66 ------------------------------------------ clients/bridge/init.ts | 60 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 66 deletions(-) delete mode 100644 clients/bridge/init.js create mode 100644 clients/bridge/init.ts diff --git a/.gitignore b/.gitignore index 4c711ce..74265e2 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,7 @@ clients/config.js clients/config.js.map clients/bridge/bridge.js clients/bridge/bridge.js.map +clients/bridge/init.js +clients/bridge/init.js.map clients/types/*.js clients/types/*.js.map diff --git a/clients/bridge/init.js b/clients/bridge/init.js deleted file mode 100644 index 9e4e236..0000000 --- a/clients/bridge/init.js +++ /dev/null @@ -1,66 +0,0 @@ -const Web3 = require("web3"); -const Client = require("web3subscriber/src/client"); -const Config = require('../config'); -const TokenInfo = require("../../build/contracts/Token.json"); -const BridgeABI = require("./abi"); -const BridgeHelper = require("./bridge"); -const Secrets = require('../../.secrets'); -const fs = require("fs"); -const path = require("path"); - -const Tokens = require("./tokenlist"); - -function crunch_tokens() { - return Tokens.tokenInfo - .filter((x) => x.address) - .map((x) => - BridgeHelper.encodeL1Address(x.address, parseInt(x.chainId).toString(16)) - ); -} - -const test_config = { - l2account: - "0x7a50c8fa50a39bd48dfd8053ebff44ba3da45dd8c3e90a5fec9fd73a4595251b", -}; - -async function test_main(config_name) { - console.log("start calling"); - config = Config[config_name](Secrets); - try { - let bridge = await BridgeABI.getBridge(config, false); - let token = Client.getContract( - bridge.web3, - bridge.config, - TokenInfo, - bridge.account - ); - - let output = {}; - let index = 4; - - console.log("Testing bridge [id=%s]", bridge.chain_hex_id); - for (token_uid of crunch_tokens()) { - console.log("Adding token uid: 0x", token_uid.toString(16)); - let tx = await bridge.addToken(token_uid); - console.log(tx); - - output[token_uid] = index++; - } - - fs.writeFileSync( - path.resolve(__dirname, "..", "token-index.json"), - JSON.stringify(output, undefined, 2) - ); - - let info = await bridge.getBridgeInfo(); - console.log("bridge info is", info); - let tokens = await bridge.allTokens(); - console.log("token list is", tokens); - } catch (err) { - console.log("%s", err); - } -} - -test_main(process.argv[2]).then((v) => { - process.exit(); -}); diff --git a/clients/bridge/init.ts b/clients/bridge/init.ts new file mode 100644 index 0000000..d5fdf8d --- /dev/null +++ b/clients/bridge/init.ts @@ -0,0 +1,60 @@ +import { EthConfig } from "../config"; +import { Bridge, withBridgeClient } from "./bridge"; +import { encodeL1address } from "web3subscriber/src/addresses"; + +const Tokens = require("./tokenlist"); +const TokenInfo = require("../../build/contracts/Token.json"); +const Secrets = require("../../.secrets"); +const fs = require("fs"); +const path = require("path"); + +function crunchTokens() { + return Tokens.tokenInfo + .filter((x: any) => x.address) + .map((x: any) => + encodeL1address(x.address, parseInt(x.chainId).toString(16)) + ); +} + +async function main(config_name: string) { + console.log("start calling"); + let config = EthConfig[config_name](Secrets); + let address = TokenInfo.networks[config.device_id].address; + try { + withBridgeClient(config, false, async (bridge: Bridge) => { + /* + let token = bridge.web3.getContract( + TokenInfo, + address, + bridge.web3.getDefaultAccount() + ); + */ + + let output: any = {}; + let index = 4; + + console.log("Testing bridge [id=%s]", bridge.getChainIdHex()); + for (let tokenUid of crunchTokens()) { + console.log("Adding token uid: 0x", tokenUid.toString(16)); + let tx = await bridge.addToken(tokenUid); + console.log(tx); + + output[tokenUid] = index++; + } + + fs.writeFileSync( + path.resolve(__dirname, "..", "token-index.json"), + JSON.stringify(output, undefined, 2) + ); + + let info = await bridge.getBridgeInfo(); + console.log("bridge info is", info); + let tokens = await bridge.allTokens(); + console.log("token list is", tokens); + }); + } catch (err) { + console.log("%s", err); + } +} + +main(process.argv[2]); From 4cf4c211d4e3fa87f141f67960c88d622eccbc91 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Fri, 12 Nov 2021 17:18:05 +0800 Subject: [PATCH 05/21] rewrite mint with typescript --- .gitignore | 2 ++ clients/token/mint.ts | 46 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 clients/token/mint.ts diff --git a/.gitignore b/.gitignore index 74265e2..2da5697 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ clients/bridge/init.js clients/bridge/init.js.map clients/types/*.js clients/types/*.js.map +clients/token/mint.js +clients/token/mint.js.map diff --git a/clients/token/mint.ts b/clients/token/mint.ts new file mode 100644 index 0000000..5312f52 --- /dev/null +++ b/clients/token/mint.ts @@ -0,0 +1,46 @@ +import { Bridge, withBridgeClient } from "../bridge/bridge"; +import { EthConfig } from "../config"; + +const Config = require("../config"); +const PBinder = require("web3subscriber/src/pbinder"); +const TokenInfo = require("../../build/contracts/Token.json"); +const Secrets = require("../../.secrets"); + +function main(configName: string, targetAccount: string) { + let config = EthConfig[configName](Secrets); + let account = config.monitor_account; + let address = TokenInfo.networks[config.device_id].address; + let pbinder = new PBinder.PromiseBinder(); + let r = pbinder.return(async () => { + withBridgeClient(config, false, async (bridge: Bridge) => { + let token = bridge.web3.getContract(TokenInfo, address, account); + // await web3.eth.net.getId(); + try { + console.log("mint token:", token.getContractInstance().options.address); + let balance = await token.getBalance(account); + console.log("sender: balance before mint:", balance); + await pbinder.bind("mint", token.getContractInstance().methods.mint(0x10000000).send()); + balance = await token.getBalance(account); + console.log("sender: balance after mint", balance); + if (targetAccount) { + await pbinder.bind( + "transfer", + token.getContractInstance().methods.transfer(targetAccount, 0x10000000).send() + ); + balance = await token.getBalance(targetAccount); + console.log("balance of recipient after transfer", balance); + } + } catch (err) { + console.log("%s", err); + } + }); + }); + return r; +} + +/* .once("transactionHash",hash => console.log(hash) */ +main(process.argv[2], process.argv[3]).when( + "mint", + "transactionHash", + (hash: string) => console.log(hash) +); From f1836d9439b72474e08438fb9d251c8e1810c8ed Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Fri, 12 Nov 2021 17:18:42 +0800 Subject: [PATCH 06/21] remove mint.js --- clients/token/mint.js | 37 ------------------------------------- 1 file changed, 37 deletions(-) delete mode 100644 clients/token/mint.js diff --git a/clients/token/mint.js b/clients/token/mint.js deleted file mode 100644 index e213209..0000000 --- a/clients/token/mint.js +++ /dev/null @@ -1,37 +0,0 @@ -const Web3 = require("web3") -const FileSys = require("fs") -const Config = require("../config") -const Client = require("web3subscriber/src/client") -const PBinder= require("web3subscriber/src/pbinder") -const TokenInfo = require("../../build/contracts/Token.json") -const Secrets = require('../../.secrets'); - -function test_mint(config_name, target_account) { - let pbinder = new PBinder.PromiseBinder(); - let r = pbinder.return (async () => { - config = Config[config_name](Secrets); - let account = config.monitor_account; - let web3 = await Client.initWeb3(config, false); - let token = Client.getContract(web3, config, TokenInfo, account); - await web3.eth.net.getId(); - try { - console.log("mint token:", token.options.address); - var balance = await token.methods.balanceOf(account).call(); - console.log("sender: balance before mint:", balance); - await pbinder.bind("mint", token.methods.mint(0x10000000).send()); - balance = await Client.getBalance(token, account); - console.log("sender: balance after mint", balance); - if (target_account) { - await pbinder.bind("transfer", token.methods.transfer(target_account, 0x10000000).send()); - balance = await Client.getBalance(token, target_account); - console.log("balance of recipient after transfer", balance); - } - } catch (err) { - console.log("%s", err); - } - }); - return r; -} - -/* .once("transactionHash",hash => console.log(hash) */ -test_mint(process.argv[2], process.argv[3]).when("mint","transactionHash", hash=>console.log(hash)).then(v => {console.log("test done!"); process.exit();}); From f04ef68c0d14c2b6215a44aa18c79642cf664be5 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Sat, 13 Nov 2021 18:04:24 +0800 Subject: [PATCH 07/21] refactor l1 client --- .gitignore | 5 + clients/bridge/bridge.ts | 263 ------------------ clients/client.ts | 103 +++++++ clients/contracts/bridge.ts | 187 +++++++++++++ clients/contracts/token.ts | 33 +++ .../tokenlist.js => contracts/tokenlist.ts} | 9 +- clients/{ => tools}/bridge/deposit.js | 0 clients/{ => tools}/bridge/init.ts | 19 +- clients/{ => tools}/bridge/status.js | 0 clients/{ => tools}/token/allowance.js | 0 clients/{ => tools}/token/balance.js | 0 clients/{ => tools}/token/mint-rio.js | 0 clients/{ => tools}/token/mint.ts | 23 +- clients/types/bridge.ts | 12 - clients/types/events.ts | 18 -- 15 files changed, 345 insertions(+), 327 deletions(-) delete mode 100644 clients/bridge/bridge.ts create mode 100644 clients/client.ts create mode 100644 clients/contracts/bridge.ts create mode 100644 clients/contracts/token.ts rename clients/{bridge/tokenlist.js => contracts/tokenlist.ts} (91%) rename clients/{ => tools}/bridge/deposit.js (100%) rename clients/{ => tools}/bridge/init.ts (70%) rename clients/{ => tools}/bridge/status.js (100%) rename clients/{ => tools}/token/allowance.js (100%) rename clients/{ => tools}/token/balance.js (100%) rename clients/{ => tools}/token/mint-rio.js (100%) rename clients/{ => tools}/token/mint.ts (53%) delete mode 100644 clients/types/bridge.ts delete mode 100644 clients/types/events.ts diff --git a/.gitignore b/.gitignore index 2da5697..d75603d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,8 @@ /package-lock.json clients/config.js clients/config.js.map +clients/client.js +clients/client.js.map clients/bridge/bridge.js clients/bridge/bridge.js.map clients/bridge/init.js @@ -13,3 +15,6 @@ clients/types/*.js clients/types/*.js.map clients/token/mint.js clients/token/mint.js.map +clients/contracts/*.js +clients/contracts/*.js.map + diff --git a/clients/bridge/bridge.ts b/clients/bridge/bridge.ts deleted file mode 100644 index 987eb48..0000000 --- a/clients/bridge/bridge.ts +++ /dev/null @@ -1,263 +0,0 @@ -import BN from "bn.js"; -import { - DelphinusContract, - DelphinusWeb3, - Web3BrowsersMode, - Web3ProviderMode, -} from "web3subscriber/src/client"; -import { PromiseBinder } from "web3subscriber/src/pbinder"; -import { ChainConfig } from "../config"; -import { BridgeInfo, TokenInfo } from "../types/bridge"; - -const ERC20 = require("../../build/contracts/IERC20.json"); -const VERIFIER = require("../../build/contracts/Verifier.json"); -const BridgeContract = require("../../build/contracts/Bridge.json"); - -const L1ADDR_BITS = 160; -const Tokens = require("./tokenlist"); - -function hexcmp(x: string, y: string) { - const xx = new BN(x, "hex"); - const yy = new BN(y, "hex"); - return xx.eq(yy); -} - -export function encodeL1address(address_hexstr: string, chex: string) { - let c = new BN(chex + "0000000000000000000000000000000000000000", "hex"); - let a = new BN(address_hexstr, 16); - return c.add(a); -} - -/* chain_id:dec * address:hex - */ -function decodeL1address(l1address: string) { - let uid = new BN(l1address); - let chain_id = uid.shrn(L1ADDR_BITS); - let address_hex = uid.sub(chain_id.shln(L1ADDR_BITS)).toString(16); - //address is 160 thus we need to padding '0' at the begining - let prefix = Array(40 - address_hex.length + 1).join("0"); - address_hex = prefix + address_hex; - let chain_hex = chain_id.toString(10); - return [chain_hex, address_hex]; -} - -export class Bridge { - readonly web3: DelphinusWeb3; - private readonly config: ChainConfig; - private readonly bridgeInfo: any; - private bridgeContract?: DelphinusContract; - - constructor(config: ChainConfig, clientMode: boolean) { - if (clientMode) { - this.web3 = new Web3BrowsersMode(); - } else { - this.web3 = new Web3ProviderMode({ - provider: config.provider(), - closeProvider: config.close_provider, - monitorAccount: config.monitor_account, - }); - } - - this.config = config; - this.bridgeInfo = BridgeContract; - } - - getChainIdHex() { - return "0x" + new BN(this.config.device_id).toString(16); - } - - async init() { - const bridgeAddress = - this.bridgeInfo.networks[this.config.device_id].address; - - console.log(`init_bridge on %s`, this.config.chain_name); - - await this.web3.connect(); - await this.switchNet(); - - this.bridgeContract = await this.web3.getContract( - this.bridgeInfo, - bridgeAddress, - this.web3.getDefaultAccount() - ); - } - - private async switchNet() { - await this.web3.switchNet( - this.getChainIdHex(), - this.config.chain_name, - this.config.rpc_source - ); - } - - private async extractChainInfo() { - let tokenInfos = await this.allTokens(); - let tokens = tokenInfos.filter( - (t) => t.token_uid != "0" - ).map((token) => { - let [cid, address] = decodeL1address(token.token_uid); - return { - address: address, - name: - Tokens.tokenInfo.find( - (x: any) => hexcmp(x.address, address) && x.chainId == cid - )?.name || "unknown", - chainId: cid, - index: tokenInfos.findIndex( - (x: TokenInfo) => x.token_uid == token.token_uid - ), - }; - }); - let chain_list = Array.from(new Set(tokens.map((x) => x.chainId))); - let token_list = chain_list.map((chain_id) => ({ - chainId: chain_id, - chainName: Tokens.chainInfo[chain_id], - tokens: tokens.filter((x) => x.chainId == chain_id), - enable: true, - })); - return token_list; - } - - async getTokenInfo(idx: number) { - const token = (await this.allTokens())[idx]; - let [cid, addr] = decodeL1address(token.token_uid); - return { - chainId: cid, - chainName: Tokens.chainInfo[cid], - tokenAddress: addr, - tokenName: - Tokens.tokenInfo.find( - (x: any) => hexcmp(x.address, addr) && x.chainId == cid - )?.name || "unknown", - index: idx, - }; - } - - /** - * - * @param address address must start with 0x - * @returns - */ - encodeL1address(address: string) { - if (address.substring(0, 2) != "0x") { - throw "address must start with 0x"; - } - - const addressHex = address.substring(2); - const chex = this.getChainIdHex().substring(2); - return encodeL1address(addressHex, chex); - } - - async getMetaData() { - return { - bridgeInfo: await this.getBridgeInfo(), - tokens: await this.allTokens(), - chainInfo: await this.extractChainInfo(), - }; - } - - private async getBridgeContract() { - if (this.bridgeContract === undefined) { - throw "Bridge not initialized."; - } - - await this.switchNet(); - return this.bridgeContract; - } - - async getBridgeInfo(): Promise { - const contract = await this.getBridgeContract(); - - return await contract.getContractInstance().methods.getBridgeInfo().call(); - } - - async allTokens(): Promise { - const contract = await this.getBridgeContract(); - - return await contract.getContractInstance().methods.allTokens().call(); - } - - async addToken(tokenid: BN) { - const contract = await this.getBridgeContract(); - - return await contract - .getContractInstance() - .methods.addToken(tokenid) - .send(); - } - - verify( - l2account: string, - calldata: BN[], - verifydata: BN[], - vid: number, - nonce: number, - rid: BN - ) { - const pbinder = new PromiseBinder(); - - return pbinder.return(async () => { - const contract = await this.getBridgeContract(); - - return await pbinder.bind( - "Verify", - contract - .getContractInstance() - .methods.verify(l2account, calldata, verifydata, vid, nonce, rid) - .send() - ); - }); - } - - deposit(tokenAddress: string, amount: number, l2account: string) { - const pbinder = new PromiseBinder(); - - return pbinder.return(async () => { - const contract = await this.getBridgeContract(); - - const token = this.web3.getContract( - ERC20, - tokenAddress, - this.web3.getDefaultAccount() - ); - - pbinder.snapshot("Approve"); - await pbinder.bind( - "Approve", - token - .getContractInstance() - .methods.approve( - contract.getContractInstance().options.address, - amount - ) - .send() - ); - pbinder.snapshot("Deposit"); - return await pbinder.bind( - "Deposit", - contract - .getContractInstance() - .methods.deposit(tokenAddress, amount, l2account) - .send() - ); - }); - } - - async close() { - await this.web3.close(); - } -} - -export async function withBridgeClient( - config: ChainConfig, - clientMode: boolean, - cb: (_: Bridge) => Promise -) { - const bridge = new Bridge(config, clientMode); - await bridge.init(); - try { - return await cb(bridge); - } finally { - bridge.close(); - } -} diff --git a/clients/client.ts b/clients/client.ts new file mode 100644 index 0000000..ebc100c --- /dev/null +++ b/clients/client.ts @@ -0,0 +1,103 @@ +import BN from "bn.js"; +import { + DelphinusWeb3, + Web3BrowsersMode, + Web3ProviderMode, +} from "web3subscriber/src/client"; +import { encodeL1address } from "web3subscriber/src/addresses"; +import { ChainConfig } from "./config"; +import { BridgeContract } from "./contracts/bridge"; +import { TokenContract } from "./contracts/token"; + +const L1ADDR_BITS = 160; + +export class L1Client { + readonly web3: DelphinusWeb3; + private readonly config: ChainConfig; + + constructor(config: ChainConfig, clientMode: boolean) { + if (clientMode) { + this.web3 = new Web3BrowsersMode(); + } else { + this.web3 = new Web3ProviderMode({ + provider: config.provider(), + closeProvider: config.close_provider, + monitorAccount: config.monitor_account, + }); + } + + this.config = config; + } + + async init() { + console.log(`init_bridge on %s`, this.config.chain_name); + + await this.web3.connect(); + await this.switchNet(); + } + + async close() { + await this.web3.close(); + } + + getChainIdHex() { + return "0x" + new BN(this.config.device_id).toString(16); + } + + getDefaultAccount() { + return this.web3.getDefaultAccount(); + } + + getBridgeContract(account?: string) { + return new BridgeContract( + this.web3, + BridgeContract.getContractAddress(this.config.device_id), + account + ); + } + + getTokenContract(address?: string, account?: string) { + return new TokenContract( + this.web3, + address || BridgeContract.getContractAddress(this.config.device_id), + account + ); + } + + private async switchNet() { + await this.web3.switchNet( + this.getChainIdHex(), + this.config.chain_name, + this.config.rpc_source + ); + } + + /** + * + * @param address address must start with 0x + * @returns + */ + encodeL1Address(address: string) { + if (address.substring(0, 2) != "0x") { + throw "address must start with 0x"; + } + + const addressHex = address.substring(2); + const chex = this.getChainIdHex().substring(2); + return encodeL1address(addressHex, chex); + } +} + +export async function withL1Client( + config: ChainConfig, + clientMode: boolean, + cb: (_: L1Client) => Promise +) { + const l1Client = new L1Client(config, clientMode); + await l1Client.init(); + try { + return await cb(l1Client); + } finally { + await l1Client.close(); + } +} diff --git a/clients/contracts/bridge.ts b/clients/contracts/bridge.ts new file mode 100644 index 0000000..5ef19ad --- /dev/null +++ b/clients/contracts/bridge.ts @@ -0,0 +1,187 @@ +import BN from "bn.js"; +import { DelphinusContract, DelphinusWeb3 } from "web3subscriber/src/client"; +import { decodeL1address } from "web3subscriber/src/addresses"; +import { PromiseBinder } from "web3subscriber/src/pbinder"; +import { TokenContract } from "./token"; +import { Tokens } from "./tokenlist"; + +const BridgeContractABI = require("../../build/contracts/Bridge.json"); + +/* + * Types + */ +export interface BridgeInfo { + chain_id: string; + amount_token: string; + amount_pool: string; + owner: string; + merkle_root: string; + rid: string; +} + +export interface TokenInfo { + token_uid: string; +} + +/* + * Events + */ +export interface Deposit { + l1token: string; + l2account: string; + amount: string; + nonce: string; +} + +export interface SwapAck { + l2account: string; + rid: string; +} + +export interface WithDraw { + l1account: string; + l2account: string; + amount: string; + nonce: string; +} + +function hexcmp(x: string, y: string) { + const xx = new BN(x, "hex"); + const yy = new BN(y, "hex"); + return xx.eq(yy); +} + +export class BridgeContract extends DelphinusContract { + constructor(web3: DelphinusWeb3, address: string, account?: string) { + super(web3, BridgeContract.getJsonInterface(), address, account); + } + + static getJsonInterface(): any { + return BridgeContractABI; + } + + static getContractAddress(chainId: string) { + return BridgeContractABI.networks[chainId].address; + } + + async getBridgeInfo() { + return this.getWeb3Contract().methods.getBridgeInfo().call(); + } + + async allTokens(): Promise { + return await this.getWeb3Contract().methods.allTokens().call(); + } + + async addToken(tokenid: BN) { + return await this.getWeb3Contract().methods.addToken(tokenid).send(); + } + + private async _verify( + l2account: string, + calldata: BN[], + verifydata: BN[], + vid: number, + nonce: number, + rid: BN + ) { + return await this.getWeb3Contract() + .methods.verify(l2account, calldata, verifydata, vid, nonce, rid) + .send(); + } + + private async _deposit(tokenAddress: string, amount: number, l2account: string) { + return await this.getWeb3Contract() + .methods.deposit(tokenAddress, amount, l2account) + .send(); + } + + verify( + l2account: string, + calldata: BN[], + verifydata: BN[], + vid: number, + nonce: number, + rid: BN + ) { + const pbinder = new PromiseBinder(); + + return pbinder.return(async () => { + return await pbinder.bind( + "Verify", + this._verify(l2account, calldata, verifydata, vid, nonce, rid) + ); + }); + } + + deposit( + tokenContract: TokenContract, + amount: number, + l2account: string + ) { + const pbinder = new PromiseBinder(); + + return pbinder.return(async () => { + pbinder.snapshot("Approve"); + await pbinder.bind( + "Approve", + tokenContract.approve(this.address(), amount) + ); + pbinder.snapshot("Deposit"); + return await pbinder.bind( + "Deposit", + this._deposit(tokenContract.address(), amount, l2account) + ); + }); + } + + private async extractChainInfo() { + let tokenInfos = await this.allTokens(); + let tokens = tokenInfos + .filter((t) => t.token_uid != "0") + .map((token) => { + let [cid, address] = decodeL1address(token.token_uid); + return { + address: address, + name: + Tokens.tokenInfo.find( + (x: any) => hexcmp(x.address, address) && x.chainId == cid + )?.name || "unknown", + chainId: cid, + index: tokenInfos.findIndex( + (x: TokenInfo) => x.token_uid == token.token_uid + ), + }; + }); + let chain_list = Array.from(new Set(tokens.map((x) => x.chainId))); + let token_list = chain_list.map((chain_id) => ({ + chainId: chain_id, + chainName: Tokens.chainInfo[chain_id], + tokens: tokens.filter((x) => x.chainId == chain_id), + enable: true, + })); + return token_list; + } + + async getTokenInfo(idx: number) { + const token = (await this.allTokens())[idx]; + let [cid, addr] = decodeL1address(token.token_uid); + return { + chainId: cid, + chainName: Tokens.chainInfo[cid], + tokenAddress: addr, + tokenName: + Tokens.tokenInfo.find( + (x: any) => hexcmp(x.address, addr) && x.chainId == cid + )?.name || "unknown", + index: idx, + }; + } + + async getMetaData() { + return { + bridgeInfo: await this.getBridgeInfo(), + tokens: await this.allTokens(), + chainInfo: await this.extractChainInfo(), + }; + } +} diff --git a/clients/contracts/token.ts b/clients/contracts/token.ts new file mode 100644 index 0000000..3a65a62 --- /dev/null +++ b/clients/contracts/token.ts @@ -0,0 +1,33 @@ +import { DelphinusContract, DelphinusWeb3 } from "web3subscriber/src/client"; + +const TokenABI = require("../../build/contracts/IERC20.json"); + +export class TokenContract extends DelphinusContract { + constructor(web3: DelphinusWeb3, address: string, account?: string) { + super(web3, TokenContract.getJsonInterface(), address, account); + } + + static getJsonInterface(): any { + return TokenABI; + } + + async approve(address: string, amount: number) { + return await this.getWeb3Contract().methods.approve(address, amount).send(); + } + + async balanceOf(account?: string) { + return account + ? await this.getWeb3Contract().methods.balanceOf(account).call() + : await this.getWeb3Contract().methods.balanceOf().call(); + } + + async mint(amount: number) { + return await this.getWeb3Contract().methods.mint(amount).send(); + } + + async transfer(address: string, amount: number) { + return await this.getWeb3Contract() + .methods.transfer(address, amount) + .send(); + } +} diff --git a/clients/bridge/tokenlist.js b/clients/contracts/tokenlist.ts similarity index 91% rename from clients/bridge/tokenlist.js rename to clients/contracts/tokenlist.ts index 6e36c04..bbe09c5 100644 --- a/clients/bridge/tokenlist.js +++ b/clients/contracts/tokenlist.ts @@ -10,7 +10,7 @@ const chain_info = { "97": "bsctestnet", } -const token_info = [ +export const Tokens = [ { chainId: "15", address:TokenInfo.networks["15"]?.address.replace("0x", ""), @@ -41,9 +41,4 @@ const token_info = [ address:TokenInfo.networks["97"]?.address.replace("0x", ""), name:"sToken" }, -]; - -module.exports = { - chainInfo: chain_info, - tokenInfo: token_info, -} +]; \ No newline at end of file diff --git a/clients/bridge/deposit.js b/clients/tools/bridge/deposit.js similarity index 100% rename from clients/bridge/deposit.js rename to clients/tools/bridge/deposit.js diff --git a/clients/bridge/init.ts b/clients/tools/bridge/init.ts similarity index 70% rename from clients/bridge/init.ts rename to clients/tools/bridge/init.ts index d5fdf8d..3371763 100644 --- a/clients/bridge/init.ts +++ b/clients/tools/bridge/init.ts @@ -1,9 +1,8 @@ -import { EthConfig } from "../config"; -import { Bridge, withBridgeClient } from "./bridge"; +import { EthConfig } from "../../config"; +import { L1Client, withL1Client } from "../../client"; import { encodeL1address } from "web3subscriber/src/addresses"; const Tokens = require("./tokenlist"); -const TokenInfo = require("../../build/contracts/Token.json"); const Secrets = require("../../.secrets"); const fs = require("fs"); const path = require("path"); @@ -19,21 +18,13 @@ function crunchTokens() { async function main(config_name: string) { console.log("start calling"); let config = EthConfig[config_name](Secrets); - let address = TokenInfo.networks[config.device_id].address; try { - withBridgeClient(config, false, async (bridge: Bridge) => { - /* - let token = bridge.web3.getContract( - TokenInfo, - address, - bridge.web3.getDefaultAccount() - ); - */ - + withL1Client(config, false, async (l1client: L1Client) => { + let bridge = l1client.getBridgeContract(); let output: any = {}; let index = 4; - console.log("Testing bridge [id=%s]", bridge.getChainIdHex()); + console.log("Testing bridge [id=%s]", l1client.getChainIdHex()); for (let tokenUid of crunchTokens()) { console.log("Adding token uid: 0x", tokenUid.toString(16)); let tx = await bridge.addToken(tokenUid); diff --git a/clients/bridge/status.js b/clients/tools/bridge/status.js similarity index 100% rename from clients/bridge/status.js rename to clients/tools/bridge/status.js diff --git a/clients/token/allowance.js b/clients/tools/token/allowance.js similarity index 100% rename from clients/token/allowance.js rename to clients/tools/token/allowance.js diff --git a/clients/token/balance.js b/clients/tools/token/balance.js similarity index 100% rename from clients/token/balance.js rename to clients/tools/token/balance.js diff --git a/clients/token/mint-rio.js b/clients/tools/token/mint-rio.js similarity index 100% rename from clients/token/mint-rio.js rename to clients/tools/token/mint-rio.js diff --git a/clients/token/mint.ts b/clients/tools/token/mint.ts similarity index 53% rename from clients/token/mint.ts rename to clients/tools/token/mint.ts index 5312f52..68cbd63 100644 --- a/clients/token/mint.ts +++ b/clients/tools/token/mint.ts @@ -1,33 +1,30 @@ -import { Bridge, withBridgeClient } from "../bridge/bridge"; -import { EthConfig } from "../config"; +import { withL1Client, L1Client } from "../../client"; +import { EthConfig } from "../../config"; -const Config = require("../config"); const PBinder = require("web3subscriber/src/pbinder"); -const TokenInfo = require("../../build/contracts/Token.json"); const Secrets = require("../../.secrets"); function main(configName: string, targetAccount: string) { let config = EthConfig[configName](Secrets); let account = config.monitor_account; - let address = TokenInfo.networks[config.device_id].address; let pbinder = new PBinder.PromiseBinder(); let r = pbinder.return(async () => { - withBridgeClient(config, false, async (bridge: Bridge) => { - let token = bridge.web3.getContract(TokenInfo, address, account); + withL1Client(config, false, async (l1client: L1Client) => { + let token = l1client.getTokenContract(); // await web3.eth.net.getId(); try { - console.log("mint token:", token.getContractInstance().options.address); - let balance = await token.getBalance(account); + console.log("mint token:", token.address()); + let balance = await token.balanceOf(account); console.log("sender: balance before mint:", balance); - await pbinder.bind("mint", token.getContractInstance().methods.mint(0x10000000).send()); - balance = await token.getBalance(account); + await pbinder.bind("mint", token.mint(0x10000000)); + balance = await token.balanceOf(account); console.log("sender: balance after mint", balance); if (targetAccount) { await pbinder.bind( "transfer", - token.getContractInstance().methods.transfer(targetAccount, 0x10000000).send() + token.transfer(targetAccount, 0x10000000) ); - balance = await token.getBalance(targetAccount); + balance = await token.balanceOf(targetAccount); console.log("balance of recipient after transfer", balance); } } catch (err) { diff --git a/clients/types/bridge.ts b/clients/types/bridge.ts deleted file mode 100644 index 29bf23d..0000000 --- a/clients/types/bridge.ts +++ /dev/null @@ -1,12 +0,0 @@ -export interface BridgeInfo { - chain_id: string; - amount_token: string; - amount_pool: string; - owner: string; - merkle_root: string; - rid: string; - } - - export interface TokenInfo { - token_uid: string; - } \ No newline at end of file diff --git a/clients/types/events.ts b/clients/types/events.ts deleted file mode 100644 index ffdb178..0000000 --- a/clients/types/events.ts +++ /dev/null @@ -1,18 +0,0 @@ -export interface Deposit { - l1token: string; - l2account: string; - amount: string; - nonce: string; - } - - export interface SwapAck { - l2account: string; - rid: string; - } - - export interface WithDraw { - l1account: string; - l2account: string; - amount: string; - nonce: string; - } From 7c8686f5dc70e036d14809d012f99365b86eb8f6 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Sat, 13 Nov 2021 18:14:07 +0800 Subject: [PATCH 08/21] fix compiling error --- clients/contracts/bridge.ts | 11 +++++------ clients/contracts/tokenlist.ts | 3 ++- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/clients/contracts/bridge.ts b/clients/contracts/bridge.ts index 5ef19ad..3442ee6 100644 --- a/clients/contracts/bridge.ts +++ b/clients/contracts/bridge.ts @@ -3,8 +3,7 @@ import { DelphinusContract, DelphinusWeb3 } from "web3subscriber/src/client"; import { decodeL1address } from "web3subscriber/src/addresses"; import { PromiseBinder } from "web3subscriber/src/pbinder"; import { TokenContract } from "./token"; -import { Tokens } from "./tokenlist"; - +import { Tokens, Chains } from "./tokenlist"; const BridgeContractABI = require("../../build/contracts/Bridge.json"); /* @@ -143,7 +142,7 @@ export class BridgeContract extends DelphinusContract { return { address: address, name: - Tokens.tokenInfo.find( + Tokens.find( (x: any) => hexcmp(x.address, address) && x.chainId == cid )?.name || "unknown", chainId: cid, @@ -155,7 +154,7 @@ export class BridgeContract extends DelphinusContract { let chain_list = Array.from(new Set(tokens.map((x) => x.chainId))); let token_list = chain_list.map((chain_id) => ({ chainId: chain_id, - chainName: Tokens.chainInfo[chain_id], + chainName: Chains[chain_id], tokens: tokens.filter((x) => x.chainId == chain_id), enable: true, })); @@ -167,10 +166,10 @@ export class BridgeContract extends DelphinusContract { let [cid, addr] = decodeL1address(token.token_uid); return { chainId: cid, - chainName: Tokens.chainInfo[cid], + chainName: Chains[cid], tokenAddress: addr, tokenName: - Tokens.tokenInfo.find( + Tokens.find( (x: any) => hexcmp(x.address, addr) && x.chainId == cid )?.name || "unknown", index: idx, diff --git a/clients/contracts/tokenlist.ts b/clients/contracts/tokenlist.ts index bbe09c5..adcf61b 100644 --- a/clients/contracts/tokenlist.ts +++ b/clients/contracts/tokenlist.ts @@ -3,7 +3,8 @@ const TokenInfo = require("../../build/contracts/Token.json"); const RioInfo = require("../../build/contracts/Rio.json"); -const chain_info = { + +export const Chains : Record = { "15": "local-test-net1", "16": "local-test-net2", "3": "ropsten", From 0be63b6462aac1703df855fa55f92c2eb62abe4d Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 15 Nov 2021 14:37:58 +0800 Subject: [PATCH 09/21] adapt delphinus-deployment --- .secrets.json | 18 ----- clients/client.ts | 2 +- clients/config.ts | 129 ----------------------------------- clients/token-index.json | 5 -- clients/tools/bridge/init.ts | 2 +- clients/tools/token/mint.ts | 2 +- package.json | 3 +- truffle-config.js | 6 +- 8 files changed, 8 insertions(+), 159 deletions(-) delete mode 100644 .secrets.json delete mode 100644 clients/config.ts delete mode 100644 clients/token-index.json diff --git a/.secrets.json b/.secrets.json deleted file mode 100644 index be1450c..0000000 --- a/.secrets.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "infura_id":"1c8e4178f8954e01a95c8eef7b8af2b7", - "getblock_key":"182a8e0d-c03a-44ac-b856-41d2e47801db", - "accounts": { - "deployer": { - "priv": "0xb8b8ceb316c761a97cdd6c3613fc5c6d71bb8c49d76f76a7a926e5f9414af0a3" - }, - "tester": { - "priv":"0xf6392ba9b8cb91490a3e06fe141d5140df89e73931b0e3570bad0de7ef1f25c3" - }, - "tester2": { - "priv":"0xba81dd44260d036d293fbe85ad1bb141276fcc331e724877f08b6b42cc3df8d9" - }, - "monitor": { - "priv":"0xf6392ba9b8cb91490a3e06fe141d5140df89e73931b0e3570bad0de7ef1f25c3" - } - } -} diff --git a/clients/client.ts b/clients/client.ts index ebc100c..16c6065 100644 --- a/clients/client.ts +++ b/clients/client.ts @@ -5,7 +5,7 @@ import { Web3ProviderMode, } from "web3subscriber/src/client"; import { encodeL1address } from "web3subscriber/src/addresses"; -import { ChainConfig } from "./config"; +import { ChainConfig } from "delphinus-deployment/src/config"; import { BridgeContract } from "./contracts/bridge"; import { TokenContract } from "./contracts/token"; diff --git a/clients/config.ts b/clients/config.ts deleted file mode 100644 index 0a98e1d..0000000 --- a/clients/config.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { provider } from "web3-core"; - -const HDWalletProvider = require("@truffle/hdwallet-provider"); -const Web3WsProvider = require("web3-providers-ws"); -const Web3HttpProvider = require("web3-providers-http"); - -const ws_options = { - timeout: 30000, // ms - - clientConfig: { - // Useful if requests are large - maxReceivedFrameSize: 100000000, // bytes - default: 1MiB - maxReceivedMessageSize: 100000000, // bytes - default: 8MiB - - // Useful to keep a connection alive - keepalive: true, - keepaliveInterval: 60000, // ms - }, - - // Enable auto reconnection - reconnect: { - auto: true, - delay: 5000, // ms - maxAttempts: 5, - onTimeout: true, - }, -}; - -const http_options = { - keepAlive: false, - timeout: 20000, // milliseconds, - withCredentials: false, -}; - -const ws_provider = (url: string) => { - let p = new Web3WsProvider(url, ws_options); - return p; -}; - -const http_provider = (url: string) => { - let p = new Web3HttpProvider(url, http_options); - return p; -}; - -export interface ChainConfig { - provider: (_: void) => any; - close_provider: (provider: provider) => Promise; - mongodb_url: string; - ws_source: string; - rpc_source: string; - device_id: string; - monitor_account: string; - chain_name: string; -} - -export const EthConfig: Record ChainConfig> = { - localtestnet1: () => { - return { - provider: () => "ws://127.0.0.1:8546", - close_provider: async (provider: any) => { - await provider.connection.close(); - }, - mongodb_url: "mongodb://localhost:27017", - ws_source: "ws://127.0.0.1:8546", - rpc_source: "ws://127.0.0.1:8545", - device_id: "15", - monitor_account: "0x6f6ef6dfe681b6593ddf27da3bfde22083aef88b", - chain_name: "localtestnet1", - }; - }, - localtestnet2: () => { - return { - provider: () => "ws://127.0.0.1:8746", - close_provider: async (provider: any) => { - await provider.connection.close(); - }, - mongodb_url: "mongodb://localhost:27017", - rpc_source: "http://127.0.0.1:8745", - ws_source: "ws://127.0.0.1:8746", - monitor_account: "0x6f6ef6dfe681b6593ddf27da3bfde22083aef88b", - device_id: "16", - chain_name: "localtestnet2", - }; - }, - bsctestnet: (secrets: any) => { - return { - provider: () => - new HDWalletProvider({ - privateKeys: [secrets.accounts.deployer.priv], - providerOrUrl: http_provider( - "https://bsc.getblock.io/testnet/?api_key=" + secrets.getblock_key - ), - shareNonce: false, - }), - close_provider: async (provider: any) => { - await provider.engine.stop(); - }, - mongodb_url: "mongodb://localhost:27017", - rpc_source: - "https://bsc.getblock.io/testnet/?api_key=" + secrets.getblock_key, - ws_source: - "wss://bsc.getblock.io/testnet/?api_key=" + secrets.getblock_key, - monitor_account: "0x6f6ef6dfe681b6593ddf27da3bfde22083aef88b", - device_id: "97", - chain_name: "bsctestnet", - }; - }, - ropsten: (secrets: any) => { - return { - provider: () => - new HDWalletProvider({ - privateKeys: [secrets.accounts.deployer.priv], - providerOrUrl: http_provider( - "https://ropsten.infura.io/v3/" + secrets.infura_id - ), - shareNonce: false, - }), - close_provider: async (provider: any) => { - await provider.engine.stop(); - }, - mongodb_url: "mongodb://localhost:27017", - rpc_source: "https://ropsten.infura.io/v3/" + secrets.infura_id, - ws_source: "wss://ropsten.infura.io/ws/v3/" + secrets.infura_id, - monitor_account: "0x6f6ef6dfe681b6593ddf27da3bfde22083aef88b", - device_id: "3", - chain_name: "ropsten", - }; - }, -}; diff --git a/clients/token-index.json b/clients/token-index.json deleted file mode 100644 index 3619688..0000000 --- a/clients/token-index.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "5195817369820449998442598550148912025672908262375": 4, - "4458373458645478945299645731909581084615981406885": 5, - "142918609290775582167001084962377293926986042917364": 6 -} \ No newline at end of file diff --git a/clients/tools/bridge/init.ts b/clients/tools/bridge/init.ts index 3371763..bc6aad8 100644 --- a/clients/tools/bridge/init.ts +++ b/clients/tools/bridge/init.ts @@ -1,4 +1,4 @@ -import { EthConfig } from "../../config"; +import { EthConfig } from "delphinus-deployment/src/config"; import { L1Client, withL1Client } from "../../client"; import { encodeL1address } from "web3subscriber/src/addresses"; diff --git a/clients/tools/token/mint.ts b/clients/tools/token/mint.ts index 68cbd63..a269777 100644 --- a/clients/tools/token/mint.ts +++ b/clients/tools/token/mint.ts @@ -1,5 +1,5 @@ import { withL1Client, L1Client } from "../../client"; -import { EthConfig } from "../../config"; +import { EthConfig } from "delphinus-deployment/src/config"; const PBinder = require("web3subscriber/src/pbinder"); const Secrets = require("../../.secrets"); diff --git a/package.json b/package.json index eeddef7..e73ff3e 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "react": "^17.0.2", "truffle": "latest", "web3": "1.5.3", - "web3subscriber": "*" + "web3subscriber": "*", + "delphinus-deployment": "*" }, "scripts": { "dev": "npx truffle dev", diff --git a/truffle-config.js b/truffle-config.js index acb66c1..206a102 100644 --- a/truffle-config.js +++ b/truffle-config.js @@ -23,7 +23,7 @@ const Web3HttpProvider = require('web3-providers-http'); const HDWalletProvider = require('@truffle/hdwallet-provider'); const fs = require('fs'); -const secrets = require('./.secrets.json'); +const secrets = require('delphinus-deployment/src/secrets'); const http_options = { keepAlive: true, @@ -80,7 +80,7 @@ module.exports = { websocket: true // Enable EventEmitter interface for web3 (default: false) }, ropsten: { //eth testnet - provider: () => new HDWalletProvider(secrets.accounts.deployer.priv, + provider: () => new HDWalletProvider(secrets.Secrets.accounts.deployer.priv, http_provider("https://ropsten.infura.io/v3/" + secrets.infura_id) ), network_id: 3, // Ropsten's id @@ -90,7 +90,7 @@ module.exports = { skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) }, bsctestnet: { //bsc - provider: () => new HDWalletProvider(secrets.accounts.deployer.priv, + provider: () => new HDWalletProvider(secrets.Secrets.accounts.deployer.priv, http_provider(`https://data-seed-prebsc-1-s1.binance.org:8545`) //http_provider("https://bsc.getblock.io/testnet/?api_key="+secrets.getblock_key) ), From 167a9089657ae752d18baa1061b7d7386879eda4 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 15 Nov 2021 15:42:33 +0800 Subject: [PATCH 10/21] fix init script --- clients/tools/bridge/init.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/clients/tools/bridge/init.ts b/clients/tools/bridge/init.ts index bc6aad8..3394104 100644 --- a/clients/tools/bridge/init.ts +++ b/clients/tools/bridge/init.ts @@ -1,14 +1,13 @@ -import { EthConfig } from "delphinus-deployment/src/config"; +import { EthConfigEnabled } from "delphinus-deployment/src/config"; import { L1Client, withL1Client } from "../../client"; import { encodeL1address } from "web3subscriber/src/addresses"; +import { Tokens } from "../../contracts/tokenlist"; -const Tokens = require("./tokenlist"); -const Secrets = require("../../.secrets"); const fs = require("fs"); const path = require("path"); function crunchTokens() { - return Tokens.tokenInfo + return Tokens .filter((x: any) => x.address) .map((x: any) => encodeL1address(x.address, parseInt(x.chainId).toString(16)) @@ -17,7 +16,7 @@ function crunchTokens() { async function main(config_name: string) { console.log("start calling"); - let config = EthConfig[config_name](Secrets); + let config = EthConfigEnabled.find(config => config.chain_name === config_name)!; try { withL1Client(config, false, async (l1client: L1Client) => { let bridge = l1client.getBridgeContract(); @@ -30,11 +29,11 @@ async function main(config_name: string) { let tx = await bridge.addToken(tokenUid); console.log(tx); - output[tokenUid] = index++; + output[tokenUid.toString()] = index++; } fs.writeFileSync( - path.resolve(__dirname, "..", "token-index.json"), + path.resolve(__dirname, "../../../../deployment/src", "token-index.json"), JSON.stringify(output, undefined, 2) ); From 15dc830236055d60922a597a2d89b850a2de792c Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 15 Nov 2021 17:47:34 +0800 Subject: [PATCH 11/21] fix BridgeInfo --- clients/client.ts | 2 +- clients/contracts/bridge.ts | 20 ++++++++++---------- clients/contracts/token.ts | 27 +++++++++++++++------------ clients/tools/token/mint.ts | 12 +++++------- 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/clients/client.ts b/clients/client.ts index 16c6065..2a0eaa9 100644 --- a/clients/client.ts +++ b/clients/client.ts @@ -59,7 +59,7 @@ export class L1Client { getTokenContract(address?: string, account?: string) { return new TokenContract( this.web3, - address || BridgeContract.getContractAddress(this.config.device_id), + address || TokenContract.getContractAddress(this.config.device_id), account ); } diff --git a/clients/contracts/bridge.ts b/clients/contracts/bridge.ts index 3442ee6..648508d 100644 --- a/clients/contracts/bridge.ts +++ b/clients/contracts/bridge.ts @@ -1,4 +1,4 @@ -import BN from "bn.js"; +import BN = require('bn.js'); import { DelphinusContract, DelphinusWeb3 } from "web3subscriber/src/client"; import { decodeL1address } from "web3subscriber/src/addresses"; import { PromiseBinder } from "web3subscriber/src/pbinder"; @@ -63,19 +63,19 @@ export class BridgeContract extends DelphinusContract { return BridgeContractABI.networks[chainId].address; } - async getBridgeInfo() { + getBridgeInfo() { return this.getWeb3Contract().methods.getBridgeInfo().call(); } - async allTokens(): Promise { - return await this.getWeb3Contract().methods.allTokens().call(); + allTokens(): Promise { + return this.getWeb3Contract().methods.allTokens().call(); } - async addToken(tokenid: BN) { - return await this.getWeb3Contract().methods.addToken(tokenid).send(); + addToken(tokenid: BN) { + return this.getWeb3Contract().methods.addToken(tokenid).send(); } - private async _verify( + private _verify( l2account: string, calldata: BN[], verifydata: BN[], @@ -83,13 +83,13 @@ export class BridgeContract extends DelphinusContract { nonce: number, rid: BN ) { - return await this.getWeb3Contract() + return this.getWeb3Contract() .methods.verify(l2account, calldata, verifydata, vid, nonce, rid) .send(); } - private async _deposit(tokenAddress: string, amount: number, l2account: string) { - return await this.getWeb3Contract() + private _deposit(tokenAddress: string, amount: number, l2account: string) { + return this.getWeb3Contract() .methods.deposit(tokenAddress, amount, l2account) .send(); } diff --git a/clients/contracts/token.ts b/clients/contracts/token.ts index 3a65a62..8b032e5 100644 --- a/clients/contracts/token.ts +++ b/clients/contracts/token.ts @@ -1,6 +1,7 @@ import { DelphinusContract, DelphinusWeb3 } from "web3subscriber/src/client"; -const TokenABI = require("../../build/contracts/IERC20.json"); +const TokenContractABI = require("../../build/contracts/Token.json"); +// const TokenABI = require("../../build/contracts/IERC20.json"); export class TokenContract extends DelphinusContract { constructor(web3: DelphinusWeb3, address: string, account?: string) { @@ -8,25 +9,27 @@ export class TokenContract extends DelphinusContract { } static getJsonInterface(): any { - return TokenABI; + return TokenContractABI; } - async approve(address: string, amount: number) { - return await this.getWeb3Contract().methods.approve(address, amount).send(); + static getContractAddress(chainId: string) { + return TokenContractABI.networks[chainId].address; } - async balanceOf(account?: string) { - return account - ? await this.getWeb3Contract().methods.balanceOf(account).call() - : await this.getWeb3Contract().methods.balanceOf().call(); + approve(address: string, amount: number) { + return this.getWeb3Contract().methods.approve(address, amount).send(); } - async mint(amount: number) { - return await this.getWeb3Contract().methods.mint(amount).send(); + balanceOf(account: string) { + return this.getWeb3Contract().methods.balanceOf(account).call(); } - async transfer(address: string, amount: number) { - return await this.getWeb3Contract() + mint(amount: number) { + return this.getWeb3Contract().methods.mint(amount).send(); + } + + transfer(address: string, amount: number) { + return this.getWeb3Contract() .methods.transfer(address, amount) .send(); } diff --git a/clients/tools/token/mint.ts b/clients/tools/token/mint.ts index a269777..c83f4be 100644 --- a/clients/tools/token/mint.ts +++ b/clients/tools/token/mint.ts @@ -1,15 +1,13 @@ import { withL1Client, L1Client } from "../../client"; -import { EthConfig } from "delphinus-deployment/src/config"; - -const PBinder = require("web3subscriber/src/pbinder"); -const Secrets = require("../../.secrets"); +import { EthConfigEnabled } from "delphinus-deployment/src/config"; +import { PromiseBinder } from "web3subscriber/src/pbinder"; function main(configName: string, targetAccount: string) { - let config = EthConfig[configName](Secrets); + let config = EthConfigEnabled.find(config => config.chain_name == configName)!; let account = config.monitor_account; - let pbinder = new PBinder.PromiseBinder(); + let pbinder = new PromiseBinder(); let r = pbinder.return(async () => { - withL1Client(config, false, async (l1client: L1Client) => { + await withL1Client(config, false, async (l1client: L1Client) => { let token = l1client.getTokenContract(); // await web3.eth.net.getId(); try { From 3ecbda1f0dbcc79468fcb70dccd0091c27814260 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Mon, 15 Nov 2021 20:25:29 +0800 Subject: [PATCH 12/21] adapt delphinus-deployment --- clients/tools/bridge/init.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/tools/bridge/init.ts b/clients/tools/bridge/init.ts index 3394104..937bbad 100644 --- a/clients/tools/bridge/init.ts +++ b/clients/tools/bridge/init.ts @@ -33,7 +33,7 @@ async function main(config_name: string) { } fs.writeFileSync( - path.resolve(__dirname, "../../../../deployment/src", "token-index.json"), + path.resolve(__dirname, "../../../../deployment/src/local", "token-index.json"), JSON.stringify(output, undefined, 2) ); From 8ca9ec1fe9f4f572a2501b1850c086c9256dac5d Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 18 Nov 2021 11:29:16 +0800 Subject: [PATCH 13/21] update deployment --- clients/client.ts | 41 +++++++++++++++++++++++++++--------- clients/tools/bridge/init.ts | 7 +++--- clients/tools/token/mint.ts | 21 +++++++++--------- 3 files changed, 46 insertions(+), 23 deletions(-) diff --git a/clients/client.ts b/clients/client.ts index 2a0eaa9..67f59bd 100644 --- a/clients/client.ts +++ b/clients/client.ts @@ -5,9 +5,14 @@ import { Web3ProviderMode, } from "web3subscriber/src/client"; import { encodeL1address } from "web3subscriber/src/addresses"; -import { ChainConfig } from "delphinus-deployment/src/config"; +import { ChainConfig, ProviderType } from "delphinus-deployment/src/types"; import { BridgeContract } from "./contracts/bridge"; import { TokenContract } from "./contracts/token"; +import { + DelphinusHDWalletProvider, + DelphinusHttpProvider, + DelphinusWsProvider, +} from "web3subscriber/src/provider"; const L1ADDR_BITS = 160; @@ -19,10 +24,26 @@ export class L1Client { if (clientMode) { this.web3 = new Web3BrowsersMode(); } else { + let provider; + + switch (config.providerType) { + case ProviderType.WebsocketProvider: + provider = new DelphinusWsProvider(config.wsSource); + break; + case ProviderType.HDWalletProvider: + provider = new DelphinusHDWalletProvider( + config.privateKey, + config.rpcSource + ); + break; + case ProviderType.HttpProvider: + provider = new DelphinusHttpProvider(config.wsSource); + break; + } + this.web3 = new Web3ProviderMode({ - provider: config.provider(), - closeProvider: config.close_provider, - monitorAccount: config.monitor_account, + provider: provider, + monitorAccount: config.monitorAccount, }); } @@ -30,7 +51,7 @@ export class L1Client { } async init() { - console.log(`init_bridge on %s`, this.config.chain_name); + console.log(`init_bridge on %s`, this.config.chainName); await this.web3.connect(); await this.switchNet(); @@ -41,7 +62,7 @@ export class L1Client { } getChainIdHex() { - return "0x" + new BN(this.config.device_id).toString(16); + return "0x" + new BN(this.config.deviceId).toString(16); } getDefaultAccount() { @@ -51,7 +72,7 @@ export class L1Client { getBridgeContract(account?: string) { return new BridgeContract( this.web3, - BridgeContract.getContractAddress(this.config.device_id), + BridgeContract.getContractAddress(this.config.deviceId), account ); } @@ -59,7 +80,7 @@ export class L1Client { getTokenContract(address?: string, account?: string) { return new TokenContract( this.web3, - address || TokenContract.getContractAddress(this.config.device_id), + address || TokenContract.getContractAddress(this.config.deviceId), account ); } @@ -67,8 +88,8 @@ export class L1Client { private async switchNet() { await this.web3.switchNet( this.getChainIdHex(), - this.config.chain_name, - this.config.rpc_source + this.config.chainName, + this.config.rpcSource ); } diff --git a/clients/tools/bridge/init.ts b/clients/tools/bridge/init.ts index 937bbad..b633344 100644 --- a/clients/tools/bridge/init.ts +++ b/clients/tools/bridge/init.ts @@ -1,7 +1,8 @@ -import { EthConfigEnabled } from "delphinus-deployment/src/config"; +import { getConfigByChainName } from "delphinus-deployment/src/config"; import { L1Client, withL1Client } from "../../client"; import { encodeL1address } from "web3subscriber/src/addresses"; import { Tokens } from "../../contracts/tokenlist"; +import { L1ClientRole } from "delphinus-deployment/src/types"; const fs = require("fs"); const path = require("path"); @@ -16,9 +17,9 @@ function crunchTokens() { async function main(config_name: string) { console.log("start calling"); - let config = EthConfigEnabled.find(config => config.chain_name === config_name)!; + let config = await getConfigByChainName(L1ClientRole.Monitor, config_name); try { - withL1Client(config, false, async (l1client: L1Client) => { + await withL1Client(config, false, async (l1client: L1Client) => { let bridge = l1client.getBridgeContract(); let output: any = {}; let index = 4; diff --git a/clients/tools/token/mint.ts b/clients/tools/token/mint.ts index c83f4be..0b15e38 100644 --- a/clients/tools/token/mint.ts +++ b/clients/tools/token/mint.ts @@ -1,10 +1,11 @@ import { withL1Client, L1Client } from "../../client"; -import { EthConfigEnabled } from "delphinus-deployment/src/config"; +import { getConfigByChainName } from "delphinus-deployment/src/config"; import { PromiseBinder } from "web3subscriber/src/pbinder"; +import { L1ClientRole } from "delphinus-deployment/src/types"; -function main(configName: string, targetAccount: string) { - let config = EthConfigEnabled.find(config => config.chain_name == configName)!; - let account = config.monitor_account; +async function main(configName: string, targetAccount: string) { + let config = await getConfigByChainName(L1ClientRole.Monitor, configName); + let account = config.monitorAccount; let pbinder = new PromiseBinder(); let r = pbinder.return(async () => { await withL1Client(config, false, async (l1client: L1Client) => { @@ -30,12 +31,12 @@ function main(configName: string, targetAccount: string) { } }); }); - return r; + await r.when( + "mint", + "transactionHash", + (hash: string) => console.log(hash) + ); } /* .once("transactionHash",hash => console.log(hash) */ -main(process.argv[2], process.argv[3]).when( - "mint", - "transactionHash", - (hash: string) => console.log(hash) -); +main(process.argv[2], process.argv[3]); \ No newline at end of file From c4b3fbe3eaba3dea1af24aacb5a4b1ce8ed50990 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 18 Nov 2021 16:09:17 +0800 Subject: [PATCH 14/21] extract getDelphinusProviderFromConfig --- clients/client.ts | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/clients/client.ts b/clients/client.ts index 67f59bd..b3670b3 100644 --- a/clients/client.ts +++ b/clients/client.ts @@ -16,6 +16,20 @@ import { const L1ADDR_BITS = 160; +function getDelphinusProviderFromConfig(config: ChainConfig) { + switch (config.providerType) { + case ProviderType.WebsocketProvider: + return new DelphinusWsProvider(config.wsSource); + case ProviderType.HDWalletProvider: + return new DelphinusHDWalletProvider( + config.privateKey, + config.rpcSource + ); + case ProviderType.HttpProvider: + return new DelphinusHttpProvider(config.wsSource); + } +} + export class L1Client { readonly web3: DelphinusWeb3; private readonly config: ChainConfig; @@ -24,25 +38,8 @@ export class L1Client { if (clientMode) { this.web3 = new Web3BrowsersMode(); } else { - let provider; - - switch (config.providerType) { - case ProviderType.WebsocketProvider: - provider = new DelphinusWsProvider(config.wsSource); - break; - case ProviderType.HDWalletProvider: - provider = new DelphinusHDWalletProvider( - config.privateKey, - config.rpcSource - ); - break; - case ProviderType.HttpProvider: - provider = new DelphinusHttpProvider(config.wsSource); - break; - } - this.web3 = new Web3ProviderMode({ - provider: provider, + provider: getDelphinusProviderFromConfig(config), monitorAccount: config.monitorAccount, }); } From 2bdfcafd67571a64bd60851e1f91a3505c939ebd Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 18 Nov 2021 16:17:59 +0800 Subject: [PATCH 15/21] format client.ts --- clients/client.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/clients/client.ts b/clients/client.ts index b3670b3..2b5faa9 100644 --- a/clients/client.ts +++ b/clients/client.ts @@ -21,10 +21,7 @@ function getDelphinusProviderFromConfig(config: ChainConfig) { case ProviderType.WebsocketProvider: return new DelphinusWsProvider(config.wsSource); case ProviderType.HDWalletProvider: - return new DelphinusHDWalletProvider( - config.privateKey, - config.rpcSource - ); + return new DelphinusHDWalletProvider(config.privateKey, config.rpcSource); case ProviderType.HttpProvider: return new DelphinusHttpProvider(config.wsSource); } From 952fc05919dc0c67ed45574427ee363b47f737c7 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Thu, 18 Nov 2021 16:23:28 +0800 Subject: [PATCH 16/21] update the secret path within truffle-config.js --- truffle-config.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/truffle-config.js b/truffle-config.js index 206a102..b343d51 100644 --- a/truffle-config.js +++ b/truffle-config.js @@ -23,7 +23,7 @@ const Web3HttpProvider = require('web3-providers-http'); const HDWalletProvider = require('@truffle/hdwallet-provider'); const fs = require('fs'); -const secrets = require('delphinus-deployment/src/secrets'); +const secrets = require('delphinus-deployment/src/remote/monitor-secrets.json'); const http_options = { keepAlive: true, @@ -80,7 +80,7 @@ module.exports = { websocket: true // Enable EventEmitter interface for web3 (default: false) }, ropsten: { //eth testnet - provider: () => new HDWalletProvider(secrets.Secrets.accounts.deployer.priv, + provider: () => new HDWalletProvider(secrets.accounts.deployer.priv, http_provider("https://ropsten.infura.io/v3/" + secrets.infura_id) ), network_id: 3, // Ropsten's id @@ -90,7 +90,7 @@ module.exports = { skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) }, bsctestnet: { //bsc - provider: () => new HDWalletProvider(secrets.Secrets.accounts.deployer.priv, + provider: () => new HDWalletProvider(secrets.accounts.deployer.priv, http_provider(`https://data-seed-prebsc-1-s1.binance.org:8545`) //http_provider("https://bsc.getblock.io/testnet/?api_key="+secrets.getblock_key) ), From c32ee1f798f7379e7f829b361f9e0b40269ba4d3 Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Tue, 23 Nov 2021 21:58:27 +0800 Subject: [PATCH 17/21] fix path of secret --- truffle-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/truffle-config.js b/truffle-config.js index b343d51..5c6606b 100644 --- a/truffle-config.js +++ b/truffle-config.js @@ -23,7 +23,7 @@ const Web3HttpProvider = require('web3-providers-http'); const HDWalletProvider = require('@truffle/hdwallet-provider'); const fs = require('fs'); -const secrets = require('delphinus-deployment/src/remote/monitor-secrets.json'); +const secrets = require('delphinus-deployment/server/config/monitor-secrets.json'); const http_options = { keepAlive: true, From 3682508b53cdd00c14dfcf2888904387be0fe386 Mon Sep 17 00:00:00 2001 From: Heng Zhang Date: Sun, 28 Nov 2021 14:00:51 +0800 Subject: [PATCH 18/21] fix mint rio --- clients/client.ts | 9 ++++ clients/contracts/rio.ts | 36 ++++++++++++++++ .../token/{mint-rio.js => mint-rio-old.js} | 0 clients/tools/token/mint-rio.ts | 42 +++++++++++++++++++ 4 files changed, 87 insertions(+) create mode 100644 clients/contracts/rio.ts rename clients/tools/token/{mint-rio.js => mint-rio-old.js} (100%) create mode 100644 clients/tools/token/mint-rio.ts diff --git a/clients/client.ts b/clients/client.ts index 2b5faa9..bad69de 100644 --- a/clients/client.ts +++ b/clients/client.ts @@ -8,6 +8,7 @@ import { encodeL1address } from "web3subscriber/src/addresses"; import { ChainConfig, ProviderType } from "delphinus-deployment/src/types"; import { BridgeContract } from "./contracts/bridge"; import { TokenContract } from "./contracts/token"; +import { RioContract } from "./contracts/rio"; import { DelphinusHDWalletProvider, DelphinusHttpProvider, @@ -71,6 +72,14 @@ export class L1Client { ); } + getRioContract(address?: string, account?: string) { + return new RioContract( + this.web3, + address || RioContract.getContractAddress(this.config.deviceId), + account + ); + } + getTokenContract(address?: string, account?: string) { return new TokenContract( this.web3, diff --git a/clients/contracts/rio.ts b/clients/contracts/rio.ts new file mode 100644 index 0000000..94ddc84 --- /dev/null +++ b/clients/contracts/rio.ts @@ -0,0 +1,36 @@ +import { DelphinusContract, DelphinusWeb3 } from "web3subscriber/src/client"; + +const RioContractABI = require("../../build/contracts/Rio.json"); +// const TokenABI = require("../../build/contracts/IERC20.json"); + +export class RioContract extends DelphinusContract { + constructor(web3: DelphinusWeb3, address: string, account?: string) { + super(web3, RioContract.getJsonInterface(), address, account); + } + + static getJsonInterface(): any { + return RioContractABI; + } + + static getContractAddress(chainId: string) { + return RioContractABI.networks[chainId].address; + } + + approve(address: string, amount: number) { + return this.getWeb3Contract().methods.approve(address, amount).send(); + } + + balanceOf(account: string) { + return this.getWeb3Contract().methods.balanceOf(account).call(); + } + + mint(amount: number) { + return this.getWeb3Contract().methods.mint(amount).send(); + } + + transfer(address: string, amount: number) { + return this.getWeb3Contract() + .methods.transfer(address, amount) + .send(); + } +} diff --git a/clients/tools/token/mint-rio.js b/clients/tools/token/mint-rio-old.js similarity index 100% rename from clients/tools/token/mint-rio.js rename to clients/tools/token/mint-rio-old.js diff --git a/clients/tools/token/mint-rio.ts b/clients/tools/token/mint-rio.ts new file mode 100644 index 0000000..32d61f1 --- /dev/null +++ b/clients/tools/token/mint-rio.ts @@ -0,0 +1,42 @@ +import { withL1Client, L1Client } from "../../client"; +import { getConfigByChainName } from "delphinus-deployment/src/config"; +import { PromiseBinder } from "web3subscriber/src/pbinder"; +import { L1ClientRole } from "delphinus-deployment/src/types"; + +async function main(configName: string, targetAccount: string) { + let config = await getConfigByChainName(L1ClientRole.Monitor, configName); + let account = config.monitorAccount; + let pbinder = new PromiseBinder(); + let r = pbinder.return(async () => { + await withL1Client(config, false, async (l1client: L1Client) => { + let token = l1client.getRioContract(); + // await web3.eth.net.getId(); + try { + console.log("mint token:", token.address()); + let balance = await token.balanceOf(account); + console.log("sender: balance before mint:", balance); + await pbinder.bind("mint", token.mint(0x100000000000)); + balance = await token.balanceOf(account); + console.log("sender: balance after mint", balance); + if (targetAccount) { + await pbinder.bind( + "transfer", + token.transfer(targetAccount, 0x100000000000) + ); + balance = await token.balanceOf(targetAccount); + console.log("balance of recipient after transfer", balance); + } + } catch (err) { + console.log("%s", err); + } + }); + }); + await r.when( + "mint", + "transactionHash", + (hash: string) => console.log(hash) + ); +} + +/* .once("transactionHash",hash => console.log(hash) */ +main(process.argv[2], process.argv[3]); \ No newline at end of file From fd09cd31979df2e0d1502a30ae3de7c32fbdbbae Mon Sep 17 00:00:00 2001 From: Heng Zhang Date: Sun, 28 Nov 2021 17:03:56 +0800 Subject: [PATCH 19/21] fix token index --- clients/tools/bridge/init.ts | 2 +- contracts/Bridge.sol | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/clients/tools/bridge/init.ts b/clients/tools/bridge/init.ts index b633344..8510ae8 100644 --- a/clients/tools/bridge/init.ts +++ b/clients/tools/bridge/init.ts @@ -22,7 +22,7 @@ async function main(config_name: string) { await withL1Client(config, false, async (l1client: L1Client) => { let bridge = l1client.getBridgeContract(); let output: any = {}; - let index = 4; + let index = 0; console.log("Testing bridge [id=%s]", l1client.getChainIdHex()); for (let tokenUid of crunchTokens()) { diff --git a/contracts/Bridge.sol b/contracts/Bridge.sol index ee3b58e..9ae4528 100644 --- a/contracts/Bridge.sol +++ b/contracts/Bridge.sol @@ -27,10 +27,6 @@ contract Bridge { _bridge_info.chain_id = chain_id; _bridge_info.owner = msg.sender; _bridge_info.merkle_root = 0x151399c724e17408a7a43cdadba2fc000da9339c56e4d49c6cdee6c4356fbc68; - addToken(0); - addToken(0); - addToken(0); - addToken(0); } /* Make sure token index is sain */ From 5bc5e6671784e8802ca7222940ff96522882e463 Mon Sep 17 00:00:00 2001 From: Heng Zhang Date: Sun, 28 Nov 2021 14:00:51 +0800 Subject: [PATCH 20/21] fix mint rio --- clients/tools/token/mint-rio.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/tools/token/mint-rio.ts b/clients/tools/token/mint-rio.ts index 32d61f1..c1dcf78 100644 --- a/clients/tools/token/mint-rio.ts +++ b/clients/tools/token/mint-rio.ts @@ -39,4 +39,4 @@ async function main(configName: string, targetAccount: string) { } /* .once("transactionHash",hash => console.log(hash) */ -main(process.argv[2], process.argv[3]); \ No newline at end of file +main(process.argv[2], process.argv[3]); From b93be9d57da3416c6ca90900f93ac7f0568563ef Mon Sep 17 00:00:00 2001 From: Xin Gao Date: Sun, 28 Nov 2021 23:41:28 +0800 Subject: [PATCH 21/21] add nft feature --- contracts/Bridge.sol | 39 ++++++++++++++++++++++++++++++++++++++- contracts/MKT.sol | 5 +++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/contracts/Bridge.sol b/contracts/Bridge.sol index 9ae4528..4833a8b 100644 --- a/contracts/Bridge.sol +++ b/contracts/Bridge.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "./Verifier.sol"; import "./Transaction.sol"; import "./MKT.sol"; @@ -9,6 +10,7 @@ contract Bridge { event Deposit(uint256 l1token, uint256 l2account, uint256 amount, uint256 nonce); event WithDraw(uint256 l1account, uint256 l2account, uint256 amount, uint256 nonce); event SwapAck(uint256 l2account, uint256 rid); + event DepositNFT(uint256 nftaddr, uint256 l2account, uint256 tokenId, uint256 nonce); BridgeInfo _bridge_info; @@ -16,13 +18,14 @@ contract Bridge { DelphinusVerifier[] private verifiers; TokenInfo[] private _tokens; + NFTAddressInfo[] private _nft_addresses; + mapping (uint256 => bool) private _tmap; address private _owner; mapping (uint256 => uint256) private _nonce; - constructor(uint32 chain_id) { _bridge_info.chain_id = chain_id; _bridge_info.owner = msg.sender; @@ -34,12 +37,23 @@ contract Bridge { require(tidx < _bridge_info.amount_token, "OutOfBound: Token Index"); } + /* Make sure nft index is sain */ + function nft_index_check(uint128 nidx) private view { + require(nidx < _bridge_info.amount_nft_contract, "OutOfBound: NFT Contract Index"); + } + /* Make sure token index is sain and return token uid */ function get_token_uid(uint128 tidx) private view returns (uint256){ token_index_check(tidx); return _tokens[tidx].token_uid; } + /* Make sure token index is sain and return nft address*/ + function get_nft_address(uint128 nidx) private view returns (uint256){ + nft_index_check(nidx); + return _nft_addresses[nidx].nft_address; + } + function ensure_admin() private view { require(_bridge_info.owner == msg.sender, "Authority: Require Admin"); } @@ -84,6 +98,21 @@ contract Bridge { } } + function _withdraw_nft(uint128 nidx, uint256 nftid, uint256 l1recipent) public { + uint256 nft_addr = get_nft_address(nidx); + if (_is_local(nft_addr) && _is_local(l1recipent)) { + address nft = address(uint160(nft_addr)); + address recipent = address(uint160(l1recipent)); + + // Sanitity checks + require(recipent!= address(0), "WithdrawNFT to the zero address"); + + // transfer amount back to recipent + IERC721 underlying_nft = IERC721(nft); + underlying_nft.transferFrom(address(this), recipent, nftid); + } + } + function addTransaction(address txaddr) public returns (uint) { ensure_admin(); uint cursor = transactions.length; @@ -137,6 +166,14 @@ contract Bridge { emit Deposit(_l1_address(token), l2account, amount , _nonce[l2account]); } + function deposit_nft(address nft, uint256 nftId, uint256 l2account) public { + IERC721 underlying_nft = IERC721(nft); + uint256 nft_address = _l1_address(nft); + underlying_nft.transferFrom(msg.sender, address(this), nftId); + _nonce[l2account] +=1; + emit DepositNFT(nft_address, l2account, nftId, _nonce[l2account]); + } + function nonceOf(uint256 l2account) public view returns(uint256) { return _nonce[l2account]; } diff --git a/contracts/MKT.sol b/contracts/MKT.sol index a0883ef..bf51132 100644 --- a/contracts/MKT.sol +++ b/contracts/MKT.sol @@ -12,9 +12,14 @@ struct TokenInfo { uint256 token_uid; } +struct NFTAddressInfo { + uint256 nft_address; +} + struct BridgeInfo { uint128 chain_id; uint32 amount_token; + uint32 amount_nft_contract; uint32 amount_pool; address owner; uint256 merkle_root;