自定义Script

自定义Script

account.ts

// account.ts
import { AptosAccount, HexString } from "aptos";

const privKey = new HexString("Your private key").toUint8Array();
export const aptosAccount = new AptosAccount(privKey);

chain.ts

// chain.ts
import { AptosClient, FaucetClient, MaybeHexString, TokenClient } from "aptos";

const APTOS_NODE_URL_MAIN = 'https://fullnode.mainnet.aptoslabs.com'
const APTOS_NODE_URL_DEV = 'https://fullnode.devnet.aptoslabs.com'
const APTOS_FAUCET_URL_DEV = 'https://faucet.devnet.aptoslabs.com'

export const isMainnet = false;

// Initialize aptos client
// This client is used to interact with aptos blockchain
const aptosNodeUrl =  isMainnet ? APTOS_NODE_URL_MAIN : APTOS_NODE_URL_DEV;
export const aptosClient = new AptosClient(aptosNodeUrl);
export const tokenClient = new TokenClient(aptosClient);

// For dev purpose, we need to fund our account with faucet.
export const fundAccountForDev = (address: MaybeHexString) => {
  const faucetClient = new FaucetClient(APTOS_NODE_URL_DEV, APTOS_FAUCET_URL_DEV);
  faucetClient.fundAccount(address, 100_000_000);
}

load_bytecode.ts

// load_bytecode.ts
import fs from "fs";
import { HexString } from "aptos";

export const loadBytecode = (scriptPath: string) => {
  const moduleHex = fs.readFileSync(scriptPath).toString("hex");
  return new HexString(moduleHex).toUint8Array();
}

script_runner.ts

// script_runner.ts
import {
  AptosAccount,
  AptosClient,
  TxnBuilderTypes,
} from "aptos";

export type ScriptCtx = {
  bytecode: Uint8Array,
  ty_args: TxnBuilderTypes.TypeTag[],
  args: TxnBuilderTypes.TransactionArgument[]
}

export async function runScript(codeCtx: ScriptCtx, sender: AptosAccount, client: AptosClient) {
  const script = new TxnBuilderTypes.Script(codeCtx.bytecode, codeCtx.ty_args, codeCtx.args);
  const scriptFunctionPayload = new TxnBuilderTypes.TransactionPayloadScript(script);
  const [{ sequence_number: sequenceNumber }, chainId] = await Promise.all([
    client.getAccount(sender.address()),
    client.getChainId(),
  ]);
  const rawTxn = new TxnBuilderTypes.RawTransaction(
    TxnBuilderTypes.AccountAddress.fromHex(sender.address()),
    BigInt(sequenceNumber),
    scriptFunctionPayload,
    100000n,
    1000n,
    BigInt(Math.floor(Date.now() / 1000) + 60),
    new TxnBuilderTypes.ChainId(chainId),
  );
  const bcsTxn = AptosClient.generateBCSTransaction(sender, rawTxn);
  return client.submitSignedBCSTransaction(bcsTxn);
}

wait_txn.ts

// wait_txn.ts
import { AptosClient } from "aptos";

export async function waitForTransaction(txnHash: string, client: AptosClient) {
  let count = 0;
  while (count < 10) {
    let tx = await client.getTransactionByHash(txnHash);
    let isPending = tx.type == "pending_transaction";
    if (!isPending) {
      return { ok: true, error: null, data: tx } as { ok: true, error: null, data: typeof tx };
    }
    await new Promise((resolve) => setTimeout(resolve, 500));
    count += 1;
    if (count >= 10) {
      return { ok: false, error: "Transaction time out", data: null } as { ok: false, error: string, data: null };
    }
  }
}

main.ts

// main.ts
import { TxnBuilderTypes } from "aptos";
import { loadBytecode } from "./load_bytecode";
import { submitScriptTransaction, ScriptCtx } from "./submit_script_transaction";
import { waitForTransaction } from "./wait_txn";
import { aptosAccount } from "./accout";
import { aptosClient } from "./chain";

// example:
// codePath exp.: "xx/build/xx/bytecode_scripts/register_coin.mv"
// tyArgs exp.: "0xCAFE::Aptox::bitcoin"
// args : script function args
export const scriptTransaction = async (
  codePath: string,
  tyArgs: TxnBuilderTypes.TypeTag[],
  args: TxnBuilderTypes.TransactionArgument[]
  ) => {
  const bytecode = loadBytecode(codePath);
  const scriptCtx: ScriptCtx = { bytecode, tyArgs, args };
  
  const txn = await submitScriptTransaction(scriptCtx, aptosAccount, aptosClient);
  return waitForTransaction(txn.hash, aptosClient);
}

Last updated