Movement move (#1211)

* [contract manager] Implement WormholeAptosContract and integrate aptos cli with the manager

* Add getChainId for wormhole contracts

* Add movement contracts

* Simplify aptos cli
This commit is contained in:
Amin Moghaddam 2024-01-11 12:35:52 +01:00 committed by GitHub
parent 7cf7420203
commit cee5da93d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 295 additions and 187 deletions

View File

@ -1,4 +1,4 @@
import { KeyValueConfig, PrivateKey, Storable } from "./base";
import { KeyValueConfig, PrivateKey, Storable, TxResult } from "./base";
import {
ChainName,
SetFee,
@ -12,7 +12,7 @@ import {
DataSource,
EvmSetWormholeAddress,
} from "xc_admin_common";
import { AptosClient, AptosAccount, CoinClient } from "aptos";
import { AptosClient, AptosAccount, CoinClient, TxnBuilderTypes } from "aptos";
import Web3 from "web3";
import {
CosmwasmExecutor,
@ -55,6 +55,10 @@ export abstract class Chain extends Storable {
);
}
public getWormholeChainId(): number {
return toChainId(this.wormholeChainName);
}
getId(): string {
return this.id;
}
@ -509,4 +513,22 @@ export class AptosChain extends Chain {
const coinClient = new CoinClient(client);
return Number(await coinClient.checkBalance(account)) / 10 ** 8;
}
async sendTransaction(
senderPrivateKey: PrivateKey,
txPayload: TxnBuilderTypes.TransactionPayloadEntryFunction
): Promise<TxResult> {
const client = this.getClient();
const sender = new AptosAccount(
new Uint8Array(Buffer.from(senderPrivateKey, "hex"))
);
const result = await client.generateSignSubmitWaitForTransaction(
sender,
txPayload,
{
maxGasAmount: BigInt(30000),
}
);
return { id: result.hash, info: result };
}
}

View File

@ -1,8 +1,74 @@
import { Contract, PriceFeed, PrivateKey, TxResult } from "../base";
import { ApiError, AptosAccount, BCS, TxnBuilderTypes } from "aptos";
import { ApiError, BCS, CoinClient, TxnBuilderTypes } from "aptos";
import { AptosChain, Chain } from "../chains";
import { DataSource } from "xc_admin_common";
import { CoinClient } from "aptos";
import { WormholeContract } from "./wormhole";
type WormholeState = {
chain_id: { number: string };
guardian_set_index: { number: string };
guardian_sets: { handle: string };
};
type GuardianSet = {
guardians: { address: { bytes: string } }[];
expiration_time: { number: string };
index: { number: string };
};
export class WormholeAptosContract extends WormholeContract {
constructor(public chain: AptosChain, public address: string) {
super();
}
async getState(): Promise<WormholeState> {
const client = this.chain.getClient();
const resources = await client.getAccountResources(this.address);
const type = "WormholeState";
for (const resource of resources) {
if (resource.type === `${this.address}::state::${type}`) {
return resource.data as WormholeState;
}
}
throw new Error(`${type} resource not found in account ${this.address}`);
}
async getCurrentGuardianSetIndex(): Promise<number> {
const data = await this.getState();
return Number(data.guardian_set_index.number);
}
async getChainId(): Promise<number> {
const data = await this.getState();
return Number(data.chain_id.number);
}
async getGuardianSet(): Promise<string[]> {
const data = await this.getState();
const client = this.chain.getClient();
const result = (await client.getTableItem(data.guardian_sets.handle, {
key_type: `u64`,
value_type: `${this.address}::structs::GuardianSet`,
key: data.guardian_set_index.number.toString(),
})) as GuardianSet;
return result.guardians.map((guardian) => guardian.address.bytes);
}
async upgradeGuardianSets(
senderPrivateKey: PrivateKey,
vaa: Buffer
): Promise<TxResult> {
const txPayload = new TxnBuilderTypes.TransactionPayloadEntryFunction(
TxnBuilderTypes.EntryFunction.natural(
`${this.address}::guardian_set_upgrade`,
"submit_vaa_entry",
[],
[BCS.bcsSerializeBytes(vaa)]
)
);
return this.chain.sendTransaction(senderPrivateKey, txPayload);
}
}
export class AptosContract extends Contract {
static type = "AptosContract";
@ -45,25 +111,11 @@ export class AptosContract extends Contract {
[BCS.bcsSerializeBytes(vaa)]
)
);
return this.sendTransaction(senderPrivateKey, txPayload);
return this.chain.sendTransaction(senderPrivateKey, txPayload);
}
private async sendTransaction(
senderPrivateKey: PrivateKey,
txPayload: TxnBuilderTypes.TransactionPayloadEntryFunction
): Promise<TxResult> {
const client = this.chain.getClient();
const sender = new AptosAccount(
new Uint8Array(Buffer.from(senderPrivateKey, "hex"))
);
const result = await client.generateSignSubmitWaitForTransaction(
sender,
txPayload,
{
maxGasAmount: BigInt(30000),
}
);
return { id: result.hash, info: result };
public getWormholeContract(): WormholeAptosContract {
return new WormholeAptosContract(this.chain, this.wormholeStateId);
}
async executeUpdatePriceFeed(
@ -78,7 +130,7 @@ export class AptosContract extends Contract {
[BCS.serializeVectorWithFunc(vaas, "serializeBytes")]
)
);
return this.sendTransaction(senderPrivateKey, txPayload);
return this.chain.sendTransaction(senderPrivateKey, txPayload);
}
getStateResources() {

View File

@ -54,6 +54,11 @@ export class WormholeCosmWasmContract extends WormholeContract {
return JSON.parse(config["\x00\x06config"])["guardian_set_index"];
}
async getChainId(): Promise<number> {
const config = await this.getConfig();
return JSON.parse(config["\x00\x06config"])["chain_id"];
}
async getGuardianSet(): Promise<string[]> {
const config = await this.getConfig();
const guardianSetIndex = JSON.parse(config["\x00\x06config"])[

View File

@ -154,6 +154,19 @@ const WORMHOLE_ABI = [
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "chainId",
outputs: [
{
internalType: "uint16",
name: "",
type: "uint16",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
@ -228,6 +241,11 @@ export class WormholeEvmContract extends WormholeContract {
);
}
async getChainId(): Promise<number> {
const wormholeContract = this.getContract();
return Number(await wormholeContract.methods.chainId().call());
}
/**
* Returns an array of guardian addresses used for VAA verification in this contract
*/

View File

@ -3,6 +3,12 @@ import { PrivateKey, TxResult } from "../base";
export abstract class WormholeContract {
abstract getCurrentGuardianSetIndex(): Promise<number>;
/**
* Returns the chain id set in this contract.
* This should match to the chain ids stored in this repo in the chains.ts file based on the network
*/
abstract getChainId(): Promise<number>;
/**
* Returns an array of guardian addresses used for VAA verification in this contract
*/
@ -31,7 +37,11 @@ export abstract class WormholeContract {
const currentIndex = await this.getCurrentGuardianSetIndex();
for (let i = currentIndex; i < MAINNET_UPGRADE_VAAS.length; i++) {
const vaa = MAINNET_UPGRADE_VAAS[i];
await this.upgradeGuardianSets(senderPrivateKey, Buffer.from(vaa, "hex"));
const result = await this.upgradeGuardianSets(
senderPrivateKey,
Buffer.from(vaa, "hex")
);
console.log(`Submitted upgrade VAA ${i} with tx id ${result.id}`);
// make sure the upgrade is complete before continuing
while ((await this.getCurrentGuardianSetIndex()) <= i) {
await new Promise((resolve) => setTimeout(resolve, 5000));

View File

@ -10,7 +10,7 @@ repl.evalCode(
"import { SuiContract } from './src/contracts/sui';" +
"import { WormholeCosmWasmContract, CosmWasmContract } from './src/contracts/cosmwasm';" +
"import { WormholeEvmContract, EvmContract } from './src/contracts/evm';" +
"import { AptosContract } from './src/contracts/aptos';" +
"import { WormholeAptosContract, AptosContract } from './src/contracts/aptos';" +
"import { DefaultStore } from './src/store';" +
"import { toPrivateKey } from './src/base';" +
"DefaultStore"

View File

@ -8,3 +8,8 @@
mainnet: true
rpcUrl: https://fullnode.mainnet.aptoslabs.com/v1
type: AptosChain
- id: movement_move_devnet
wormholeChainName: movement_move_devnet
mainnet: false
rpcUrl: https://devnet.m1.movementlabs.xyz/v1
type: AptosChain

View File

@ -388,3 +388,8 @@
rpcUrl: https://sepolia.base.org
networkId: 84532
type: EvmChain
- id: movement_evm_devnet
mainnet: false
rpcUrl: https://mevm.devnet.m1.movementlabs.xyz/v1
networkId: 336
type: EvmChain

View File

@ -6,3 +6,7 @@
stateId: "0x7e783b349d3e89cf5931af376ebeadbfab855b3fa239b7ada8f5a92fbea6b387"
wormholeStateId: "0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625"
type: AptosContract
- chain: movement_move_devnet
stateId: "0x9357e76fe965c9956a76181ee49f66d51b7f9c3800182a944ed96be86301e49f"
wormholeStateId: "0x9236893d6444b208b7e0b3e8d4be4ace90b6d17817ab7d1584e46a33ef5c50c9"
type: AptosContract

View File

@ -232,3 +232,6 @@
- chain: base_sepolia
address: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729"
type: EvmContract
- chain: movement_evm_devnet
address: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729"
type: EvmContract

View File

@ -109,6 +109,8 @@ export const RECEIVER_CHAINS = {
bttc_testnet: 50041,
zksync_sepolia: 50042,
base_sepolia: 50043,
movement_evm_devnet: 50044,
movement_move_devnet: 50045,
};
// If there is any overlapping value the receiver chain will replace the wormhole

View File

@ -2,8 +2,7 @@
Install aptos cli with the same version specified in the ci workflows.
All the commands which submit transactions require an environment variable for the private key to be set.
Depending on the network, this can be either `APTOS_LOCALNET_KEY`, `APTOS_TESTNET_KEY` or `APTOS_MAINNET_KEY`.
All the commands which submit transactions require an environment variable `APTOS_PRIVATE_KEY` for the private key to be set.
# Deploying from scratch
@ -13,7 +12,10 @@ capability. You can read more about it [here](https://github.com/wormhole-founda
Assuming the wormhole and deployer contracts are already deployed, we can deploy the pyth oracle with the following command:
```bash
npm run cli deploy-pyth -- ../contracts <seed> -n testnet
npm run cli deploy-pyth -- ../contracts <seed> \
-n aptos_testnet \
--deployer <deployer-address> \
--wormhole <wormhole-address>
```
`seed` can be any random string that is used for determining a specific contract address based on the seed value and the signer address.
@ -30,40 +32,15 @@ wormhole = "_"
### Initializing pyth
You can run the following to initialize the pyth contract, the following is a sample (testnet) config:
You can run the following to initialize the pyth contract:
```bash
npm run cli init-pyth -- <seed> -n testnet \
npm run cli init-pyth -- <seed> -n <network> \
--stale-price-threshold 60 \
--update-fee 1 \
--governance-emitter-chain-id 1 \
--governance-emitter-address 63278d271099bfd491951b3e648f08b1c71631e4a53674ad43e8f9f98068c385 \
--data-source-chain-ids 1 \
--data-source-chain-ids 26 \
--data-source-chain-ids 26 \
--data-source-emitter-addresses f346195ac02f37d60d4db8ffa6ef74cb1be3550047543a4a9ee9acf4d78697b0 \
--data-source-emitter-addresses a27839d641b07743c0cb5f68c51f8cd31d2c0762bec00dc6fcd25433ef1ab5b6 \
--data-source-emitter-addresses e101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71
--channel <stable-or-beta>
```
The following is a sample mainnet config:
```bash
npm run cli init-pyth -- <seed> -n mainnet \
--stale-price-threshold 60 \
--update-fee 1 \
--governance-emitter-chain-id 1 \
--governance-emitter-address 5635979a221c34931e32620b9293a463065555ea71fe97cd6237ade875b12e9e \
--data-source-chain-ids 1 \
--data-source-chain-ids 26 \
--data-source-chain-ids 26 \
--data-source-emitter-addresses 6bb14509a612f01fbbc4cffeebd4bbfb492a86df717ebe92eb6df432a3f00a25 \
--data-source-emitter-addresses f8cd23c2ab91237730770bbea08d61005cdda0984348f3f6eecb559638c0bba0 \
--data-source-emitter-addresses e101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71
```
Note that the `data-source-chain-ids` are paired with `data-source-emitter-addresses` and their order matters.
# Upgrade process:
The following steps are needed to upgrade our aptos contracts:

View File

@ -4,34 +4,40 @@ import { AptosAccount, AptosClient, BCS, TxnBuilderTypes } from "aptos";
import fs from "fs";
import sha3 from "js-sha3";
import { ethers } from "ethers";
import {
AptosChain,
DefaultStore,
getDefaultDeploymentConfig,
} from "contract_manager";
const LOCALNET: string = "localnet";
const TESTNET: string = "testnet";
const MAINNET: string = "mainnet";
interface Network {
// RPC endpoint of the network
endpoint: string;
// Private key of the network
key: string | undefined;
}
const NETWORK_CHOICES = Object.entries(DefaultStore.chains)
.filter(([chain, config]) => {
return config instanceof AptosChain;
})
.map(([chain, _]) => {
return chain;
});
const NETWORK_OPTION = {
alias: "n",
describe: "network",
type: "string",
choices: [LOCALNET, TESTNET, MAINNET],
choices: NETWORK_CHOICES,
demandOption: true,
} as const;
const CHANNEL_OPTION = {
describe: "channel",
type: "string",
choices: ["stable", "beta"],
demandOption: true,
} as const;
const DEPLOYER_OPTION = {
describe: "deployer contract address deployed in the network",
type: "string",
default: "0xb31e712b26fd295357355f6845e77c888298636609e93bc9b05f0f604049f434",
} as const;
const WORMHOLE_OPTION = {
describe: "wormhole contract address deployed in the network",
type: "string",
default: "0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625",
} as const;
const PYTH_OPTION = {
describe: "pyth contract address deployed in the network",
@ -50,29 +56,6 @@ interface PackageBCS {
codeHash: Uint8Array;
}
const networks = new Map<string, Network>([
[
LOCALNET,
{
key: process.env["APTOS_LOCALNET_KEY"],
endpoint: "http://0.0.0.0:8080",
},
],
[
TESTNET,
{
key: process.env["APTOS_TESTNET_KEY"],
endpoint: "https://fullnode.testnet.aptoslabs.com/v1",
},
],
[
MAINNET,
{
key: process.env["APTOS_MAINNET_KEY"],
endpoint: "https://fullnode.mainnet.aptoslabs.com/v1",
},
],
]);
export const builder: (args: Argv<any>) => Argv<any> = (yargs) =>
yargs
.command(
@ -101,6 +84,37 @@ export const builder: (args: Argv<any>) => Argv<any> = (yargs) =>
await executeTransaction(argv.network, txPayload);
}
)
.command(
"deploy-wormhole <package-dir> <seed>",
"Deploy the wormhole package using a resource account.",
(yargs) => {
return yargs
.positional("package-dir", { type: "string" })
.positional("seed", { type: "string" })
.option("deployer", DEPLOYER_OPTION)
.option("network", NETWORK_OPTION);
},
async (argv) => {
const sender = getSender();
const derivedAddress = generateDerivedAddress(
sender.address().toString(),
argv.seed!
);
const namedAddresses = `deployer=${argv.deployer},wormhole=0x${derivedAddress}`;
console.log("Building the package with the following named addresses:");
console.log(`Deployer=${argv.deployer}`);
console.log(`Wormhole=${derivedAddress}`);
const txPayload = createDeployDerivedTransaction(
argv["package-dir"],
argv.deployer,
argv.seed,
namedAddresses
);
await executeTransaction(argv.network, txPayload);
}
)
.command(
"deploy-pyth <package-dir> <seed>",
"Deploy the pyth package using a resource account.",
@ -113,7 +127,7 @@ export const builder: (args: Argv<any>) => Argv<any> = (yargs) =>
.option("network", NETWORK_OPTION);
},
async (argv) => {
const sender = getSender(argv.network);
const sender = getSender();
const derivedAddress = generateDerivedAddress(
sender.address().toString(),
argv.seed!
@ -124,36 +138,31 @@ export const builder: (args: Argv<any>) => Argv<any> = (yargs) =>
console.log(`Wormhole=${argv.wormhole}`);
console.log(`Deployer=${argv.deployer}`);
console.log(`Pyth=${derivedAddress}`);
const artifact = serializePackage(
buildPackage(argv["package-dir"]!, namedAddresses)
);
const txPayload = new TxnBuilderTypes.TransactionPayloadEntryFunction(
TxnBuilderTypes.EntryFunction.natural(
argv.deployer + "::deployer",
"deploy_derived",
[],
[
artifact.meta,
artifact.bytecodes,
BCS.bcsSerializeBytes(Buffer.from(argv["seed"]!, "ascii")),
]
)
const txPayload = createDeployDerivedTransaction(
argv["package-dir"],
argv.deployer,
argv.seed,
namedAddresses
);
await executeTransaction(argv.network, txPayload);
}
)
.command(
"derived-address <seed> <signer>",
"derived-address <seed>",
"Generate the derived address for the given seed and sender address",
(yargs) => {
return yargs
.positional("seed", { type: "string", demandOption: true })
.positional("signer", { type: "string", demandOption: true });
.option("signer", { type: "string" });
},
async (argv) => {
console.log(generateDerivedAddress(argv.signer, argv.seed));
console.log(
generateDerivedAddress(
argv.signer || getSender().address().toString(),
argv.seed
)
);
}
)
.command(
@ -162,39 +171,15 @@ export const builder: (args: Argv<any>) => Argv<any> = (yargs) =>
(yargs) => {
return yargs
.option("network", NETWORK_OPTION)
.option("chain-id", {
describe: "Chain id",
type: "number",
default: 22,
demandOption: false,
})
.option("governance-chain-id", {
describe: "Governance chain id",
type: "number",
default: 1,
demandOption: false,
})
.option("governance-address", {
describe: "Governance address",
type: "string",
default:
"0x0000000000000000000000000000000000000000000000000000000000000004",
demandOption: false,
})
.option("guardian-address", {
alias: "g",
demandOption: true,
describe: "Initial guardian's address",
type: "string",
});
.option("channel", CHANNEL_OPTION);
},
async (argv) => {
const guardian_address = evm_address(
argv["guardian-address"]
).substring(24);
const chain_id = argv["chain-id"];
const governance_address = evm_address(argv["governance-address"]);
const governance_chain_id = argv["governance-chain-id"];
const chain_id = DefaultStore.chains[argv.network].getWormholeChainId();
const config = getDefaultDeploymentConfig(argv.channel).wormholeConfig;
const governance_contract = config.governanceContract;
const governance_chain_id = config.governanceChainId;
const guardian_address = config.initialGuardianSet[0]; // assuming only one guardian for now
const guardian_addresses_serializer = new BCS.Serializer();
guardian_addresses_serializer.serializeU32AsUleb128(1);
@ -205,10 +190,10 @@ export const builder: (args: Argv<any>) => Argv<any> = (yargs) =>
const args = [
BCS.bcsSerializeUint64(chain_id),
BCS.bcsSerializeUint64(governance_chain_id),
BCS.bcsSerializeBytes(Buffer.from(governance_address, "hex")),
BCS.bcsSerializeBytes(Buffer.from(governance_contract, "hex")),
guardian_addresses_serializer.getBytes(),
];
const sender = getSender(argv.network);
const sender = getSender();
const wormholeAddress = generateDerivedAddress(
sender.address().hex(),
"wormhole"
@ -216,7 +201,7 @@ export const builder: (args: Argv<any>) => Argv<any> = (yargs) =>
const txPayload = new TxnBuilderTypes.TransactionPayloadEntryFunction(
TxnBuilderTypes.EntryFunction.natural(
`${wormholeAddress}::wormhole`,
"init_2",
"init",
[],
args
)
@ -237,57 +222,37 @@ export const builder: (args: Argv<any>) => Argv<any> = (yargs) =>
type: "number",
demandOption: true,
})
.option("governance-emitter-chain-id", {
describe: "Governance emitter chain id",
type: "number",
demandOption: true,
})
.option("governance-emitter-address", {
describe: "Governance emitter address",
type: "string",
demandOption: true,
})
.option("update-fee", {
describe: "Update fee",
type: "number",
demandOption: true,
})
.option("data-source-chain-ids", {
describe: "Data source chain IDs",
type: "array",
demandOption: true,
})
.option("data-source-emitter-addresses", {
describe: "Data source emitter addresses",
type: "array",
demandOption: true,
});
.option("channel", CHANNEL_OPTION);
},
async (argv) => {
const stale_price_threshold = argv["stale-price-threshold"];
const governance_emitter_chain_id = argv["governance-emitter-chain-id"];
const governance_emitter_address = evm_address(
argv["governance-emitter-address"]
);
const update_fee = argv["update-fee"];
const config = getDefaultDeploymentConfig(argv.channel);
const governance_emitter_chain_id =
config.governanceDataSource.emitterChain;
const governance_emitter_address =
config.governanceDataSource.emitterAddress;
const dataSourceChainIdsSerializer = new BCS.Serializer();
dataSourceChainIdsSerializer.serializeU32AsUleb128(
argv["data-source-chain-ids"].length
config.dataSources.length
);
argv["data-source-chain-ids"].forEach((chain_id: number) =>
dataSourceChainIdsSerializer.serializeU64(chain_id)
);
const dataSourceEmitterAddressesSerializer = new BCS.Serializer();
dataSourceEmitterAddressesSerializer.serializeU32AsUleb128(
argv["data-source-emitter-addresses"].length
config.dataSources.length
);
argv["data-source-emitter-addresses"].forEach((emitter_address) => {
config.dataSources.forEach((ds) => {
dataSourceChainIdsSerializer.serializeU64(ds.emitterChain);
dataSourceEmitterAddressesSerializer.serializeBytes(
Buffer.from(emitter_address as string, "hex")
Buffer.from(ds.emitterAddress, "hex")
);
});
const update_fee = argv["update-fee"];
const args = [
BCS.bcsSerializeUint64(stale_price_threshold),
@ -297,7 +262,7 @@ export const builder: (args: Argv<any>) => Argv<any> = (yargs) =>
dataSourceEmitterAddressesSerializer.getBytes(),
BCS.bcsSerializeUint64(update_fee),
];
const sender = getSender(argv.network);
const sender = getSender();
const pythAddress = generateDerivedAddress(
sender.address().hex(),
argv.seed
@ -383,7 +348,8 @@ export const builder: (args: Argv<any>) => Argv<any> = (yargs) =>
.option("network", NETWORK_OPTION);
},
async (argv) => {
const endpoint = networks.get(argv.network)!.endpoint;
const endpoint = (DefaultStore.chains[argv.network] as AptosChain)
.rpcUrl;
const addr1 = argv["addr-1"];
const addr2 = argv["addr-2"];
const url = `${endpoint}/accounts/${addr1}/resource/0x1::code::PackageRegistry`;
@ -416,22 +382,23 @@ export const builder: (args: Argv<any>) => Argv<any> = (yargs) =>
)
.demandCommand();
function getSender(network: string) {
if (networks.get(network)!.key === undefined) {
function getSender() {
const key = process.env["APTOS_PRIVATE_KEY"];
if (key === undefined) {
throw new Error(
`No key for network ${network}. Please set the APTOS_${network.toUpperCase()}_KEY environment variable.`
`Please set the APTOS_PRIVATE_KEY environment variable to the private key of the sender in hex format`
);
}
return new AptosAccount(
new Uint8Array(Buffer.from(networks.get(network)!.key!, "hex"))
);
return new AptosAccount(new Uint8Array(Buffer.from(key, "hex")));
}
async function executeTransaction(
network: string,
txPayload: TxnBuilderTypes.TransactionPayloadEntryFunction
) {
const client = new AptosClient(networks.get(network)!.endpoint);
const sender = getSender(network);
const endpoint = (DefaultStore.chains[network] as AptosChain).rpcUrl;
const client = new AptosClient(endpoint);
const sender = getSender();
console.log(
await client.generateSignSubmitWaitForTransaction(sender, txPayload, {
maxGasAmount: BigInt(30000),
@ -528,6 +495,28 @@ function serializePackage(p: Package): PackageBCS {
};
}
function createDeployDerivedTransaction(
packageDir: string,
deployer: string,
seed: string,
namedAddresses: string
) {
const artifact = serializePackage(buildPackage(packageDir, namedAddresses));
return new TxnBuilderTypes.TransactionPayloadEntryFunction(
TxnBuilderTypes.EntryFunction.natural(
deployer + "::deployer",
"deploy_derived",
[],
[
artifact.meta,
artifact.bytecodes,
BCS.bcsSerializeBytes(Buffer.from(seed, "ascii")),
]
)
);
}
function hex(x: string): string {
return ethers.utils.hexlify(x, { allowMissingPrefix: true });
}

View File

@ -0,0 +1,16 @@
[
{
"contractName": "Migrations",
"address": "0xf5BBe9558F4Bf37F1eB82fb2CEdb1C775FA56832"
},
{
"contractName": "WormholeReceiver",
"address": "0x8250f4aF4B972684F7b336503E2D6dFeDeB1487a",
"transactionHash": "0x9e86ade70d9383cb16171450d6047f60d9df8061a165988abd52735e66d35126"
},
{
"contractName": "PythUpgradable",
"address": "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
"transactionHash": "0xc5a932f9bf50032493843be32939929f6bd9ec848ff8aa52f91489d31f403145"
}
]