Adds VAA self signing logic and updates implementation addresses (#42)
* evm: remove obsolete packages. * evm: fixes shebang for shell scripts. * evm: forward arguments in deploy shell scripts. * evm: adjustments in `tsconfig.json` * evm: adds script to self sign testnet upgrade. * evm: yarn.lock update * evm: Adds registrations to circle integration initializer temporarily. * evm: fixes env var for RPC URLs * evm: rename environment files. * evm: adds RPC URLs for arbitrum and eth testnets * evm: updates the CircleIntegration implementation addresses. * evm: switches to ESM. * evm: yarn.lock update * evm: reverts testnet hardcoded cross registrations. * evm: removes `ts-node` in favour of `tsx` * minor fixes to submit_testnet_registraion script * adds base deployment configuration * fix env variable on base mainnet deployment * base mainnet configuration --------- Co-authored-by: solanoe <solanoepalacio@gmail.com>
This commit is contained in:
parent
2e0831c6c1
commit
105ad59bad
|
@ -34,7 +34,7 @@ Then run the following command to deploy (and set up) the proxy contract:
|
|||
|
||||
```
|
||||
# sample deployment command
|
||||
. env/put_your_env_file_here.env && PRIVATE_KEY=put_your_private_key_here bash shell-scripts/deploy_contracts.sh
|
||||
. env/put_your_env_file_here.env && shell-scripts/deploy_contracts.sh --private-key put_your_private_key_here
|
||||
```
|
||||
|
||||
## Test Suite
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
export CONFIGURE_CCTP_RPC="https://base.publicnode.com"
|
||||
|
||||
### Contract addresses
|
||||
export RELEASE_WORMHOLE_ADDRESS=0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6
|
||||
export RELEASE_CIRCLE_BRIDGE_ADDRESS=0x1682Ae6375C4E4A97e4B583BC394c861A46D8962 # token messenger
|
||||
export RELEASE_WORMHOLE_FINALITY=1
|
||||
|
||||
### Deployed Circle Integration addresses
|
||||
export CIRCLE_INTEGRATION_IMPLEMENTATION="0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c"
|
||||
export CIRCLE_INTEGRATION_SETUP="0xD73aFD826D6bDD4D2fEF326DF5091451A5d8130a"
|
||||
export CIRCLE_INTEGRATION_PROXY="0x03faBB06Fa052557143dC28eFCFc63FC12843f1D"
|
||||
|
||||
# Used in verification scripts
|
||||
export RELEASE_EVM_CHAIN_ID=8453
|
|
@ -1,4 +1,4 @@
|
|||
export RPC=""
|
||||
export CONFIGURE_CCTP_RPC="https://goerli-rollup.arbitrum.io/rpc"
|
||||
|
||||
### Contract addresses
|
||||
export RELEASE_WORMHOLE_ADDRESS=0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e
|
||||
|
@ -6,7 +6,7 @@ export RELEASE_CIRCLE_BRIDGE_ADDRESS=0x12dcfd3fe2e9eac2859fd1ed86d2ab8c5a2f9352
|
|||
export RELEASE_WORMHOLE_FINALITY=1
|
||||
|
||||
### Deployed Circle Integration addresses
|
||||
export CIRCLE_INTEGRATION_IMPLEMENTATION=0xa098368aaadc0fdf3e309cda710d7a5f8bdeecd9
|
||||
export CIRCLE_INTEGRATION_IMPLEMENTATION=0xD73aFD826D6bDD4D2fEF326DF5091451A5d8130a
|
||||
export CIRCLE_INTEGRATION_SETUP=0xb0a9feeaf74f2e8e2966bf774466ca3575ec8a6d
|
||||
export CIRCLE_INTEGRATION_PROXY=0x2E8F5E00a9C5D450A72700546B89E2b70DfB00f2
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
export RPC="https://api.avax-test.network/ext/bc/C/rpc"
|
||||
export CONFIGURE_CCTP_RPC="https://api.avax-test.network/ext/bc/C/rpc"
|
||||
|
||||
### Contract addresses
|
||||
export RELEASE_WORMHOLE_ADDRESS=0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C
|
||||
|
@ -6,7 +6,7 @@ export RELEASE_CIRCLE_BRIDGE_ADDRESS=0xeb08f243e5d3fcff26a9e38ae5520a669f4019d0
|
|||
export RELEASE_WORMHOLE_FINALITY=1
|
||||
|
||||
### Deployed Circle Integration addresses
|
||||
export CIRCLE_INTEGRATION_IMPLEMENTATION=0xf0ff9898918351148ffd97c7ddb412086505eae1
|
||||
export CIRCLE_INTEGRATION_IMPLEMENTATION=0xD73aFD826D6bDD4D2fEF326DF5091451A5d8130a
|
||||
export CIRCLE_INTEGRATION_SETUP=0xd66a83c1cd3cf85a071daa6a4bcbea32e22931c0
|
||||
export CIRCLE_INTEGRATION_PROXY=0x58f4c17449c90665891c42e14d34aae7a26a472e
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
export CONFIGURE_CCTP_RPC="https://goerli.base.org"
|
||||
|
||||
### Contract addresses
|
||||
export RELEASE_WORMHOLE_ADDRESS=0x23908A62110e21C04F3A4e011d24F901F911744A
|
||||
export RELEASE_CIRCLE_BRIDGE_ADDRESS=0x877b8e8c9e2383077809787ED6F279ce01CB4cc8
|
||||
export RELEASE_WORMHOLE_FINALITY=1
|
||||
|
||||
|
||||
### Deployed Circle Integration addresses
|
||||
export CIRCLE_INTEGRATION_IMPLEMENTATION=0xD73aFD826D6bDD4D2fEF326DF5091451A5d8130a
|
||||
export CIRCLE_INTEGRATION_SETUP=0xC5180b274Ead8aC34131B6dDa0323e403d671De7
|
||||
export CIRCLE_INTEGRATION_PROXY=0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c
|
||||
|
||||
# Used in verification scripts
|
||||
export RELEASE_EVM_CHAIN_ID=84531
|
|
@ -1,4 +1,4 @@
|
|||
export RPC=""
|
||||
export CONFIGURE_CCTP_RPC="https://rpc.ankr.com/eth_goerli"
|
||||
|
||||
### Contract addresses
|
||||
export RELEASE_WORMHOLE_ADDRESS=0x706abc4E45D419950511e474C7B9Ed348A4a716c
|
||||
|
@ -6,7 +6,7 @@ export RELEASE_CIRCLE_BRIDGE_ADDRESS=0xd0c3da58f55358142b8d3e06c1c30c5c6114efe8
|
|||
export RELEASE_WORMHOLE_FINALITY=200
|
||||
|
||||
### Deployed Circle Integration addresses
|
||||
export CIRCLE_INTEGRATION_IMPLEMENTATION=0x4fa4b2c3744b29D0e4F1AaFE8B758F953FaCf1A4
|
||||
export CIRCLE_INTEGRATION_IMPLEMENTATION=0xD73aFD826D6bDD4D2fEF326DF5091451A5d8130a
|
||||
export CIRCLE_INTEGRATION_SETUP=0xB9aCd3891EBf91EC09cfe337EE5A8EEfF4317846
|
||||
export CIRCLE_INTEGRATION_PROXY=0x0a69146716b3a21622287efa1607424c663069a4
|
||||
|
|
@ -1,13 +1,12 @@
|
|||
export RPC="https://goerli.optimism.io"
|
||||
export CONFIGURE_CCTP_RPC="https://rpc.goerli.optimism.gateway.fm"
|
||||
|
||||
### Contract addresses
|
||||
export RELEASE_WORMHOLE_ADDRESS=0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35
|
||||
export RELEASE_CIRCLE_BRIDGE_ADDRESS=0x23a04d5935ed8bc8e3eb78db3541f0abfb001c6e
|
||||
export RELEASE_WORMHOLE_FINALITY=1
|
||||
|
||||
|
||||
### Deployed Circle Integration addresses
|
||||
export CIRCLE_INTEGRATION_IMPLEMENTATION=0xD73aFD826D6bDD4D2fEF326DF5091451A5d8130a
|
||||
export CIRCLE_INTEGRATION_IMPLEMENTATION=0xD4Bab83eDe934973d22f1da04819fe2E5b5a9Ef4
|
||||
export CIRCLE_INTEGRATION_SETUP=0xC5180b274Ead8aC34131B6dDa0323e403d671De7
|
||||
export CIRCLE_INTEGRATION_PROXY=0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c
|
||||
|
|
@ -3,29 +3,28 @@
|
|||
"version": "0.1.0",
|
||||
"main": "index.js",
|
||||
"license": "ISC",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.11.17",
|
||||
"chai": "^4.3.6",
|
||||
"ethers": "^5.7.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certusone/wormhole-sdk": "^0.9.0",
|
||||
"@improbable-eng/grpc-web-node-http-transport": "^0.15.0",
|
||||
"@openzeppelin/contracts": "^4.7.3",
|
||||
"@typechain/ethers-v5": "^10.1.1",
|
||||
"@types/argparse": "^2.0.10",
|
||||
"@types/chai": "^4.3.3",
|
||||
"@types/mocha": "^9.1.1",
|
||||
"argparse": "^2.0.1",
|
||||
"axios": "^1.1.3",
|
||||
"dotenv": "^16.0.3",
|
||||
"elliptic": "^6.5.4",
|
||||
"express": "^4.18.2",
|
||||
"@types/node": "^20.0.0",
|
||||
"@types/yargs": "^17.0.24",
|
||||
"chai": "^4.3.6",
|
||||
"mocha": "^10.0.0",
|
||||
"ts-mocha": "^10.0.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typechain": "^8.1.1",
|
||||
"typescript": "^4.8.3"
|
||||
"tsx": "^3.13.0",
|
||||
"typescript": "^5.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certusone/wormhole-sdk": "^0.10.3",
|
||||
"@noble/secp256k1": "^2.0.0",
|
||||
"@openzeppelin/contracts": "^4.7.3",
|
||||
"@typechain/ethers-v5": "^11.1.1",
|
||||
"@xlabs-xyz/ledger-signer": "0.0.3",
|
||||
"dotenv": "^16.0.3",
|
||||
"ethers": "^5.7.1",
|
||||
"typechain": "^8.3.1",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"scripts": {
|
||||
"build-types": "bash shell-scripts/make_ethers_types.sh",
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
forge script $(dirname $0)/../forge-scripts/deploy_contracts.sol \
|
||||
--rpc-url $RPC \
|
||||
--private-key $PRIVATE_KEY \
|
||||
--broadcast --slow
|
||||
--rpc-url $CONFIGURE_CCTP_RPC \
|
||||
--broadcast --slow $@
|
|
@ -1,9 +1,8 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
forge script $(dirname $0)/../forge-scripts/deploy_implementation_only.sol \
|
||||
-vv \
|
||||
--rpc-url $RPC \
|
||||
--private-key $PRIVATE_KEY \
|
||||
--broadcast --slow
|
||||
--rpc-url $CONFIGURE_CCTP_RPC \
|
||||
--broadcast --slow $@
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
SRC=$(dirname $0)/../out
|
||||
DST=$(dirname $0)/../ts/src/ethers-contracts
|
||||
|
||||
typechain --target=ethers-v5 --out-dir=$DST $SRC/*/*.json
|
||||
typechain --target=ethers-v5 --node16-modules --out-dir=$DST $SRC/*/*.json
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
pgrep anvil > /dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Usage: ./submit_testnet_registration <target chain> <foreign chain> <foreign emitter> <foreign domain> <forge script args (keys)>
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
|
@ -8,8 +10,9 @@ export FOREIGN_EMITTER=$3
|
|||
export FOREIGN_DOMAIN=$4
|
||||
export SIGNER_KEY=$5
|
||||
|
||||
forge script $(dirname $0)/../forge-scripts/generate_registration_vaa.sol \
|
||||
shift 5 # <- remove 5 first arguments
|
||||
|
||||
forge script $(dirname $0)/../forge-scripts/submit_testnet_registration.sol \
|
||||
-vv \
|
||||
--rpc-url $RPC \
|
||||
--private-key $PRIVATE_KEY \
|
||||
--broadcast --slow
|
||||
--rpc-url $CONFIGURE_CCTP_RPC \
|
||||
--broadcast --slow $@
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ts-node $(dirname $0)/../ts/scripts/upgrade_proxy.ts $@
|
||||
npx tsx $(dirname $0)/../ts/scripts/upgrade_proxy.ts $@
|
|
@ -1,4 +1,4 @@
|
|||
#/usr/bin/env bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
etherscan_key=$1
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#/usr/bin/env bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
etherscan_key=$1
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#/usr/bin/env bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
etherscan_key=$1
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import {ethers} from "ethers";
|
||||
import {tryNativeToUint8Array} from "@certusone/wormhole-sdk";
|
||||
import {MockGuardians} from "@certusone/wormhole-sdk/lib/cjs/mock";
|
||||
import {CircleGovernanceEmitter} from "../test/helpers/mock";
|
||||
import {MockGuardians} from "@certusone/wormhole-sdk/lib/esm/mock";
|
||||
import {CircleGovernanceEmitter} from "../test/helpers/mock.js";
|
||||
import {abi as WORMHOLE_ABI} from "../../out/IWormhole.sol/IWormhole.json";
|
||||
import {abi as CIRCLE_INTEGRATION_ABI} from "../../out/CircleIntegration.sol/CircleIntegration.json";
|
||||
import {getTimeNow} from "../test/helpers/utils";
|
||||
import {getTimeNow} from "../test/helpers/utils.js";
|
||||
import {expect} from "chai";
|
||||
|
||||
require("dotenv").config({path: process.argv.slice(2)[0]});
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
import { ethers } from "ethers";
|
||||
import { tryNativeToHexString } from "@certusone/wormhole-sdk";
|
||||
import { signAsync } from "@noble/secp256k1";
|
||||
|
||||
const circleIntegrationModule =
|
||||
"0x000000000000000000000000000000436972636c65496e746567726174696f6e";
|
||||
const GOVERNANCE_UPGRADE_ACTION = 3;
|
||||
const governanceChainId = 1;
|
||||
const governanceContract =
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000004";
|
||||
|
||||
export interface Guardian {
|
||||
/**
|
||||
* Private key in hexadecimal string 0x encoded.
|
||||
*/
|
||||
key: string;
|
||||
/**
|
||||
* Index of the public key in the current Guardian set.
|
||||
*/
|
||||
index: number;
|
||||
}
|
||||
|
||||
export interface GuardianSet {
|
||||
guardians: Guardian[];
|
||||
id: number;
|
||||
}
|
||||
|
||||
export function doubleKeccak256(body: ethers.BytesLike) {
|
||||
return ethers.utils.keccak256(ethers.utils.keccak256(body));
|
||||
}
|
||||
|
||||
export function createCircleIntegrationUpgradeVAA(
|
||||
chainId: number,
|
||||
newAddress: string,
|
||||
guardianSet: GuardianSet,
|
||||
) {
|
||||
/*
|
||||
bytes32 module;
|
||||
uint8 action;
|
||||
uint16 chain;
|
||||
bytes32 newContract; //listed as address in the struct, but is actually bytes32 inside the VAA
|
||||
*/
|
||||
|
||||
const payload = ethers.utils.solidityPack(
|
||||
["bytes32", "uint8", "uint16", "bytes32"],
|
||||
[
|
||||
circleIntegrationModule,
|
||||
GOVERNANCE_UPGRADE_ACTION,
|
||||
chainId,
|
||||
"0x" + tryNativeToHexString(newAddress, "ethereum"),
|
||||
],
|
||||
);
|
||||
|
||||
return encodeAndSignGovernancePayload(payload, guardianSet);
|
||||
}
|
||||
|
||||
export async function encodeAndSignGovernancePayload(
|
||||
payload: string,
|
||||
guardianSet: GuardianSet,
|
||||
): Promise<string> {
|
||||
const timestamp = Math.floor(Date.now() / 1000);
|
||||
const nonce = 1;
|
||||
const sequence = 1;
|
||||
const consistencyLevel = 1;
|
||||
const vaaVersion = 1;
|
||||
|
||||
const encodedVAABody = ethers.utils.solidityPack(
|
||||
["uint32", "uint32", "uint16", "bytes32", "uint64", "uint8", "bytes"],
|
||||
[
|
||||
timestamp,
|
||||
nonce,
|
||||
governanceChainId,
|
||||
governanceContract,
|
||||
sequence,
|
||||
consistencyLevel,
|
||||
payload,
|
||||
],
|
||||
);
|
||||
|
||||
const hash = doubleKeccak256(encodedVAABody).substring(2);
|
||||
|
||||
const signatures = (await Promise.all(guardianSet.guardians
|
||||
.map(async ({ key, index }) => {
|
||||
const signature = await signAsync(hash, key);
|
||||
if (signature.recovery === undefined)
|
||||
throw new Error(`Failed to sign message: missing recovery id`);
|
||||
|
||||
// Remember that each signature is accompanied by the guardian index.
|
||||
const packSig = ethers.utils.solidityPack(
|
||||
["uint8", "bytes32", "bytes32", "uint8"],
|
||||
[
|
||||
index,
|
||||
ethers.utils.hexZeroPad(ethers.utils.hexlify(signature.r), 32),
|
||||
ethers.utils.hexZeroPad(ethers.utils.hexlify(signature.s), 32),
|
||||
signature.recovery,
|
||||
],
|
||||
);
|
||||
return packSig.substring(2);
|
||||
})))
|
||||
.join("");
|
||||
|
||||
const vm = [
|
||||
ethers.utils
|
||||
.solidityPack(
|
||||
["uint8", "uint32", "uint8"],
|
||||
[
|
||||
vaaVersion,
|
||||
// guardianSetIndex
|
||||
guardianSet.id,
|
||||
// number of signers
|
||||
guardianSet.guardians.length,
|
||||
],
|
||||
)
|
||||
.substring(2),
|
||||
signatures,
|
||||
encodedVAABody.substring(2),
|
||||
].join("");
|
||||
|
||||
return "0x" + vm;
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
import { ethers } from "ethers";
|
||||
import yargs from "yargs";
|
||||
import type { Argv } from "yargs";
|
||||
import { hideBin } from "yargs/helpers";
|
||||
|
||||
export type SignerArguments =
|
||||
| {
|
||||
useLedger: true;
|
||||
derivationPath: string;
|
||||
}
|
||||
| {
|
||||
useLedger: false;
|
||||
privateKey: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* @dev Use this to enrich your argument parsing with signer options
|
||||
*/
|
||||
export function addSignerArgsParser<T>(parser: Argv<T>) {
|
||||
return parser
|
||||
.option("ledger", {
|
||||
boolean: true,
|
||||
default: false,
|
||||
description: "Use ledger to sign transactions",
|
||||
required: false,
|
||||
})
|
||||
.option("derivation-path", {
|
||||
string: true,
|
||||
description:
|
||||
"BIP32 derivation path to use. Used only with ledger devices.",
|
||||
required: false,
|
||||
})
|
||||
.option("private-key", {
|
||||
string: true,
|
||||
description: "EVM Private Key.",
|
||||
required: false,
|
||||
});
|
||||
}
|
||||
|
||||
type ParsedSignerArgs = Awaited<
|
||||
ReturnType<ReturnType<typeof addSignerArgsParser>["parse"]>
|
||||
>;
|
||||
|
||||
/**
|
||||
* @notice Use this if you don't parse any arguments and need to provide
|
||||
* signer options.
|
||||
*/
|
||||
export async function parseSignerArgs() {
|
||||
const signerArgsParser = addSignerArgsParser(yargs())
|
||||
.help("h")
|
||||
.alias("h", "help");
|
||||
const args = await signerArgsParser.parse(hideBin(process.argv));
|
||||
return validateSignerArgs(args);
|
||||
}
|
||||
|
||||
export function validateSignerArgs(
|
||||
args: ParsedSignerArgs,
|
||||
): SignerArguments {
|
||||
if ((args.privateKey !== undefined) === args.ledger) {
|
||||
throw new Error(
|
||||
"Exactly one signing method must be provided. Use either the '--ledger' or the '--privateKey' options.",
|
||||
);
|
||||
}
|
||||
|
||||
if (args.ledger) {
|
||||
if (args.derivationPath === undefined) {
|
||||
throw new Error(
|
||||
"An account must be selected using the '--derivation-path' option when signing with a ledger device.",
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
useLedger: true,
|
||||
derivationPath: args.derivationPath,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
useLedger: false,
|
||||
// The private key cannot be undefined at this point but typescript's type narrowing is a bit lacking to determine that.
|
||||
privateKey: args.privateKey!,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getSigner(
|
||||
args: SignerArguments,
|
||||
provider: ethers.providers.Provider,
|
||||
): Promise<ethers.Signer> {
|
||||
if (args.useLedger) {
|
||||
const { LedgerSigner } = await import("@xlabs-xyz/ledger-signer");
|
||||
return LedgerSigner.create(provider, args.derivationPath);
|
||||
}
|
||||
|
||||
return new ethers.Wallet(args.privateKey, provider);
|
||||
}
|
|
@ -1,67 +1,69 @@
|
|||
import { ArgumentParser, Namespace } from "argparse";
|
||||
import { ethers } from "ethers";
|
||||
import yargs from "yargs";
|
||||
import {
|
||||
ICircleIntegration,
|
||||
ICircleIntegration__factory,
|
||||
} from "../src/ethers-contracts";
|
||||
} from "../src/ethers-contracts/index.js";
|
||||
import { addSignerArgsParser, validateSignerArgs, getSigner } from "./signer.js";
|
||||
|
||||
interface Setup {
|
||||
circleIntegration: ICircleIntegration;
|
||||
governanceMessage: Buffer;
|
||||
}
|
||||
|
||||
function setUp(): Setup {
|
||||
const parser = new ArgumentParser({
|
||||
description: "Upgrade Circle Integration Proxy",
|
||||
});
|
||||
async function setUp(): Promise<Setup> {
|
||||
const parser = addSignerArgsParser(yargs())
|
||||
.help("help", "Upgrade Circle Integration Proxy")
|
||||
.env("CONFIGURE_CCTP")
|
||||
.option("proxy", {
|
||||
string: true,
|
||||
required: true,
|
||||
description: "Proxy Contract Address",
|
||||
})
|
||||
.option("governance-message", {
|
||||
required: true,
|
||||
string: true,
|
||||
description: "Signed Governance Message in base64 format",
|
||||
})
|
||||
.option("rpc", {
|
||||
string: true,
|
||||
required: true,
|
||||
description: "EVM RPC URL",
|
||||
});
|
||||
|
||||
parser.add_argument("-m", "--governance-message", {
|
||||
required: true,
|
||||
help: "Signed Governance Message",
|
||||
});
|
||||
parser.add_argument("-p", "--proxy", {
|
||||
required: true,
|
||||
help: "Proxy Contract Address",
|
||||
});
|
||||
parser.add_argument("--rpc-url", { required: true, help: "EVM RPC" });
|
||||
parser.add_argument("--private-key", {
|
||||
required: true,
|
||||
help: "EVM Private Key",
|
||||
});
|
||||
const parsedArgs = await parser.argv;
|
||||
const signerArgs = validateSignerArgs(parsedArgs);
|
||||
|
||||
const args: Namespace = parser.parse_args();
|
||||
|
||||
const provider = new ethers.providers.StaticJsonRpcProvider(args.rpc_url);
|
||||
const wallet = new ethers.Wallet(args.private_key, provider);
|
||||
const provider = new ethers.providers.StaticJsonRpcProvider(parsedArgs.rpc);
|
||||
const signer = await getSigner(signerArgs, provider);
|
||||
const circleIntegration = ICircleIntegration__factory.connect(
|
||||
args.proxy,
|
||||
wallet
|
||||
parsedArgs.proxy,
|
||||
signer,
|
||||
);
|
||||
|
||||
return {
|
||||
circleIntegration,
|
||||
governanceMessage: Buffer.from(args.governance_message, "hex"),
|
||||
governanceMessage: Buffer.from(parsedArgs.governanceMessage, "base64"),
|
||||
};
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const { circleIntegration, governanceMessage } = setUp();
|
||||
const { circleIntegration, governanceMessage } = await setUp();
|
||||
|
||||
const chainId = await circleIntegration.chainId();
|
||||
console.log(chainId);
|
||||
console.log(
|
||||
`Executing mainnet CircleIntegration upgrade on chainId=${chainId}`,
|
||||
);
|
||||
|
||||
const tx = circleIntegration
|
||||
.upgradeContract(governanceMessage)
|
||||
.then((tx) => tx.wait())
|
||||
.catch((msg) => {
|
||||
// should not happen
|
||||
console.log(msg);
|
||||
return null;
|
||||
});
|
||||
if (tx === null) {
|
||||
console.log("failed transaction");
|
||||
const tx = await circleIntegration.upgradeContract(governanceMessage);
|
||||
console.log(`Upgrade transaction sent txHash=${tx.hash}`);
|
||||
|
||||
const receipt = await tx.wait();
|
||||
if (receipt.status !== 1) {
|
||||
console.log("Failed transaction");
|
||||
return 1;
|
||||
} else {
|
||||
console.log("Transaction successful");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
import { ethers } from "ethers";
|
||||
import yargs from "yargs";
|
||||
import { hideBin } from "yargs/helpers";
|
||||
import {
|
||||
ICircleIntegration,
|
||||
ICircleIntegration__factory,
|
||||
} from "../src/ethers-contracts/index.js";
|
||||
import { addSignerArgsParser, validateSignerArgs, getSigner } from "./signer.js";
|
||||
import { createCircleIntegrationUpgradeVAA, GuardianSet } from "./sign_vaa.js";
|
||||
|
||||
interface Setup {
|
||||
circleIntegration: ICircleIntegration;
|
||||
newImplementation: string;
|
||||
guardians: string[];
|
||||
}
|
||||
|
||||
async function setUp(): Promise<Setup> {
|
||||
const parser = addSignerArgsParser(yargs())
|
||||
.help("help", "Upgrade testnet Circle Integration Proxy")
|
||||
.env("CONFIGURE_CCTP")
|
||||
.option("proxy", {
|
||||
string: true,
|
||||
required: true,
|
||||
description: "Proxy Contract Address",
|
||||
})
|
||||
.option("new-implementation", {
|
||||
string: true,
|
||||
required: true,
|
||||
description: "New implementation contract address",
|
||||
})
|
||||
.option("guardian", {
|
||||
array: true,
|
||||
string: true,
|
||||
required: true,
|
||||
description: `Guardian private key in hexadecimal format.
|
||||
If there is more than one guardian, they must be sorted by their guardian set index.
|
||||
Skipping indexes in the guardian set is not supported.`,
|
||||
})
|
||||
.option("rpc", {
|
||||
string: true,
|
||||
required: true,
|
||||
description: "EVM RPC URL",
|
||||
});
|
||||
|
||||
const parsedArgs = await parser.parse(hideBin(process.argv));
|
||||
if (!ethers.utils.isAddress(parsedArgs.newImplementation)) {
|
||||
throw new Error(
|
||||
`The implementation address is invalid: ${parsedArgs.newImplementation}`,
|
||||
);
|
||||
}
|
||||
const signerArgs = validateSignerArgs(parsedArgs);
|
||||
|
||||
const provider = new ethers.providers.StaticJsonRpcProvider(parsedArgs.rpc);
|
||||
const signer = await getSigner(signerArgs, provider);
|
||||
const circleIntegration = ICircleIntegration__factory.connect(
|
||||
parsedArgs.proxy,
|
||||
signer,
|
||||
);
|
||||
|
||||
return {
|
||||
circleIntegration,
|
||||
newImplementation: parsedArgs.newImplementation,
|
||||
guardians: parsedArgs.guardian,
|
||||
};
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const { circleIntegration, newImplementation, guardians } = await setUp();
|
||||
|
||||
const chainId = await circleIntegration.chainId();
|
||||
console.log(
|
||||
`Executing testnet CircleIntegration upgrade on chainId=${chainId}`,
|
||||
);
|
||||
|
||||
const guardianSet: GuardianSet = {
|
||||
id: 0,
|
||||
guardians: guardians.map((guardian, index) => {
|
||||
return { key: guardian, index };
|
||||
}),
|
||||
};
|
||||
|
||||
const governanceMessage = await createCircleIntegrationUpgradeVAA(
|
||||
chainId,
|
||||
newImplementation,
|
||||
guardianSet,
|
||||
);
|
||||
|
||||
const tx = await circleIntegration.upgradeContract(governanceMessage);
|
||||
console.log(`Upgrade transaction sent txHash=${tx.hash}`);
|
||||
|
||||
const receipt = await tx.wait();
|
||||
if (receipt.status !== 1) {
|
||||
console.log("Failed transaction");
|
||||
return 1;
|
||||
} else {
|
||||
console.log("Transaction successful");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
|
@ -1,2 +1,2 @@
|
|||
export * from "./ethers-contracts";
|
||||
export * from "./types";
|
||||
export * from "./ethers-contracts/index.js";
|
||||
export * from "./types.js";
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
IMessageTransmitter__factory,
|
||||
IUSDC__factory,
|
||||
IWormhole__factory,
|
||||
} from "../src/ethers-contracts";
|
||||
} from "../src/ethers-contracts/index.js";
|
||||
import {
|
||||
AVAX_CIRCLE_BRIDGE_ADDRESS,
|
||||
AVAX_FORK_CHAIN_ID,
|
||||
|
@ -26,7 +26,7 @@ import {
|
|||
WALLET_PRIVATE_KEY,
|
||||
WORMHOLE_GUARDIAN_SET_INDEX,
|
||||
WORMHOLE_MESSAGE_FEE,
|
||||
} from "./helpers/consts";
|
||||
} from "./helpers/consts.js";
|
||||
|
||||
describe("Environment Test", () => {
|
||||
describe("Global", () => {
|
||||
|
|
|
@ -9,12 +9,12 @@ import {
|
|||
AVAX_LOCALHOST,
|
||||
ETH_FORK_CHAIN_ID,
|
||||
AVAX_FORK_CHAIN_ID,
|
||||
} from "./helpers/consts";
|
||||
import {ICircleIntegration__factory} from "../src/ethers-contracts";
|
||||
import {MockGuardians} from "@certusone/wormhole-sdk/lib/cjs/mock";
|
||||
} from "./helpers/consts.js";
|
||||
import {ICircleIntegration__factory} from "../src/ethers-contracts/index.js";
|
||||
import {MockGuardians} from "@certusone/wormhole-sdk/lib/esm/mock";
|
||||
|
||||
import {CircleGovernanceEmitter} from "./helpers/mock";
|
||||
import {getTimeNow, readCircleIntegrationProxyAddress} from "./helpers/utils";
|
||||
import {CircleGovernanceEmitter} from "./helpers/mock.js";
|
||||
import {getTimeNow, readCircleIntegrationProxyAddress} from "./helpers/utils.js";
|
||||
|
||||
describe("Circle Integration Registration", () => {
|
||||
// ethereum wallet, CircleIntegration contract and USDC contract
|
||||
|
|
|
@ -19,23 +19,23 @@ import {
|
|||
AVAX_FORK_CHAIN_ID,
|
||||
ETH_WORMHOLE_ADDRESS,
|
||||
AVAX_WORMHOLE_ADDRESS,
|
||||
} from "./helpers/consts";
|
||||
} from "./helpers/consts.js";
|
||||
import {
|
||||
ICircleIntegration__factory,
|
||||
IUSDC__factory,
|
||||
IMockIntegration__factory,
|
||||
IWormhole__factory,
|
||||
} from "../src/ethers-contracts";
|
||||
import {MockGuardians} from "@certusone/wormhole-sdk/lib/cjs/mock";
|
||||
import {RedeemParameters, TransferParameters} from "../src";
|
||||
import {findCircleMessageInLogs} from "../src/logs";
|
||||
} from "../src/ethers-contracts/index.js";
|
||||
import {MockGuardians} from "@certusone/wormhole-sdk/lib/esm/mock";
|
||||
import {RedeemParameters, TransferParameters} from "../src/index.js";
|
||||
import {findCircleMessageInLogs} from "../src/logs.js";
|
||||
import {
|
||||
MockCircleAttester,
|
||||
readCircleIntegrationProxyAddress,
|
||||
readMockIntegrationAddress,
|
||||
findWormholeMessageInLogs,
|
||||
findRedeemEventInLogs,
|
||||
} from "./helpers/utils";
|
||||
} from "./helpers/utils.js";
|
||||
|
||||
describe("Circle Integration Send and Receive", () => {
|
||||
// ethereum wallet, CircleIntegration contract and USDC contract
|
||||
|
|
|
@ -9,12 +9,12 @@ import {
|
|||
AVAX_LOCALHOST,
|
||||
ETH_FORK_CHAIN_ID,
|
||||
AVAX_FORK_CHAIN_ID,
|
||||
} from "./helpers/consts";
|
||||
import {ICircleIntegration__factory} from "../src/ethers-contracts";
|
||||
import {MockGuardians} from "@certusone/wormhole-sdk/lib/cjs/mock";
|
||||
} from "./helpers/consts.js";
|
||||
import {ICircleIntegration__factory} from "../src/ethers-contracts/index.js";
|
||||
import {MockGuardians} from "@certusone/wormhole-sdk/lib/esm/mock";
|
||||
|
||||
import {CircleGovernanceEmitter} from "./helpers/mock";
|
||||
import {getTimeNow, readCircleIntegrationProxyAddress} from "./helpers/utils";
|
||||
import {CircleGovernanceEmitter} from "./helpers/mock.js";
|
||||
import {getTimeNow, readCircleIntegrationProxyAddress} from "./helpers/utils.js";
|
||||
|
||||
const {execSync} = require("child_process");
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {GovernanceEmitter} from "@certusone/wormhole-sdk/lib/cjs/mock";
|
||||
import {GovernanceEmitter} from "@certusone/wormhole-sdk/lib/esm/mock";
|
||||
import {ethers} from "ethers";
|
||||
|
||||
export interface Transfer {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {tryNativeToHexString} from "@certusone/wormhole-sdk";
|
||||
import {ethSignWithPrivate} from "@certusone/wormhole-sdk/lib/cjs/mock";
|
||||
import {ethSignWithPrivate} from "@certusone/wormhole-sdk/lib/esm/mock";
|
||||
import {ethers} from "ethers";
|
||||
import * as fs from "fs";
|
||||
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
"compilerOptions": {
|
||||
"types": ["node", "mocha", "chai"],
|
||||
"typeRoots": ["./node_modules/@types"],
|
||||
"lib": ["es2020"],
|
||||
"module": "CommonJS",
|
||||
"target": "es2020",
|
||||
"lib": ["ES2022", "dom"],
|
||||
"module": "NodeNext",
|
||||
"target": "ES2022",
|
||||
"esModuleInterop": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"resolveJsonModule": true,
|
||||
"moduleResolution": "node"
|
||||
}
|
||||
"moduleResolution": "NodeNext"
|
||||
},
|
||||
"include": ["ts"]
|
||||
}
|
||||
|
|
2313
evm/yarn.lock
2313
evm/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue