PHP WebShell

Текущая директория: /opt/BitGoJS/examples/ts/avaxp

Просмотр файла: multisig-crosschain-export-import.ts

/**
 * Transfer AVAX from single-sig X-chain wallet to a BitGo multi-sig P-chain wallet.
 *
 * Copyright 2022, BitGo, Inc.  All Rights Reserved.
 */
import { Avalanche, BinTools, BN, Buffer } from 'avalanche';
import {
  AVMAPI,
  KeyChain as AVMKeyChain,
  AmountOutput,
  UnsignedTx,
  ExportTx,
  TransferableOutput,
  TransferableInput,
  Tx as AVMTx,
} from 'avalanche/dist/apis/avm';
import {
  PlatformVMAPI,
  SECPTransferOutput,
  SECPTransferInput,
  UTXOSet,
  UTXO,
  UnsignedTx as PVMUnsignedTx,
  KeyChain as PlatformVMKeyChain,
  Tx as PlatformVMTx,
} from 'avalanche/dist/apis/platformvm';
import { Defaults, UnixNow } from 'avalanche/dist/utils';

type ChainConfig = {
  NODE_HOST: string;
  NODE_PORT: number;
  NODE_PROTOCOL: string;
  NODE_NETWORK_ID: number;
};

const FUJI: ChainConfig = {
  NODE_HOST: 'localhost',
  NODE_PORT: 9650,
  NODE_PROTOCOL: 'http',
  NODE_NETWORK_ID: 5,
};

// const MAINNET: ChainConfig = {
//   NODE_HOST: 'api.avax.network',
//   NODE_PORT: 9650,
//   NODE_PROTOCOL: 'http',
//   NODE_NETWORK_ID: 1,
// };

// Fuji or Mainnet config
const conf = FUJI;

// Private Key containing funds
// Example: PrivateKey-here
const avaxPrivateKey = '';

// multisig wallet receive addresses
// Example: [
//   'P-address1',
//   'P-address2',
//   'P-address3',
// ]
const pMultisigReceiveAddresses = [];

// amount to transfer cross-chain plus fees
const transferAmountVal = (1 + 0.002) * 1e9; // 1 AVAX + 0.002 AVAX fee

/*
 * This function transfers funds from a single X-chain wallet to a P-chain multisig wallet
 */
