diff --git a/Tiltfile b/Tiltfile index 5d12db010..7906c8eb8 100644 --- a/Tiltfile +++ b/Tiltfile @@ -301,14 +301,14 @@ def build_node_yaml(): "http://wormchain:1317", "--gatewayRelayerContract", - "wormhole17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9jfksztgw5uh69wac2pgshdnj3k", + "wormhole1wn625s4jcmvk0szpl85rj5azkfc6suyvf75q6vrddscjdphtve8sca0pvl", "--gatewayRelayerKeyPath", "/tmp/mounted-keys/wormchain/gwrelayerKey", "--gatewayRelayerKeyPassPhrase", "test0000", "--gatewayContract", - "wormhole17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9jfksztgw5uh69wac2pgshdnj3k", + "wormhole1ghd753shjuwexxywmgs4xz7x2q732vcnkm6h2pyv9s6ah3hylvrqtm7t3h", "--gatewayWS", "ws://wormchain:26657/websocket", "--gatewayLCD", diff --git a/node/pkg/gwrelayer/gwrelayer_test.go b/node/pkg/gwrelayer/gwrelayer_test.go index 9842fd251..49b28045d 100644 --- a/node/pkg/gwrelayer/gwrelayer_test.go +++ b/node/pkg/gwrelayer/gwrelayer_test.go @@ -3,7 +3,6 @@ package gwrelayer import ( "bytes" "encoding/hex" - "fmt" "testing" "time" @@ -11,6 +10,7 @@ import ( "github.com/stretchr/testify/require" "github.com/certusone/wormhole/node/pkg/common" + "github.com/wormhole-foundation/wormhole/sdk" "github.com/wormhole-foundation/wormhole/sdk/vaa" sdktypes "github.com/cosmos/cosmos-sdk/types" @@ -110,9 +110,8 @@ func Test_shouldPublishToTokenBridge(t *testing.T) { }) } - addr, err := sdktypes.Bech32ifyAddressBytes("wormhole", decodeBytes("aeb534c45c3049d380b9d9b966f9895f53abd4301bfaff407fa09dea8ae7a924")) + _, err = sdktypes.Bech32ifyAddressBytes("wormhole", decodeBytes("aeb534c45c3049d380b9d9b966f9895f53abd4301bfaff407fa09dea8ae7a924")) require.NoError(t, err) - fmt.Println(addr) } func decodeBytes(s string) []byte { @@ -130,3 +129,13 @@ func addr(str string) vaa.Address { } return a } + +func Test_verifyDevnetTokenBridgeAddress(t *testing.T) { + tokenBridgeAddressInTilt := "wormhole1eyfccmjm6732k7wp4p6gdjwhxjwsvje44j0hfx8nkgrm8fs7vqfssvpdkx" //nolint:gosec + targetAddress, err := convertBech32AddressToWormhole(tokenBridgeAddressInTilt) + require.NoError(t, err) + + expectedAddress, exists := sdk.KnownDevnetTokenbridgeEmitters[vaa.ChainIDWormchain] + require.True(t, exists) + assert.True(t, bytes.Equal(expectedAddress[:], targetAddress[:])) +} diff --git a/sdk/devnet_consts.go b/sdk/devnet_consts.go index a5270df6d..fea4c1b4f 100644 --- a/sdk/devnet_consts.go +++ b/sdk/devnet_consts.go @@ -15,7 +15,7 @@ var knownDevnetTokenbridgeEmitters = map[vaa.ChainID]string{ vaa.ChainIDTerra: "9e28beafa966b2407bffb0d48651e94972a56e69f3c0897d9e8facbdaeb98386", vaa.ChainIDBSC: "0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16", vaa.ChainIDAlgorand: "8ec299cb7f3efec28f542397e07f07118d74c875f85409ed8e6b93c17b60e992", - vaa.ChainIDWormchain: "45dbea4617971d93188eda21530bc6503d153313b6f575048c2c35dbc6e4fb06", + vaa.ChainIDWormchain: "c9138c6e5bd7a2ab79c1a87486c9d7349d064b35ac9f7498f3b207b3a61e6013", vaa.ChainIDSui: "be8d2e6809d4873bcf1d8be6af2b92500091ad6aa5dc76bc717af86a58d300ca", } diff --git a/sdk/js/src/utils/consts.ts b/sdk/js/src/utils/consts.ts index fb8a12129..6edb919d1 100644 --- a/sdk/js/src/utils/consts.ts +++ b/sdk/js/src/utils/consts.ts @@ -822,9 +822,9 @@ const DEVNET = { nft_bridge: undefined, }, wormchain: { - core: "wormhole17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9jfksztgw5uh69wac2pgshdnj3k", + core: "wormhole1ghd753shjuwexxywmgs4xz7x2q732vcnkm6h2pyv9s6ah3hylvrqtm7t3h", token_bridge: - "wormhole1ghd753shjuwexxywmgs4xz7x2q732vcnkm6h2pyv9s6ah3hylvrqtm7t3h", + "wormhole1eyfccmjm6732k7wp4p6gdjwhxjwsvje44j0hfx8nkgrm8fs7vqfssvpdkx", nft_bridge: undefined, }, sepolia: { diff --git a/wormchain/contracts/tools/deploy_wormchain.ts b/wormchain/contracts/tools/deploy_wormchain.ts index 6d80e6922..3108d4453 100644 --- a/wormchain/contracts/tools/deploy_wormchain.ts +++ b/wormchain/contracts/tools/deploy_wormchain.ts @@ -28,6 +28,11 @@ if (process.env.INIT_SIGNERS_KEYS_CSV === "undefined") { throw msg; } +const init_guardians = JSON.parse(process.env.INIT_SIGNERS); +if (!init_guardians || init_guardians.length === 0) { + throw "failed to get initial guardians from .env file."; +} + const VAA_SIGNERS = process.env.INIT_SIGNERS_KEYS_CSV.split(","); const GOVERNANCE_CHAIN = Number(devnetConsts.global.governanceChainId); const GOVERNANCE_EMITTER = devnetConsts.global.governanceEmitterAddress; @@ -44,8 +49,17 @@ const artifacts: ContractName[] = [ "global_accountant.wasm", "wormchain_ibc_receiver.wasm", "ntt_global_accountant.wasm", + "cw_wormhole.wasm", + "cw_token_bridge.wasm", + "cw20_wrapped_2.wasm", + "ibc_translator.wasm", ]; +// Governance constants defined by the Wormhole spec. +const govChain = 1; +const govAddress = + "0000000000000000000000000000000000000000000000000000000000000004"; + const ARTIFACTS_PATH = "../artifacts/"; /* Check that the artifact folder contains all the wasm files we expect and nothing else */ @@ -390,6 +404,242 @@ async function main() { allowListResponse.transactionHash, allowListResponse.code ); + + // instantiate wormhole core bridge + addresses["cw_wormhole.wasm"] = await instantiate( + codeIds["cw_wormhole.wasm"], + { + gov_chain: govChain, + gov_address: Buffer.from(govAddress, "hex").toString("base64"), + guardian_set_expirity: 86400, + initial_guardian_set: { + addresses: init_guardians.map((hex) => { + return { + bytes: Buffer.from(hex, "hex").toString("base64"), + }; + }), + expiration_time: 0, + }, + chain_id: 3104, + fee_denom: "utest", + }, + "wormhole" + ); + console.log( + "instantiated wormhole core bridge contract: ", + addresses["cw_wormhole.wasm"] + ); + + // instantiate wormhole token bridge + addresses["cw_token_bridge.wasm"] = await instantiate( + codeIds["cw_token_bridge.wasm"], + { + gov_chain: govChain, + gov_address: Buffer.from(govAddress, "hex").toString("base64"), + wormhole_contract: addresses["cw_wormhole.wasm"], + wrapped_asset_code_id: codeIds["cw20_wrapped_2.wasm"], + chain_id: 3104, + native_denom: "", + native_symbol: "", + native_decimals: 6, + }, + "tokenBridge" + ); + console.log( + "instantiated wormhole token bridge contract: ", + addresses["cw_token_bridge.wasm"] + ); + + /* Registrations: tell the bridge contracts to know about each other */ + + const contract_registrations = { + "cw_token_bridge.wasm": [ + // Solana + process.env.REGISTER_SOL_TOKEN_BRIDGE_VAA, + // Ethereum + process.env.REGISTER_ETH_TOKEN_BRIDGE_VAA, + // BSC + process.env.REGISTER_BSC_TOKEN_BRIDGE_VAA, + // ALGO + process.env.REGISTER_ALGO_TOKEN_BRIDGE_VAA, + // TERRA + process.env.REGISTER_TERRA_TOKEN_BRIDGE_VAA, + // TERRA2 + process.env.REGISTER_TERRA2_TOKEN_BRIDGE_VAA, + // NEAR + process.env.REGISTER_NEAR_TOKEN_BRIDGE_VAA, + // APTOS + process.env.REGISTER_APTOS_TOKEN_BRIDGE_VAA, + ], + }; + + for (const [contract, registrations] of Object.entries( + contract_registrations + )) { + console.log(`Registering chains for ${contract}:`); + for (const registration of registrations) { + const executeMsg = client.wasm.msgExecuteContract({ + sender: signer, + contract: addresses[contract], + msg: toUtf8( + JSON.stringify({ + submit_vaa: { + data: Buffer.from(registration, "hex").toString("base64"), + }, + }) + ), + funds: [], + }); + const executeRes = await client.signAndBroadcast(signer, [executeMsg], { + ...ZERO_FEE, + gas: "10000000", + }); + console.log( + "updated token bridge registration: ", + executeRes.transactionHash + ); + } + } + + // add the wasm instantiate allowlist for token bridge + // contract address bech32 to hex conversion + const { data } = fromBech32(addresses["cw_token_bridge.wasm"]); + const contractBuf = Buffer.from(data); + + // code ID number to uint64 hex conversion + const codeIdBuf = Buffer.alloc(8); + const cw20CodeId = codeIds["cw20_wrapped_2.wasm"]; + codeIdBuf.writeUInt32BE(cw20CodeId >> 8, 0); //write the high order bits (shifted over) + codeIdBuf.writeUInt32BE(cw20CodeId & 0x00ff, 4); //write the low order bits + const payload = `${contractBuf.toString("hex")}${codeIdBuf.toString("hex")}`; + let vaa: VAA = { + version: 1, + guardianSetIndex: 0, + signatures: [], + timestamp: 0, + nonce: 0, + emitterChain: GOVERNANCE_CHAIN, + emitterAddress: GOVERNANCE_EMITTER, + sequence: BigInt(Math.floor(Math.random() * 100000000)), + consistencyLevel: 0, + payload: { + type: "Other", + hex: `0000000000000000000000000000000000000000005761736D644D6F64756C65040${CHAIN_ID_WORMCHAIN.toString( + 16 + )}${payload}`, + }, + }; + vaa.signatures = sign(VAA_SIGNERS, vaa as unknown as VAA); + + const msgInstantiateAllowlist = client.core.msgAddWasmInstantiateAllowlist({ + signer: signer, + address: addresses["cw_token_bridge.wasm"], + code_id: codeIds["cw20_wrapped_2.wasm"], + vaa: hexToUint8Array(serialiseVAA(vaa as unknown as VAA)), + }); + const msgInstantiateAllowlistRes = await client.signAndBroadcast( + signer, + [msgInstantiateAllowlist], + { + ...ZERO_FEE, + gas: "10000000", + } + ); + console.log("wasm instantiate allowlist msg: ", msgInstantiateAllowlist); + console.log( + "wasm instantiate allowlist result: ", + msgInstantiateAllowlistRes + ); + + // instantiate ibc translator + addresses["ibc_translator.wasm"] = await instantiate( + codeIds["ibc_translator.wasm"], + { + token_bridge_contract: addresses["cw_token_bridge.wasm"], + }, + "ibcTranslator" + ); + console.log( + "instantiated ibc translator contract: ", + addresses["ibc_translator.wasm"] + ); + + // update channel mapping + let updateChannelVaa: VAA = { + version: 1, + guardianSetIndex: 0, + signatures: [], + timestamp: 0, + nonce: 0, + emitterChain: GOVERNANCE_CHAIN, + emitterAddress: GOVERNANCE_EMITTER, + sequence: BigInt(Math.floor(Math.random() * 100000000)), + consistencyLevel: 0, + payload: { + type: "Other", + hex: + "000000000000000000000000000000000000004962635472616e736c61746f72" + // module IbcTranslator + "01" + // action IbcReceiverActionUpdateChannelChain + "0c20" + // target chain id wormchain + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006368616e6e656c2d31" + // channel-1 + "0012", // chain id terra2 (18) + }, + }; + updateChannelVaa.signatures = sign( + VAA_SIGNERS, + updateChannelVaa as unknown as VAA + ); + const updateMsg = client.wasm.msgExecuteContract({ + sender: signer, + contract: addresses["ibc_translator.wasm"], + msg: toUtf8( + JSON.stringify({ + submit_update_chain_to_channel_map: { + vaa: Buffer.from( + serialiseVAA(updateChannelVaa as unknown as VAA), + "hex" + ).toString("base64"), + }, + }) + ), + funds: [], + }); + const executeRes = await client.signAndBroadcast(signer, [updateMsg], { + ...ZERO_FEE, + gas: "10000000", + }); + console.log("updated channel mapping: ", executeRes.transactionHash); + + // set params for tokenfactory and PFM + let setDefaultParamsVaa: VAA = { + version: 1, + guardianSetIndex: 0, + signatures: [], + timestamp: 0, + nonce: 0, + emitterChain: GOVERNANCE_CHAIN, + emitterAddress: GOVERNANCE_EMITTER, + sequence: BigInt(Math.floor(Math.random() * 100000000)), + consistencyLevel: 0, + payload: { + type: "Other", + hex: "", + }, + }; + const setParamsMsg = client.core.msgExecuteGatewayGovernanceVaa({ + signer: signer, + vaa: hexToUint8Array( + serialiseVAA(setDefaultParamsVaa as unknown as VAA) + ), + }); + await client + .signAndBroadcast(signer, [setParamsMsg], { + ...ZERO_FEE, + gas: "10000000", + }) + .then((res) => { + console.log("set params for tokenfactory and pfm: ", res.transactionHash); + }); } try {