Abi

如何以程式方式為智能合約交易生成數據有效負載?

  • May 2, 2020

一些錢包,例如 Gnosis Safe 多重簽名,沒有 web3.js 支持或內置 ABI 編碼器。如何創建呼叫智能合約功能並源自此類錢包的交易?

您需要有智能合約的 ABI 文件。然後,您可以使用 Node.js 控制台、JavaScript 或 TypeScript 生成有效負載,Data以觸發交易的智能合約函式呼叫。

撥打此類電話的步驟

  1. 獲取智能合約所需的 ABI 文件,通常來自 Github
  2. 為 ABI 編碼創建一個粘貼在 Node.js 控制台中的程式碼段。
  3. 獲取此程式碼段的結果以Data在事務中使用
  4. 創建一個新事務。To欄位是智能合約地址,Data值是腳本 ABI 編碼的結果。

這是一個使用 TypeScript 和 OpenZeppelin SDK 製作數據負載以供approve()呼叫的範例。

import { ZWeb3, Contracts } from '@openzeppelin/upgrades';
import { createProvider } from './src/utils/deploy';

const INFURA_PROJECT_ID = '...';

async function run(): Promise<void> {
 // Initialze
 const provider = createProvider([], INFURA_PROJECT_ID, 'mainnet');
 ZWeb3.initialize(provider);

 // Instiate contracts
 const DawnTokenImpl = Contracts.getFromLocal('DawnTokenImpl');
 const TokenSwap = Contracts.getFromLocal('TokenSwap');
 const token = DawnTokenImpl.at('0x580c8520dEDA0a441522AEAe0f9F7A5f29629aFa');
 const tokenSwap = DawnTokenImpl.at('0x2e776B7BFb8E8307E476BA4B77B21D4532ed47d2');
 const holder = '0xedae4cfB12ECfCDE46853f63aBa76D8EA3CF3871';

 // Read the full balance of the multisig wallet
 const allOfBalance = await token.methods.balanceOf(holder).call();

 // Approve this balance to be used for the token swap
 const dataPayload = token.methods.approve(tokenSwap.address, allOfBalance).encodeABI();
 console.log('Data payload for approve() tx is', dataPayload);
}

run();

範例輸出是

Data payload for approve() tx is 0x095ea7b30000000000000000000000002e776b7bfb8e8307e476ba4b77b21d4532ed47d20000000000000000000000000000000000000000004d50b9c6c40cb6192cfce0

有關如何在 OpenZeppelin SDK 環境中執行控制台腳本片段的更多資訊

對於Gnosis MultiSigWallet,我使用以下內容:

function submitTransaction(options, msWalletAddr, contractAddr, contractAbi, functionName, functionArgs, privateKey) {
   return sign(options, msWalletAddr, "submitTransaction", [contractAddr, "0", encode(contractAbi, functionName, functionArgs)], privateKey);
}

function confirmTransaction(options, msWalletAddr, transactionId, privateKey) {
   return sign(options, msWalletAddr, "confirmTransaction", [transactionId], privateKey);
}

function executeTransaction(options, msWalletAddr, transactionId, privateKey) {
   return sign(options, msWalletAddr, "executeTransaction", [transactionId], privateKey);
}

function revokeConfirmation(options, msWalletAddr, transactionId, privateKey) {
   return sign(options, msWalletAddr, "revokeConfirmation", [transactionId], privateKey);
}

options參數是一個包含以下欄位的對象:

  • price(天然氣價格)
  • limit(氣體限制)
  • nonce(交易隨機數)

功能signencode實現如下:

const EthereumTx = require("ethereumjs-tx");

function sign(options, msWalletAddr, actionName, actionArgs, privateKey) {
   const params = {
       value   : 0, 
       chainId : 1,
       gasPrice: Number(options.price), 
       gasLimit: Number(options.limit),
       nonce   : Number(options.nonce),
       to      : msWalletAddr, 
       data    : encode(MultiSigWalletAbi, actionName, actionArgs)
   };
   const ethereumTx = new EthereumTx(params);
   ethereumTx.sign(Buffer.from(privateKey.slice(2), "hex"));
   return ethereumTx.serialize().toString("hex");
}

function encode(contractAbi, functionName, functionArgs) {
   for (const object of contractAbi)
       if (object.name == functionName)
           return web3.eth.abi.encodeFunctionCall(object, functionArgs);
   throw new Error("function " + functionName + " does not exist");
}

變數web3MultiSigWalletAbi假定為全域變數並已初始化。


正如您從 中可以理解的那樣value: 0,上面的程式碼僅支持不傳遞乙太的函式,但可以通過傳遞很容易地啟用value輸入。

從 中可以理解chainId: 1,上面的程式碼僅支持部署在主網上的合約,但可以通過chainId輸入輕鬆啟用。

引用自:https://ethereum.stackexchange.com/questions/82981