export async function crossChainTransfer(
  conf: ChainConfig,
  avaxPrivateKey: string,
  pMultisigReceiveAddresses: string[],
  transferAmountVal: number
): Promise<any> {
  // connect to network and get info
  console.log('Connecting to network...');
  const avalanche = new Avalanche(conf.NODE_HOST, conf.NODE_PORT, conf.NODE_PROTOCOL, conf.NODE_NETWORK_ID);
  const networkID = await avalanche.Info().getNetworkID();
  const networkName = await avalanche.Info().getNetworkName();
  console.log('Network:', { networkName, networkID });

  // set basic params
  const bintools: BinTools = BinTools.getInstance();
  const avaxAssetID: string = Defaults.network[networkID].P.avaxAssetID as string;
  const avaxAssetIDBuf = bintools.cb58Decode(avaxAssetID);
  const locktime: BN = new BN(0);
  const memo: Buffer = Buffer.from('Manually Export AVAX from single-sig X-Chain to multi-sig P-Chain');
  const xBlockchainID: string = Defaults.network[networkID].X.blockchainID;
  const pBlockchainID: string = Defaults.network[networkID].P.blockchainID;

  // import the key into keychains
  const pchain: PlatformVMAPI = avalanche.PChain();
  const xchain: AVMAPI = avalanche.XChain();
  const xKeychain: AVMKeyChain = xchain.keyChain();
  const pKeychain: PlatformVMKeyChain = pchain.keyChain();
  xKeychain.importKey(avaxPrivateKey);
  pKeychain.importKey(avaxPrivateKey);

  // get X-chain address
  const xAddressesStrings = xKeychain.getAddressStrings();
  const xAddressesBufs = xKeychain.getAddresses();
  console.log('X-Chain addresses:', xAddressesStrings);

  // set fees
  const fee: BN = pchain.getDefaultTxFee();
  console.log(`Fee = ${fee}`);

  // get utxos
  const avmUTXOResponse: any = await xchain.getUTXOs(xAddressesStrings);
  const utxoSet: UTXOSet = avmUTXOResponse.utxos;
  const utxos: UTXO[] = utxoSet.getAllUTXOs();

  const outputs: TransferableOutput[] = [];
  const exportedOuts: TransferableOutput[] = [];
  const inputs: TransferableInput[] = [];

  let totalInputsAmount: BN = new BN(0);
  const transferAmount: BN = new BN(transferAmountVal);

  utxos.forEach((utxo: UTXO) => {
    // type 7 is transferable output
    if (utxo.getOutput().getTypeID() === 7 && totalInputsAmount.lt(transferAmount.add(fee).add(fee))) {
      console.log('\nSelected utxo:');

      // get amount and asset
      const amountOutput: AmountOutput = utxo.getOutput() as AmountOutput;
      const amount: BN = amountOutput.getAmount().clone();
      const assetID: Buffer = utxo.getAssetID();
      console.log(`utxo asset:amount = ${bintools.bufferToB58(assetID)}:${amount.toString()}`);

      // get utxo txid
      const txid: Buffer = utxo.getTxID();
      const outputidx: Buffer = utxo.getOutputIdx();
      console.log(`utxo txid:outputIdx = ${bintools.bufferToB58(txid)}:${new BN(outputidx).toString()}\n`);

      // create inputs
      const secpTransferInput: SECPTransferInput = new SECPTransferInput(amount);
      if (utxo.getOutput().getAddresses().length > 1) {
        throw Error('Exported UTXO should have only one address');
      }
      secpTransferInput.addSignatureIdx(0, xAddressesBufs[0]);

      const input: TransferableInput = new TransferableInput(txid, outputidx, assetID, secpTransferInput);
      inputs.push(input);
      totalInputsAmount = totalInputsAmount.add(amount);
    } else {
      throw Error('utxo is not avax');
    }
  });
  console.log(`total imported: amount = ${totalInputsAmount}\n`);

  // cross chain export output
  let secpTransferOutput: SECPTransferOutput = new SECPTransferOutput();
  secpTransferOutput = new SECPTransferOutput(transferAmount.sub(fee), xAddressesBufs, locktime, 1);

  // push exported output
  exportedOuts.push(new TransferableOutput(avaxAssetIDBuf, secpTransferOutput));
  console.log(`exported utxo: amount = ${secpTransferOutput.getAmount()}\n`);

  // create change
  const secpTransferOutputChange = new SECPTransferOutput(
    totalInputsAmount.sub(secpTransferOutput.getAmount().add(fee)),
    xAddressesBufs,
    locktime,
    1
  );

  // push change output
  outputs.push(new TransferableOutput(avaxAssetIDBuf, secpTransferOutputChange));
  console.log(`change utxo: amount = ${secpTransferOutputChange.getAmount()}\n`);

  // create export tx
  const exportTx: ExportTx = new ExportTx(
    networkID,
    bintools.cb58Decode(xBlockchainID),
    outputs,
    inputs,
    memo,
    bintools.cb58Decode(pBlockchainID),
    exportedOuts
  );

  const unsignedExportTx: UnsignedTx = new UnsignedTx(exportTx);
  const signedExportTx: AVMTx = unsignedExportTx.sign(xKeychain);

  console.log('Issuing Export...');
  const exportTxid: string = await xchain.issueTx(signedExportTx);
  console.log(`Export success! TXID: https://explorer-xp.avax-test.network/tx/${exportTxid}`);

  // sleep for 5 seconds
  console.log('Wait 5 seconds for export to confirm...');

  await new Promise((resolve) => setTimeout(resolve, 5000));

  // create import tx

  // X-chain exported out address strings
  const pxAddressStrings = xAddressesStrings.map((address) => {
    return 'P-' + address.slice(2);
  });

  // get the exported p utxos
  const platformVMUTXOResponse: any = await pchain.getUTXOs(pxAddressStrings, pBlockchainID);
  const pvmUtxoSet: UTXOSet = platformVMUTXOResponse.utxos;
  console.log(`pvmUtxoSet length = ${pvmUtxoSet.getAllUTXOs().length}`);

  // create import tx
  const unsignedImportTx: PVMUnsignedTx = await pchain.buildImportTx(
    pvmUtxoSet,
    pxAddressStrings,
    xBlockchainID,
    pMultisigReceiveAddresses,
    pxAddressStrings,
    pMultisigReceiveAddresses,
    memo,
    UnixNow(),
    locktime,
    2 // threshold of 2 in the resulting utxo
  );

  const signedImportTx: PlatformVMTx = unsignedImportTx.sign(pKeychain);
  console.log('Issuing Import...');
  const txid: string = await pchain.issueTx(signedImportTx);
  console.log(`Import Success! TXID: https://explorer-xp.avax-test.network/tx/${txid}`);

  await new Promise((resolve) => setTimeout(resolve, 5000));
}

crossChainTransfer(conf, avaxPrivateKey, pMultisigReceiveAddresses, transferAmountVal);

Выполнить команду


Для локальной разработки. Не используйте в интернете!