diff --git a/package.json b/package.json index f6a50c098..9c6527dd5 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "packages/*" ], "scripts": { - "compile": "lerna run compile", + "compile": "lerna run compile --scope=@webb-tools/contracts", "build": "yarn compile && yarn build:packages", "setup": "yarn compile && yarn build:circuits && yarn build:ptau", "test": "yarn workspace @webb-tools/contracts run test", @@ -51,6 +51,8 @@ "copyfiles": "^2.4.1", "eth-proof": "~2.1.6", "ethers": "5.7.0", + "itertools": "^1.7.1", + "tomlify-j0.4":"^3.0.0", "ffjavascript": "^0.2.38", "hardhat": "^2.6.8", "hardhat-gas-reporter": "^1.0.8", @@ -95,4 +97,4 @@ "typechain": "^5.1.2", "typescript": "4.7.2" } -} +} \ No newline at end of file diff --git a/packages/anchors/src/AnchorHandler.ts b/packages/anchors/src/AnchorHandler.ts index be81fc9d5..2a0a84577 100644 --- a/packages/anchors/src/AnchorHandler.ts +++ b/packages/anchors/src/AnchorHandler.ts @@ -3,6 +3,7 @@ import { AnchorHandler as AnchorHandlerContract, AnchorHandler__factory, } from '@webb-tools/contracts'; +import { Deployer } from './Deployer'; export class AnchorHandler { contract: AnchorHandlerContract; @@ -25,6 +26,29 @@ export class AnchorHandler { return handler; } + public static async create2AnchorHandler( + bridgeAddress: string, + initResourceIds: string[], + initContractAddresses: string[], + deployer: Deployer, + saltHex: string, + signer: ethers.Signer + ) { + const argTypes = ['address', 'bytes32[]', 'address[]']; + const args = [bridgeAddress, initResourceIds, initContractAddresses]; + const { contract: contract } = await deployer.deploy( + AnchorHandler__factory, + saltHex, + signer, + undefined, + argTypes, + args + ); + + const handler = new AnchorHandler(contract); + return handler; + } + public static async connect(handlerAddress: string, signer: ethers.Signer) { const handlerContract = AnchorHandler__factory.connect(handlerAddress, signer); const handler = new AnchorHandler(handlerContract); diff --git a/packages/anchors/tsconfig.build.json b/packages/anchors/tsconfig.build.json index b3ebe74b3..b051ff381 100644 --- a/packages/anchors/tsconfig.build.json +++ b/packages/anchors/tsconfig.build.json @@ -5,6 +5,6 @@ "exclude": [], "extends": "../../tsconfig.build.json", "include": [ - "./src/**/*.ts", + "./src/*.ts", ] } diff --git a/packages/bridges/src/SignatureBridgeSide.ts b/packages/bridges/src/SignatureBridgeSide.ts index 840b1d13d..c367d1668 100644 --- a/packages/bridges/src/SignatureBridgeSide.ts +++ b/packages/bridges/src/SignatureBridgeSide.ts @@ -2,7 +2,7 @@ import { BigNumber, ethers } from 'ethers'; import { SignatureBridge, SignatureBridge__factory } from '@webb-tools/contracts'; import { FungibleTokenWrapper, Treasury } from '@webb-tools/tokens'; import { TokenWrapperHandler } from '@webb-tools/tokens'; -import { AnchorHandler } from '@webb-tools/anchors'; +import { AnchorHandler, Deployer } from '@webb-tools/anchors'; import { IVAnchor, IBridgeSide, Proposal } from '@webb-tools/interfaces'; import { TreasuryHandler } from '@webb-tools/tokens'; import { getChainIdType } from '@webb-tools/utils'; @@ -52,6 +52,29 @@ export class SignatureBridgeSide implements IBridgeSide { return bridgeSide; } + public static async create2BridgeSide( + deployer: Deployer, + saltHex: string, + admin: ethers.Wallet + ): Promise { + const argTypes = ['address', 'uint32']; + const args = [admin.address, 0]; + const { contract: deployedBridge } = await deployer.deploy( + SignatureBridge__factory, + saltHex, + admin, + undefined, + argTypes, + args + ); + const bridgeSide = new SignatureBridgeSide(deployedBridge, (data: any) => { + return Promise.resolve(signMessage(admin, data)); + }); + bridgeSide.admin = admin; + bridgeSide.governor = admin; + return bridgeSide; + } + /** * When an existing SignatureBridge is connected, the governor must be configured. * In the case of connectMocked, a wallet address is passed which will act as the governor. diff --git a/packages/contracts/test/token/AaveTokenWrapper.test.ts b/packages/contracts/test/token/AaveTokenWrapper.test.ts index f708191cc..1c568a4a9 100644 --- a/packages/contracts/test/token/AaveTokenWrapper.test.ts +++ b/packages/contracts/test/token/AaveTokenWrapper.test.ts @@ -10,18 +10,12 @@ const { BigNumber } = require('ethers'); const bne = (x, e) => BigNumber.from(x + '0'.repeat(parseInt(e))); // Convenience wrapper classes for contract classes -import { ERC20 as ERC20Class } from '@webb-tools/tokens'; -import { IERC20 } from '../../lib/IERC20'; -import { AaveTokenWrapper } from '../../lib/AaveTokenWrapper'; -import { AaveTokenWrapper__factory } from '../../lib/factories/AaveTokenWrapper__factory'; +import { AaveTokenWrapper, AaveTokenWrapper__factory, IERC20 } from '@webb-tools/contracts'; import { expect } from 'chai'; describe('AaveTokenWrapper', () => { - let token: ERC20Class; let aaveToken: AaveTokenWrapper; let sender: SignerWithAddress; - const tokenName = 'Token'; - const tokenSymbol = 'TKN'; const aaveTokenName = 'Wrapped Token'; const aaveTokenSymbol = 'wTKN'; const aaveLendingPoolAddress = '0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9'; diff --git a/packages/contracts/test/trees/MerkleForest.test.ts b/packages/contracts/test/trees/MerkleForest.test.ts index fb5f24e53..ea67d912a 100644 --- a/packages/contracts/test/trees/MerkleForest.test.ts +++ b/packages/contracts/test/trees/MerkleForest.test.ts @@ -6,13 +6,12 @@ import { toFixedHex } from '@webb-tools/sdk-core'; import { BigNumber } from 'ethers'; import { ethers } from 'hardhat'; -import { poseidon, poseidon_gencontract as poseidonContract } from 'circomlibjs'; +import { poseidon_gencontract as poseidonContract } from 'circomlibjs'; import { MerkleTree } from '@webb-tools/sdk-core'; import { PoseidonHasher } from '@webb-tools/anchors'; import { MerkleForestMock as MerkleForestMockContract, LinkableIncrementalBinaryTree as LinkableIncrementalBinaryTreeContract, - LinkableIncrementalBinaryTree__factory, } from '../../lib'; const TruffleAssert = require('truffle-assertions'); const assert = require('assert'); diff --git a/packages/contracts/test/vanchor/mocks/SetupTxVAnchorMock.ts b/packages/contracts/test/vanchor/mocks/SetupTxVAnchorMock.ts index dc9d93a64..4a3d42599 100644 --- a/packages/contracts/test/vanchor/mocks/SetupTxVAnchorMock.ts +++ b/packages/contracts/test/vanchor/mocks/SetupTxVAnchorMock.ts @@ -6,14 +6,12 @@ import { Utxo, CircomProvingManager, ProvingManagerSetupInput, - Note, - NoteGenInput, FIELD_SIZE, LeafIdentifier, } from '@webb-tools/sdk-core'; import { IVariableAnchorExtData, IVariableAnchorPublicInputs } from '@webb-tools/interfaces'; import { hexToU8a, u8aToHex, getChainIdType, ZkComponents } from '@webb-tools/utils'; -import { VAnchorTree as VAnchorContract } from '../../../typechain'; +import { VAnchorTree as VAnchorContract } from '@webb-tools/contracts'; export class SetupTxVAnchorMock extends VAnchor { private rootsForProof: BigNumber[]; diff --git a/packages/contracts/test/vanchor/vanchor.test.ts b/packages/contracts/test/vanchor/vanchor.test.ts index 2b204ee1b..ab5e8a0d3 100644 --- a/packages/contracts/test/vanchor/vanchor.test.ts +++ b/packages/contracts/test/vanchor/vanchor.test.ts @@ -39,10 +39,7 @@ import { } from '@webb-tools/sdk-core'; import { VAnchor, PoseidonHasher } from '@webb-tools/anchors'; import { Verifier } from '@webb-tools/vbridge'; -import { writeFileSync } from 'fs'; import { SetupTxVAnchorMock } from './mocks/SetupTxVAnchorMock'; -import { isTupleTypeNode } from 'typescript'; -import { TokenWrapper__factory } from 'packages/contracts/typechain'; const BN = require('bn.js'); diff --git a/packages/tokens/package.json b/packages/tokens/package.json index 74bf0d5be..807af1985 100644 --- a/packages/tokens/package.json +++ b/packages/tokens/package.json @@ -9,6 +9,7 @@ "compile": "tsc -p tsconfig.build.json" }, "dependencies": { + "@webb-tools/anchors": "^0.5.4", "@webb-tools/contracts": "^0.5.4", "@webb-tools/sdk-core": "0.1.4-119", "@webb-tools/utils": "^0.5.4", diff --git a/packages/tokens/src/FungibleTokenWrapper.ts b/packages/tokens/src/FungibleTokenWrapper.ts index dfe14ca7f..b71bd7ebd 100644 --- a/packages/tokens/src/FungibleTokenWrapper.ts +++ b/packages/tokens/src/FungibleTokenWrapper.ts @@ -6,6 +6,7 @@ import { FungibleTokenWrapper__factory, } from '@webb-tools/contracts'; import { assert } from 'chai'; +import { Deployer } from '@webb-tools/anchors'; export class FungibleTokenWrapper { contract: FungibleTokenWrapperContract; @@ -42,6 +43,37 @@ export class FungibleTokenWrapper { return tokenWrapper; } + public static async create2FungibleTokenWrapper( + name: string, + symbol: string, + feePercentage: number, + feeRecipient: string, + handler: string, + limit: string, + isNativeAllowed: boolean, + deployer: Deployer, + saltHex: string, + signer: ethers.Signer + ) { + assert(feePercentage <= 10_000, 'feePercentage should be less than 10_000'); + + const argTypes = ['string', 'string']; + const args = [name, symbol]; + const { contract: contract } = await deployer.deploy( + FungibleTokenWrapper__factory, + saltHex, + signer, + undefined, + argTypes, + args + ); + + // Initialize immediately after deployment as we use an intializer now + await contract.initialize(feePercentage, feeRecipient, handler, limit, isNativeAllowed); + const tokenWrapper = new FungibleTokenWrapper(contract, signer); + return tokenWrapper; + } + public static connect(address: string, signer: ethers.Signer) { const contract = FungibleTokenWrapper__factory.connect(address, signer); const tokenWrapper = new FungibleTokenWrapper(contract, signer); diff --git a/packages/tokens/src/TokenWrapperHandler.ts b/packages/tokens/src/TokenWrapperHandler.ts index 93e506431..8782bf950 100644 --- a/packages/tokens/src/TokenWrapperHandler.ts +++ b/packages/tokens/src/TokenWrapperHandler.ts @@ -3,6 +3,7 @@ import { TokenWrapperHandler as TokenWrapperHandlerContract, TokenWrapperHandler__factory, } from '@webb-tools/contracts'; +import { Deployer } from '@webb-tools/anchors'; export class TokenWrapperHandler { contract: TokenWrapperHandlerContract; @@ -25,6 +26,28 @@ export class TokenWrapperHandler { return handler; } + public static async create2TokenWrapperHandler( + bridgeAddress: string, + initResourceIds: string[], + initContractAddresses: string[], + deployer: Deployer, + saltHex: string, + signer: ethers.Signer + ) { + const argTypes = ['address', 'bytes32[]', 'address[]']; + const args = [bridgeAddress, initResourceIds, initContractAddresses]; + const { contract: contract } = await deployer.deploy( + TokenWrapperHandler__factory, + saltHex, + signer, + undefined, + argTypes, + args + ); + const handler = new TokenWrapperHandler(contract); + return handler; + } + public static async connect(handlerAddress: string, signer: ethers.Signer) { const handlerContract = TokenWrapperHandler__factory.connect(handlerAddress, signer); const handler = new TokenWrapperHandler(handlerContract); diff --git a/packages/tokens/src/Treasury.ts b/packages/tokens/src/Treasury.ts index 34a9d1bff..b3df257aa 100644 --- a/packages/tokens/src/Treasury.ts +++ b/packages/tokens/src/Treasury.ts @@ -2,6 +2,7 @@ import { BigNumber, ethers } from 'ethers'; import { getChainIdType } from '@webb-tools/utils'; import { toHex, generateFunctionSigHash, toFixedHex } from '@webb-tools/sdk-core'; import { Treasury as TreasuryContract, Treasury__factory } from '@webb-tools/contracts'; +import { Deployer } from '@webb-tools/anchors'; export class Treasury { contract: TreasuryContract; @@ -24,6 +25,27 @@ export class Treasury { return handler; } + public static async create2Treasury( + treasuryHandler: string, + deployer: Deployer, + saltHex: string, + signer: ethers.Signer + ) { + const argTypes = ['string']; + const args = [treasuryHandler]; + const { contract: contract } = await deployer.deploy( + Treasury__factory, + saltHex, + signer, + undefined, + argTypes, + args + ); + + const handler = new Treasury(contract, signer); + return handler; + } + public static connect(address: string, signer: ethers.Signer) { const contract = Treasury__factory.connect(address, signer); const treasury = new Treasury(contract, signer); diff --git a/packages/tokens/src/TreasuryHandler.ts b/packages/tokens/src/TreasuryHandler.ts index c15760f34..5adb82fc3 100644 --- a/packages/tokens/src/TreasuryHandler.ts +++ b/packages/tokens/src/TreasuryHandler.ts @@ -3,6 +3,7 @@ import { TreasuryHandler as TreasuryHandlerContract, TreasuryHandler__factory, } from '@webb-tools/contracts'; +import { Deployer } from '@webb-tools/anchors'; export class TreasuryHandler { contract: TreasuryHandlerContract; @@ -25,6 +26,28 @@ export class TreasuryHandler { return handler; } + public static async create2TreasuryHandler( + bridgeAddress: string, + initResourceIds: string[], + initContractAddresses: string[], + deployer: Deployer, + saltHex: string, + sender: ethers.Signer + ) { + const argTypes = ['address', 'bytes32[]', 'address[]']; + const args = [bridgeAddress, initResourceIds, initContractAddresses]; + const { contract: contract } = await deployer.deploy( + TreasuryHandler__factory, + saltHex, + sender, + undefined, + argTypes, + args + ); + const handler = new TreasuryHandler(contract); + return handler; + } + public static async connect(handlerAddress: string, signer: ethers.Signer) { const handlerContract = TreasuryHandler__factory.connect(handlerAddress, signer); const handler = new TreasuryHandler(handlerContract); diff --git a/scripts/evm/deployments/VBridge8Side.ts b/scripts/evm/deployments/VBridge8Side.ts index 57c8072ea..8f1f675cf 100644 --- a/scripts/evm/deployments/VBridge8Side.ts +++ b/scripts/evm/deployments/VBridge8Side.ts @@ -1,9 +1,8 @@ import { VBridge } from '@webb-tools/vbridge'; import { FungibleTokenWrapper } from '@webb-tools/tokens'; -import { fetchComponentsFromFilePaths } from '@webb-tools/utils'; +import { fetchComponentsFromFilePaths, getChainIdType } from '@webb-tools/utils'; import { DeployerConfig } from '@webb-tools/interfaces'; import path from 'path'; -import { ethers } from 'ethers'; import { chainIdTypeGoerli, chainIdTypeOptimism, @@ -23,7 +22,14 @@ import { walletDemeter, chainIdTypeSepolia, walletSepolia, -} from '../ethersGovernorWallets'; + chainIdTypeAurora, +} from "../ethersGovernorWallets"; +import { EvmLinkedAnchor, ProposalSigningBackend } from "@webb-tools/test-utils"; +import { ContractConfig, getEvmChainConfig, writeEvmChainConfig } from "./utils"; +import { zip } from 'itertools'; +import fs from 'fs'; +import { EndPointConfig, goerliEndPoints, moonbaseEndPoints, optimismEndPoints, polygonEndPoints, sepoliaEndPoints } from "./endPoints"; + async function deploySignatureVBridge( tokens: Record, @@ -94,42 +100,98 @@ async function deploySignatureVBridge( async function run() { const deployers: DeployerConfig = { - [chainIdTypeGoerli]: walletGoerli, - [chainIdTypeSepolia]: walletSepolia, - [chainIdTypeOptimism]: walletOptimism, + // [chainIdTypeGoerli]: walletGoerli, + // [chainIdTypeSepolia]: walletSepolia, + // [chainIdTypeOptimism]: walletOptimism, [chainIdTypePolygon]: walletPolygon, - [chainIdTypeMoonbase]: walletMoonbase, - [chainIdTypeArbitrum]: walletArbitrum, + // [chainIdTypeMoonbase]: walletMoonbase, + // [chainIdTypeArbitrum]: walletArbitrum, // [chainIdTypeHermes]: walletHermes, // [chainIdTypeAthena]: walletAthena, // [chainIdTypeDemeter]: walletDemeter }; const tokens: Record = { - [chainIdTypeGoerli]: ['0', '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6'], - [chainIdTypeSepolia]: ['0', '0xeD43f81C17976372Fcb5786Dd214572e7dbB92c7'], - [chainIdTypeOptimism]: ['0', '0x4200000000000000000000000000000000000006'], + // [chainIdTypeGoerli]: ['0', '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6'], + // [chainIdTypeSepolia]: ['0', '0xeD43f81C17976372Fcb5786Dd214572e7dbB92c7'], + // [chainIdTypeOptimism]: ['0', '0x4200000000000000000000000000000000000006'], [chainIdTypePolygon]: ['0x9c3C9283D3e44854697Cd22D3Faa240Cfb032889'], - [chainIdTypeMoonbase]: ['0xD909178CC99d318e4D46e7E66a972955859670E1'], - [chainIdTypeArbitrum]: ['0', '0xe39Ab88f8A4777030A534146A9Ca3B52bd5D43A3'], + // [chainIdTypeMoonbase]: ['0xD909178CC99d318e4D46e7E66a972955859670E1'], + // [chainIdTypeArbitrum]: ['0', '0xe39Ab88f8A4777030A534146A9Ca3B52bd5D43A3'], // [chainIdTypeHermes]: ['0'], // [chainIdTypeAthena]: ['0'], // [chainIdTypeDemeter]: ['0'] }; + + const endPoints: Record = { + // [chainIdTypeGoerli]: goerliEndPoints, + // [chainIdTypeSepolia]: sepoliaEndPoints, + // [chainIdTypeOptimism]: optimismEndPoints, + [chainIdTypePolygon]: polygonEndPoints, + // [chainIdTypeMoonbase]: moonbaseEndPoints, + } const vbridge = await deploySignatureVBridge(tokens, deployers); // print out all the info for the addresses const bridgeConfig = await vbridge.exportConfig(); - - for (const anchor of Array.from(bridgeConfig.vAnchors.values())) { + + const anchorIterable = bridgeConfig.vAnchors.values(); + const bridgeSideIterable = bridgeConfig.vBridgeSides.values(); + + for (const [anchor, bridgeSide] of zip(anchorIterable, bridgeSideIterable)){ const chainId = await anchor.signer.getChainId(); - console.log(`Anchor ${anchor.contract.address.toLowerCase()} for chain ${chainId}`); - } + const anchorContractConfig: ContractConfig = { + address: anchor.contract.address.toLowerCase(), + deployedAt: anchor.contract.deployTransaction.blockNumber + }; + const bridgeContractConfig: ContractConfig = { + address: bridgeSide.contract.address.toLowerCase(), + deployedAt: bridgeSide.contract.deployTransaction.blockNumber + } + const proposalSigningBackend : ProposalSigningBackend = { type: "DKGNode", node: "tangle" } + const linkedAnchors: EvmLinkedAnchor[] = []; + const typedChainId = getChainIdType(chainId); + const beneficiary = "0xf1fd5607b90f6c421db7313158baac170d4f053b"; // relayer wallet address + + // Add all other anchors to the list of linked anchors + for (const otherAnchor of Array.from(bridgeConfig.vAnchors.values())) { + if (otherAnchor !== anchor) { + linkedAnchors.push({ + chainId: (await otherAnchor.contract.getChainId()).toString(), + address: otherAnchor.contract.address.toLowerCase(), + type: "Evm" + }); + } + } + + const endPointConfig = endPoints[typedChainId]; + // construct chain configuration + const chainConfig = getEvmChainConfig( + chainId, + anchorContractConfig, + bridgeContractConfig, + deployers[typedChainId], + linkedAnchors, + proposalSigningBackend, + endPointConfig, + beneficiary + ); + + const configString = JSON.stringify(chainConfig, null, 2); + console.log(configString); + // convert config to kebab case and write to json file + const dirPath = `${__dirname}/relayer-config`; + writeEvmChainConfig(`${dirPath}/${endPointConfig.name}.toml`, chainConfig + ) - for (const bridgeSide of Array.from(bridgeConfig.vBridgeSides.values())) { - const chainId = await bridgeSide.admin.getChainId(); - console.log(`BridgeSide ${bridgeSide.contract.address.toLowerCase()} for chain ${chainId}`); + console.log( + `Anchor ${anchorContractConfig.address} deployed at: ${anchorContractConfig.deployedAt} for chainId ${chainId}` + ); + + console.log( + `BridgeSide ${bridgeContractConfig.address} deployed at: ${bridgeContractConfig.deployedAt} for chain ${chainId}` + ); } for (const webbToken of Array.from(bridgeConfig.webbTokenAddresses.entries())) { diff --git a/scripts/evm/deployments/create2/create2Bridge.ts b/scripts/evm/deployments/create2/create2Bridge.ts new file mode 100644 index 000000000..57eab20b6 --- /dev/null +++ b/scripts/evm/deployments/create2/create2Bridge.ts @@ -0,0 +1,341 @@ +import { ethers, BigNumber } from 'ethers'; +import { SignatureBridgeSide } from '@webb-tools/bridges'; +import { + FungibleTokenWrapper, + TreasuryHandler, + Treasury, + TokenWrapperHandler, +} from '@webb-tools/tokens'; +import { AnchorIdentifier, GovernorConfig, DeployerConfig } from '@webb-tools/interfaces'; +import { AnchorHandler, Deployer, PoseidonHasher, VAnchor } from '@webb-tools/anchors'; +import { getChainIdType, ZkComponents } from '@webb-tools/utils'; +import { Verifier } from '@webb-tools/vbridge'; +import { DeterministicDeployFactory__factory } from '@webb-tools/contracts'; + +export type ExistingAssetInput = { + // A record of chainId => address of wrappable tokens to be supported in the webbToken. + asset: Record; +}; + +// Users define an input for a completely new bridge +export type VBridgeInput = { + // The tokens which should be supported after deploying from this bridge input + vAnchorInputs: ExistingAssetInput; + + // The IDs of the chains to deploy to + chainIDs: number[]; + + // The number of max edges for vanchors, if not provided, maxEdges is derived from passed chainIDs. + maxEdges?: number; + + // Existing webb tokens can be connected + webbTokens: Map; +}; + +export type BridgeConfig = { + // The addresses of tokens available to be transferred over this bridge config + // chainId => FungibleTokenWrapperAddress + webbTokenAddresses: Map; + + // The addresses of the anchors for the FungibleTokenWrapper + // {anchorIdentifier} => anchorAddress + vAnchors: Map; + + // The addresses of the Bridge contracts (bridgeSides) to interact with + vBridgeSides: Map; +}; + +const zeroAddress = '0x0000000000000000000000000000000000000000'; + +function checkNativeAddress(tokenAddress: string): boolean { + if (tokenAddress === zeroAddress || tokenAddress === '0') { + return true; + } + return false; +} + +// A bridge is +export class Create2VBridge { + private constructor( + // Mapping of chainId => vBridgeSide + public vBridgeSides: Map, + + // chainID => FungibleTokenWrapper (webbToken) address + public webbTokenAddresses: Map, + + // Mapping of resourceID => linkedVAnchor[]; so we know which + // vanchors need updating when the anchor for resourceID changes state. + public linkedVAnchors: Map, + + // Mapping of anchorIdString => Anchor for easy anchor access + public vAnchors: Map + ) {} + + //might need some editing depending on whether anchor identifier structure changes + public static createVAnchorIdString(vAnchorIdentifier: AnchorIdentifier): string { + return `${vAnchorIdentifier.chainId.toString()}`; + } + + public static createVAnchorIdentifier(vAnchorString: string): AnchorIdentifier | null { + return { + chainId: Number(vAnchorString), + }; + } + + // Takes as input a 2D array [[anchors to link together], [...]] + // And returns a map of resourceID => linkedAnchor[] + public static async createLinkedVAnchorMap( + createdVAnchors: VAnchor[][] + ): Promise> { + let linkedVAnchorMap = new Map(); + for (let groupedVAnchors of createdVAnchors) { + for (let i = 0; i < groupedVAnchors.length; i++) { + // create the resourceID of this anchor + let resourceID = await groupedVAnchors[i].createResourceId(); + let linkedVAnchors = []; + for (let j = 0; j < groupedVAnchors.length; j++) { + if (i != j) { + linkedVAnchors.push(groupedVAnchors[j]); + } + } + // insert the linked anchors into the linked map + linkedVAnchorMap.set(resourceID, linkedVAnchors); + } + } + return linkedVAnchorMap; + } + + // Deployments of all contracts for the bridge will be done with the DeployerConfig. + // After deployments, the wallet in the DeployerConfig will transfer ownership + // to the initialGovernor + public static async deployVariableAnchorBridge( + vBridgeInput: VBridgeInput, + deployers: DeployerConfig, + initialGovernors: GovernorConfig, + smallCircuitZkComponents: ZkComponents, + largeCircuitZkComponents: ZkComponents + ): Promise { + const salt = '66756'; + const saltHex = ethers.utils.id(salt); + let webbTokenAddresses: Map = new Map(); + let vBridgeSides: Map = new Map(); + let vAnchors: Map = new Map(); + // createdAnchors have the form of [[Anchors created on chainID], [...]] + // and anchors in the subArrays of thhe same index should be linked together + let createdVAnchors: VAnchor[][] = []; + + // Determine the maxEdges for the anchors on this VBridge deployment + let maxEdges = vBridgeInput.maxEdges ?? vBridgeInput.chainIDs.length > 2 ? 7 : 1; + + for (let chainID of vBridgeInput.chainIDs) { + const initialGovernor = initialGovernors[chainID]; + // Create the bridgeSide + let deployer: Deployer; + const Deployer1 = new DeterministicDeployFactory__factory(deployers[chainID]); + let deployer1Contract = await Deployer1.deploy(); + await deployer1Contract.deployed(); + deployer = new Deployer(deployer1Contract); + let vBridgeInstance = await SignatureBridgeSide.create2BridgeSide(deployer, saltHex, deployers[chainID] ); + const handler = await AnchorHandler.create2AnchorHandler( + vBridgeInstance.contract.address, + [], + [], + deployer, + saltHex, + deployers[chainID] + ); + vBridgeInstance.setAnchorHandler(handler); + // Create Treasury and TreasuryHandler + const treasuryHandler = await TreasuryHandler.create2TreasuryHandler( + vBridgeInstance.contract.address, + [], + [], + deployer, + saltHex, + vBridgeInstance.admin + ); + const treasury = await Treasury.create2Treasury( + treasuryHandler.contract.address, + deployer, + saltHex, + vBridgeInstance.admin + ); + await vBridgeInstance.setTreasuryHandler(treasuryHandler); + await vBridgeInstance.setTreasuryResourceWithSignature(treasury); + // Create the Hasher and Verifier for the chain + const hasherInstance = await PoseidonHasher.create2PoseidonHasher(deployer, saltHex, deployers[chainID]); + const verifier = await Verifier.create2Verifier(deployer, saltHex, deployers[chainID]); + let verifierInstance = verifier.contract; + // Check the addresses of the asset. If it is zero, deploy a native token wrapper + let allowedNative: boolean = false; + for (const tokenToBeWrapped of vBridgeInput.vAnchorInputs.asset[chainID]!) { + // If passed '0' or zero address, token to be wrapped should support native. + if (checkNativeAddress(tokenToBeWrapped)) { + allowedNative = true; + } + } + + // Deploy TokenWrapperHandler + const tokenWrapperHandler = await TokenWrapperHandler.create2TokenWrapperHandler( + vBridgeInstance.contract.address, + [], + [], + deployer, + saltHex, + vBridgeInstance.admin + ); + let tokenInstance: FungibleTokenWrapper; + if (!vBridgeInput.webbTokens.get(chainID)) { + tokenInstance = await FungibleTokenWrapper.create2FungibleTokenWrapper( + `webbWETH`, + `webbWETH`, + 0, + treasury.contract.address, + tokenWrapperHandler.contract.address, + '10000000000000000000000000', + allowedNative, + deployer, + saltHex, + deployers[chainID] + ); + } else { + tokenInstance = vBridgeInput.webbTokens.get(chainID)!; + } + await vBridgeInstance.setTokenWrapperHandler(tokenWrapperHandler); + await vBridgeInstance.setFungibleTokenResourceWithSignature(tokenInstance); + // Add all token addresses to the governed token instance. + for (const tokenToBeWrapped of vBridgeInput.vAnchorInputs.asset[chainID]!) { + // if the address is not '0', then add it + if (!checkNativeAddress(tokenToBeWrapped)) { + await vBridgeInstance.executeAddTokenProposalWithSig(tokenInstance, tokenToBeWrapped); + } + } + // append each token + webbTokenAddresses.set(chainID, tokenInstance.contract.address); + + let chainGroupedVAnchors: VAnchor[] = []; + + // loop through all the anchor sizes on the token + const vAnchorInstance = await VAnchor.create2VAnchor( + deployer, + saltHex, + verifierInstance.address, + 30, + hasherInstance.contract.address, + handler.contract.address, + tokenInstance.contract.address, + maxEdges, + smallCircuitZkComponents, + largeCircuitZkComponents, + deployers[chainID] + ); + // grant minting rights to the anchor + await tokenInstance.grantMinterRole(vAnchorInstance.contract.address); + chainGroupedVAnchors.push(vAnchorInstance); + vAnchors.set(Create2VBridge.createVAnchorIdString({ chainId: chainID }), vAnchorInstance); + await Create2VBridge.setPermissions(vBridgeInstance, chainGroupedVAnchors); + createdVAnchors.push(chainGroupedVAnchors); + // Transfer ownership of the bridge to the initialGovernor + const tx = await vBridgeInstance.transferOwnership(initialGovernor, 0); + await tx.wait(); + vBridgeSides.set(chainID, vBridgeInstance); + } + + // All anchors created, massage data to group anchors which should be linked together + let groupLinkedVAnchors: VAnchor[][] = []; + + // all subarrays will have the same number of elements + for (let i = 0; i < createdVAnchors[0].length; i++) { + let linkedAnchors: VAnchor[] = []; + for (let j = 0; j < createdVAnchors.length; j++) { + linkedAnchors.push(createdVAnchors[j][i]); + } + groupLinkedVAnchors.push(linkedAnchors); + } + + // link the anchors + const linkedVAnchorMap = await Create2VBridge.createLinkedVAnchorMap(groupLinkedVAnchors); + + return new Create2VBridge(vBridgeSides, webbTokenAddresses, linkedVAnchorMap, vAnchors); + } + + // The setPermissions method accepts initialized bridgeSide and anchors. + // it creates the anchor handler and sets the appropriate permissions + // for the bridgeSide/anchorHandler/anchor + public static async setPermissions( + vBridgeSide: SignatureBridgeSide, + vAnchors: VAnchor[] + ): Promise { + let tokenDenomination = '1000000000000000000'; // 1 ether + for (let vAnchor of vAnchors) { + await vBridgeSide.connectAnchorWithSignature(vAnchor); + await vBridgeSide.executeMinWithdrawalLimitProposalWithSig( + vAnchor, + BigNumber.from(0).toString() + ); + await vBridgeSide.executeMaxDepositLimitProposalWithSig( + vAnchor, + BigNumber.from(tokenDenomination).mul(1_000_000).toString() + ); + } + } + + /** + * Updates the state of the BridgeSides and Anchors with + * the new state of the @param srcAnchor. + * @param srcAnchor The anchor that has updated. + * @returns + */ + public async updateLinkedVAnchors(srcAnchor: VAnchor) { + // Find the bridge sides that are connected to this Anchor + const linkedResourceID = await srcAnchor.createResourceId(); + const vAnchorsToUpdate = this.linkedVAnchors.get(linkedResourceID); + if (!vAnchorsToUpdate) { + return; + } + + // update the sides + for (let vAnchor of vAnchorsToUpdate) { + // get the bridge side which corresponds to this anchor + const chainId = getChainIdType(await vAnchor.signer.getChainId()); + const resourceID = await vAnchor.createResourceId(); + const vBridgeSide = this.vBridgeSides.get(chainId); + await vBridgeSide!.executeAnchorProposalWithSig(srcAnchor, resourceID); + } + } + + public async update(chainId: number) { + const vAnchor = this.getVAnchor(chainId); + if (!vAnchor) { + return; + } + await this.updateLinkedVAnchors(vAnchor); + } + + public getVBridgeSide(chainId: number) { + return this.vBridgeSides.get(chainId); + } + + public getVAnchor(chainId: number) { + let intendedAnchor: VAnchor = undefined; + intendedAnchor = this.vAnchors.get(Create2VBridge.createVAnchorIdString({ chainId })); + return intendedAnchor; + } + + // Returns the address of the webbToken which wraps the given token name. + public getWebbTokenAddress(chainId: number): string | undefined { + return this.webbTokenAddresses.get(chainId); + } + + public exportConfig(): BridgeConfig { + return { + webbTokenAddresses: this.webbTokenAddresses, + vAnchors: this.vAnchors, + vBridgeSides: this.vBridgeSides, + }; + } + + +} + +export default Create2VBridge; diff --git a/scripts/evm/deployments/create2/deploymentScript.ts b/scripts/evm/deployments/create2/deploymentScript.ts new file mode 100644 index 000000000..ef7f0fd82 --- /dev/null +++ b/scripts/evm/deployments/create2/deploymentScript.ts @@ -0,0 +1,199 @@ +import { FungibleTokenWrapper } from "@webb-tools/tokens"; +import { fetchComponentsFromFilePaths, getChainIdType } from "@webb-tools/utils"; +import { DeployerConfig } from "@webb-tools/interfaces"; +import path from "path"; +import { ethers } from "ethers"; +import { + chainIdTypeGoerli, + chainIdTypeOptimism, + chainIdTypeArbitrum, + chainIdTypePolygon, + chainIdTypeMoonbase, + walletGoerli, + walletOptimism, + walletArbitrum, + walletPolygon, + walletMoonbase, + chainIdTypeHermes, + chainIdTypeAthena, + chainIdTypeDemeter, + walletHermes, + walletAthena, + walletDemeter, + chainIdTypeSepolia, + walletSepolia, + chainIdTypeAurora, +} from "../../ethersGovernorWallets"; +import { EvmLinkedAnchor, ProposalSigningBackend } from "@webb-tools/test-utils"; +import { ContractConfig, getEvmChainConfig, writeEvmChainConfig } from "../utils"; +import { zip } from 'itertools'; +import { EndPointConfig, moonbaseEndPoints, polygonEndPoints, sepoliaEndPoints } from "../endPoints"; +import Create2VBridge from "./create2Bridge"; + + +async function deploySignatureVBridge( + tokens: Record, + deployers: DeployerConfig +): Promise { + let assetRecord: Record = {}; + let chainIdsArray: number[] = []; + let existingWebbTokens = new Map(); + let governorConfig: Record = {}; + + for (const chainIdType of Object.keys(deployers)) { + assetRecord[chainIdType] = tokens[chainIdType]; + chainIdsArray.push(Number(chainIdType)); + governorConfig[Number(chainIdType)] = await deployers[ + chainIdType + ].getAddress(); + existingWebbTokens[chainIdType] = null; + console.log(tokens[chainIdType]); + } + + const bridgeInput = { + vAnchorInputs: { + asset: assetRecord, + }, + chainIDs: chainIdsArray, + webbTokens: existingWebbTokens, + }; + + console.log(bridgeInput); + + const zkComponentsSmall = await fetchComponentsFromFilePaths( + path.resolve( + __dirname, + `../../../../solidity-fixtures/solidity-fixtures/vanchor_2/8/poseidon_vanchor_2_8.wasm` + ), + path.resolve( + __dirname, + `../../../../solidity-fixtures/solidity-fixtures/vanchor_2/8/witness_calculator.cjs` + ), + path.resolve( + __dirname, + `../../../../solidity-fixtures/solidity-fixtures/vanchor_2/8/circuit_final.zkey` + ) + ); + const zkComponentsLarge = await fetchComponentsFromFilePaths( + path.resolve( + __dirname, + `../../../../solidity-fixtures/solidity-fixtures/vanchor_16/8/poseidon_vanchor_16_8.wasm` + ), + path.resolve( + __dirname, + `../../../../solidity-fixtures/solidity-fixtures/vanchor_16/8/witness_calculator.cjs` + ), + path.resolve( + __dirname, + `../../../../solidity-fixtures/solidity-fixtures/vanchor_16/8/circuit_final.zkey` + ) + ); + + console.log(governorConfig); + + return Create2VBridge.deployVariableAnchorBridge( + bridgeInput, + deployers, + governorConfig, + zkComponentsSmall, + zkComponentsLarge + ); +} + +async function run() { + const deployers: DeployerConfig = { + // [chainIdTypeGoerli]: walletGoerli, + [chainIdTypeSepolia]: walletSepolia, + // [chainIdTypeOptimism]: walletOptimism, + // [chainIdTypePolygon]: walletPolygon, + // [chainIdTypeMoonbase]: walletMoonbase, + }; + + const tokens: Record = { + // [chainIdTypeGoerli]: ["0", ""], + [chainIdTypeSepolia]: ["0", "0xeD43f81C17976372Fcb5786Dd214572e7dbB92c7"], + // [chainIdTypeOptimism]: ["0", "0x4200000000000000000000000000000000000006"], + // [chainIdTypePolygon]: ["0x9c3C9283D3e44854697Cd22D3Faa240Cfb032889"], + // [chainIdTypeMoonbase]: ["0xD909178CC99d318e4D46e7E66a972955859670E1"], + }; + + const endPoints: Record = { + // [chainIdTypeGoerli]: goerliEndPoints, + [chainIdTypeSepolia]: sepoliaEndPoints, + // [chainIdTypeOptimism]: optimismEndPoints, + // [chainIdTypePolygon]: polygonEndPoints, + // [chainIdTypeMoonbase]: moonbaseEndPoints, + } + + const vbridge = await deploySignatureVBridge(tokens, deployers); + + // print out all the info for the addresses + const bridgeConfig = await vbridge.exportConfig(); + + const anchorIterable = bridgeConfig.vAnchors.values(); + const bridgeSideIterable = bridgeConfig.vBridgeSides.values(); + + + for (const [anchor, bridgeSide] of zip(anchorIterable, bridgeSideIterable)){ + const chainId = await anchor.signer.getChainId(); + const anchorContractConfig: ContractConfig = { + address: anchor.contract.address.toLowerCase(), + deployedAt: anchor.contract.deployTransaction.blockNumber + }; + const bridgeContractConfig: ContractConfig = { + address: bridgeSide.contract.address.toLowerCase(), + deployedAt: bridgeSide.contract.deployTransaction.blockNumber + } + const proposalSigningBackend : ProposalSigningBackend = { type: "DKGNode", node: "tangle" } + const linkedAnchors: EvmLinkedAnchor[] = []; + const typedChainId = getChainIdType(chainId); + const beneficiary = "0xf1fd5607b90f6c421db7313158baac170d4f053b"; // relayer wallet address + + // Add all other anchors to the list of linked anchors + for (const otherAnchor of Array.from(bridgeConfig.vAnchors.values())) { + if (otherAnchor !== anchor) { + linkedAnchors.push({ + chainId: (await otherAnchor.contract.getChainId()).toString(), + address: otherAnchor.contract.address.toLowerCase(), + type: "Evm" + }); + } + } + + const endPointConfig = endPoints[typedChainId]; + // construct chain configuration + const chainConfig = getEvmChainConfig( + chainId, + anchorContractConfig, + bridgeContractConfig, + deployers[typedChainId], + linkedAnchors, + proposalSigningBackend, + endPointConfig, + beneficiary + ); + + // convert config to kebab case and write to json file + const dirPath = `${__dirname}/relayer-config`; + writeEvmChainConfig(`${dirPath}/${endPointConfig.name}.toml`, chainConfig + ) + + console.log( + `Anchor ${anchorContractConfig.address} deployed at: ${anchorContractConfig.deployedAt} for chainId ${chainId}` + ); + + console.log( + `BridgeSide ${bridgeContractConfig.address} deployed at: ${bridgeContractConfig.deployedAt} for chain ${chainId}` + ); + } + + for (const webbToken of Array.from( + bridgeConfig.webbTokenAddresses.entries() + )) { + console.log( + `webbToken entry: ${webbToken[0]} + ${webbToken[1].toLowerCase()}` + ); + } +} + +run(); diff --git a/scripts/evm/deployments/endPoints.ts b/scripts/evm/deployments/endPoints.ts new file mode 100644 index 000000000..ac676b805 --- /dev/null +++ b/scripts/evm/deployments/endPoints.ts @@ -0,0 +1,37 @@ +export type EndPointConfig = { + httpEndpoint: string, + wsEndpoint: string, + name: string + } + +export const polygonEndPoints: EndPointConfig = { + httpEndpoint: process.env.MUMBAI_TESTNET_HTTPS_URL!, + wsEndpoint: process.env.MUMBAI_TESTNET_WSS_URL!, + name: "mumbai" +}; + +export const sepoliaEndPoints: EndPointConfig = { + httpEndpoint: process.env.SEPOLIA_HTTPS_URL!, + wsEndpoint: process.env.SEPOLIA_WSS_URL!, + name: "sepolia" +}; + +export const optimismEndPoints: EndPointConfig = { + httpEndpoint: process.env.OPTIMISM_TESTNET_HTTPS_URL!, + wsEndpoint: process.env.OPTIMISM_TESTNET_WSS_URL!, + name: "optimism" +}; + +export const moonbaseEndPoints: EndPointConfig = { + httpEndpoint: process.env.MOONBASE_HTTPS_URL!, + wsEndpoint: process.env.MOONBASE_WSS_URL!, + name: "moonbase" +}; + +export const goerliEndPoints: EndPointConfig = { + httpEndpoint: process.env.GOERLI_HTTPS_URL!, + wsEndpoint: process.env.GOERLI_WSS_URL!, + name: "goerli" +}; + + diff --git a/scripts/evm/deployments/relayer-config/moonbase.toml b/scripts/evm/deployments/relayer-config/moonbase.toml new file mode 100644 index 000000000..cb2c9865d --- /dev/null +++ b/scripts/evm/deployments/relayer-config/moonbase.toml @@ -0,0 +1,40 @@ +[evm] + +[evm.moonbase] +beneficiary = "0xf1fd5607b90f6c421db7313158baac170d4f053b" +block-confirmations = 0.0 +chain-id = 1287.0 +enabled = true +name = "moonbase" +private-key = "0xc086596a698603ae7428a61ced569cbc5fdc24ae91c341d692aad590febc4429" + +[[evm.moonbase.contracts]] +address = "0x57f608d6561f0e354026f17f492c57311fd8080f" +contract = "VAnchor" + +[evm.moonbase.contracts.events-watcher] +enabled = true +polling-interval = 1000.0 +print-progress-interval = 7000.0 + +[[evm.moonbase.contracts.linked-anchors]] +address = "0x2552f59ff85602bff8043ca6ef94b1cbb14dc2c6" +chain-id = "80001" +type = "Evm" + +[evm.moonbase.contracts.proposal-signing-backend] +node = "tangle" +type = "DKGNode" + +[evm.moonbase.contracts.withdraw-config] +withdraw-fee-percentage = 0.0 +withdraw-gaslimit = "0x5B8D80" + +[[evm.moonbase.contracts]] +address = "0x12cec77a5ac7108ae453a7aeb6a31afc2b6f0bd8" +contract = "SignatureBridge" + +[evm.moonbase.contracts.events-watcher] +enabled = true +polling-interval = 1000.0 +print-progress-interval = 7000.0 \ No newline at end of file diff --git a/scripts/evm/deployments/relayer-config/mumbai.toml b/scripts/evm/deployments/relayer-config/mumbai.toml new file mode 100644 index 000000000..59bfd75ff --- /dev/null +++ b/scripts/evm/deployments/relayer-config/mumbai.toml @@ -0,0 +1,40 @@ +[evm] + +[evm.mumbai] +beneficiary = "0xf1fd5607b90f6c421db7313158baac170d4f053b" +block-confirmations = 0.0 +chain-id = 80001.0 +enabled = true +name = "mumbai" +private-key = "0xc086596a698603ae7428a61ced569cbc5fdc24ae91c341d692aad590febc4429" + +[[evm.mumbai.contracts]] +address = "0x2552f59ff85602bff8043ca6ef94b1cbb14dc2c6" +contract = "VAnchor" + +[evm.mumbai.contracts.events-watcher] +enabled = true +polling-interval = 1000.0 +print-progress-interval = 7000.0 + +[[evm.mumbai.contracts.linked-anchors]] +address = "0x57f608d6561f0e354026f17f492c57311fd8080f" +chain-id = "1287" +type = "Evm" + +[evm.mumbai.contracts.proposal-signing-backend] +node = "tangle" +type = "DKGNode" + +[evm.mumbai.contracts.withdraw-config] +withdraw-fee-percentage = 0.0 +withdraw-gaslimit = "0x5B8D80" + +[[evm.mumbai.contracts]] +address = "0xca216c5dee21f69ff8ebaa32b26b0165bcd7d9c0" +contract = "SignatureBridge" + +[evm.mumbai.contracts.events-watcher] +enabled = true +polling-interval = 1000.0 +print-progress-interval = 7000.0 \ No newline at end of file diff --git a/scripts/evm/deployments/utils.ts b/scripts/evm/deployments/utils.ts new file mode 100644 index 000000000..a4cbe7b54 --- /dev/null +++ b/scripts/evm/deployments/utils.ts @@ -0,0 +1,174 @@ +import fs from 'fs'; +import { Contract, ConvertToKebabCase, EventsWatcher, FullChainInfo, LinkedAnchor, ProposalSigningBackend, WithdrawConfig } from "@webb-tools/test-utils"; +import { EndPointConfig } from "./endPoints"; +import { Wallet } from 'ethers'; +import { toToml } from 'tomlify-j0.4'; + +// Default WithdrawlConfig for the contracts. +const defaultWithdrawConfigValue: WithdrawConfig = { + withdrawGaslimit: '0x5B8D80', + withdrawFeePercentage: 0, +}; + +// Default Event watcher config. +const defaultEventWatcherConfigValue: EventsWatcher = { + enabled: true, + pollingInterval: 1000, + printProgressInterval: 7000, +}; + +export type ContractConfig = { + address: string, + deployedAt: number, +}; + +export function getEvmChainConfig( + chainId: number, + anchor: ContractConfig, + bridge: ContractConfig, + deployerWallet: Wallet, + linkedAnchors: LinkedAnchor[], + proposalSigningBackend: ProposalSigningBackend, + endpoint: EndPointConfig, + beneficiary?: string + ): FullChainInfo{ + + const contracts: Contract[] = [ + // first the local Anchor + { + contract: 'VAnchor', + address: anchor.address, + deployedAt: anchor.deployedAt, + size: 1, // Ethers + proposalSigningBackend: proposalSigningBackend, + withdrawConfig: defaultWithdrawConfigValue, + eventsWatcher: defaultEventWatcherConfigValue, + linkedAnchors: linkedAnchors, + }, + { + contract: 'SignatureBridge', + address: bridge.address, + deployedAt: bridge.deployedAt, + eventsWatcher: defaultEventWatcherConfigValue + }, + ]; + const chainInfo: FullChainInfo = { + name: endpoint.name, + enabled: true, + httpEndpoint: endpoint.httpEndpoint, + wsEndpoint: endpoint.wsEndpoint, + blockConfirmations: 0, + chainId: chainId, + beneficiary: beneficiary ?? '', + privateKey: deployerWallet.privateKey, + contracts: contracts, + }; + return chainInfo; +} + + +export function writeEvmChainConfig ( + path: string, + config: FullChainInfo +) { + type ConvertedLinkedAnchor = ConvertToKebabCase; + type ConvertedContract = Omit< + ConvertToKebabCase, + | 'events-watcher' + | 'proposal-signing-backend' + | 'withdraw-config' + | 'linked-anchors' + | 'deployed-at' + > & { + 'events-watcher': ConvertToKebabCase; + 'proposal-signing-backend'?: ConvertToKebabCase; + 'withdraw-config'?: ConvertToKebabCase; + 'linked-anchors'?: ConvertedLinkedAnchor[]; + }; + type ConvertedConfig = Omit< + ConvertToKebabCase, + 'contracts' + > & { + contracts: ConvertedContract[]; + }; + type FullConfigFile = { + evm: { + // chainId as the chain identifier + [key: number]: ConvertedConfig; + }; + }; + + const convertedConfig: ConvertedConfig = { + beneficiary: config.beneficiary, + 'block-confirmations': config.blockConfirmations, + 'chain-id': config.chainId, + contracts: config.contracts.map((contract) => ({ + address: contract.address, + contract: contract.contract, + 'deployed-at': contract.deployedAt, + 'events-watcher': { + enabled: contract.eventsWatcher.enabled, + 'polling-interval': contract.eventsWatcher.pollingInterval, + 'print-progress-interval': + contract.eventsWatcher.printProgressInterval + }, + 'linked-anchors': contract?.linkedAnchors?.map((anchor: LinkedAnchor) => + anchor.type === 'Evm' + ? { + address: anchor.address, + 'chain-id': anchor.chainId, + type: 'Evm' + } + : anchor.type === 'Substrate' + ? { + 'chain-id': anchor.chainId, + pallet: anchor.pallet, + 'tree-id': anchor.treeId, + type: 'Substrate' + + } + : { + 'resource-id': anchor.resourceId, + type: 'Raw' + } + ), + 'proposal-signing-backend': + contract.proposalSigningBackend?.type === 'Mocked' + ? { + 'private-key': contract.proposalSigningBackend?.privateKey, + type: 'Mocked' + } + : contract.proposalSigningBackend?.type === 'DKGNode' + ? { + node: contract.proposalSigningBackend?.node, + type: 'DKGNode' + } + : undefined, + 'withdraw-config': contract.withdrawConfig + ? { + 'withdraw-fee-percentage': + contract.withdrawConfig?.withdrawFeePercentage, + 'withdraw-gaslimit': contract.withdrawConfig?.withdrawGaslimit + } + : undefined + })), + enabled: config.enabled, + 'http-endpoint': config.httpEndpoint, + name: config.name, + 'private-key': config.privateKey, + 'ws-endpoint': config.wsEndpoint + }; + const fullConfigFile: FullConfigFile = { + evm: { + [config.name]: convertedConfig + } + }; + + const toml = toToml(fullConfigFile, { spaces: 4 }); + + // Write the TOML string to a file + fs.writeFileSync(path, toml); + +} + + diff --git a/scripts/evm/ethersGovernorWallets.ts b/scripts/evm/ethersGovernorWallets.ts index 8f25e0380..1a1728b9b 100644 --- a/scripts/evm/ethersGovernorWallets.ts +++ b/scripts/evm/ethersGovernorWallets.ts @@ -9,7 +9,10 @@ export const chainIdTypePolygon = getChainIdType(80001); export const providerGoerli = new ethers.providers.JsonRpcProvider( `https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161` ); -export const walletGoerli = new ethers.Wallet(process.env.PRIVATE_KEY!, providerGoerli); +export const walletGoerli = new ethers.Wallet( + process.env.PRIVATE_KEY!, + providerGoerli +); export const chainIdTypeGoerli = getChainIdType(5); export const providerSepolia = new ethers.providers.JsonRpcProvider(`https://rpc.sepolia.org`); diff --git a/tsconfig.json b/tsconfig.json index 9ea6e3462..116734619 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,10 +22,10 @@ "packages/evm-test-utils/src/*" ], "@webb-tools/contracts": [ - "packages/contracts/typechain" + "packages/contracts/src" ], "@webb-tools/contracts/*": [ - "packages/contracts/typechain/*" + "packages/contracts/src/*" ], "@webb-tools/interfaces": [ "packages/interfaces/src" diff --git a/yarn.lock b/yarn.lock index 690e1ae3c..3ee402c1e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -993,7 +993,7 @@ pirates "^4.0.5" source-map-support "^0.5.16" -"@babel/runtime@^7.18.9", "@babel/runtime@^7.19.0", "@babel/runtime@^7.20.6", "@babel/runtime@^7.20.7", "@babel/runtime@^7.4.4", "@babel/runtime@^7.8.4": +"@babel/runtime@^7.15.4", "@babel/runtime@^7.18.9", "@babel/runtime@^7.19.0", "@babel/runtime@^7.20.6", "@babel/runtime@^7.20.7", "@babel/runtime@^7.4.4", "@babel/runtime@^7.8.4": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.7.tgz#fcb41a5a70550e04a7b708037c7c32f7f356d8fd" integrity sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ== @@ -12754,6 +12754,13 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" +itertools@^1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/itertools/-/itertools-1.7.1.tgz#39fb110782b7f57b9c14782c25fe35bd3997d4fc" + integrity sha512-0sC8t0HYOH0wb/mU5eLmp2g19yfhqho12Q6kCX6MGkNEEJQz97LIXzZ2bbIDyzBnQGcMixmcAtByzKjiaFkw8Q== + dependencies: + "@babel/runtime" "^7.15.4" + jake@^10.8.5: version "10.8.5" resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.5.tgz#f2183d2c59382cb274226034543b9c03b8164c46" @@ -18525,6 +18532,11 @@ toidentifier@1.0.1: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== +tomlify-j0.4@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/tomlify-j0.4/-/tomlify-j0.4-3.0.0.tgz#99414d45268c3a3b8bf38be82145b7bba34b7473" + integrity sha512-2Ulkc8T7mXJ2l0W476YC/A209PR38Nw8PuaCNtk9uI3t1zzFdGQeWYGQvmj2PZkVvRC/Yoi4xQKMRnWc/N29tQ== + tough-cookie@^2.3.3, tough-cookie@~2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"