Solidity

正確編譯的 remix 合約返回空 ABI

  • April 11, 2021

我有兩個問題。我的合約已經使用 remix 和 truffle 成功編譯和部署。但是: q1) remix 返回一個空的 ABI 數組。

在此處輸入圖像描述

此外,在我點擊左下角的編譯契約後,更改回 Context.sol 而不是 ww1.sol。

在此處輸入圖像描述

q2) 在 Truffle 中,合約的 json 文件在 build/contracts/ 文件夾中的 abi 如下:

[{ "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, { "indexed": true, "internalType": "address", "name": "spender", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "Approval", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "delegator", "type": "address" }, { "indexed": true, "internalType": "address", "name": "fromDelegate", "type": "address" }, { "indexed": true, "internalType": "address", "name": "toDelegate", "type": "address" } ], "name": "DelegateChanged", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "delegate", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "previousBalance", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "newBalance", "type": "uint256" } ], "name": "DelegateVotesChanged", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "OwnershipTransferred", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "from", "type": "address" }, { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "Transfer", "type": "event" }, { "inputs": [], "name": "DELEGATION_TYPEHASH", "outputs": [ { "internalType": "bytes32", "name": "", "type": "bytes32" } ], "stateMutability": "view", "type": "function", "constant": true }, { "inputs": [], "name": "DOMAIN_TYPEHASH", "outputs": [ { "internalType": "bytes32", "name": "", "type": "bytes32" } ], "stateMutability": "view", "type": "function", "constant": true }, { "inputs": [ { "internalType": "address", "name": "owner", "type": "address" }, { "internalType": "address", "name": "spender", "type": "address" } ], "name": "allowance", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function", "constant": true }, { "inputs": [ { "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "approve", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "account", "type": "address" } ], "name": "balanceOf", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function", "constant": true }, { "inputs": [ { "internalType": "address", "name": "", "type": "address" }, { "internalType": "uint32", "name": "", "type": "uint32" } ], "name": "checkpoints", "outputs": [ { "internalType": "uint32", "name": "fromBlock", "type": "uint32" }, { "internalType": "uint256", "name": "votes", "type": "uint256" } ], "stateMutability": "view", "type": "function", "constant": true }, { "inputs": [], "name": "decimals", "outputs": [ { "internalType": "uint8", "name": "", "type": "uint8" } ], "stateMutability": "view", "type": "function", "constant": true }, { "inputs": [ { "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "subtractedValue", "type": "uint256" } ], "name": "decreaseAllowance", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "getOwner", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "stateMutability": "view", "type": "function", "constant": true }, { "inputs": [ { "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "addedValue", "type": "uint256" } ], "name": "increaseAllowance", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "name", "outputs": [ { "internalType": "string", "name": "", "type": "string" } ], "stateMutability": "view", "type": "function", "constant": true }, { "inputs": [ { "internalType": "address", "name": "", "type": "address" } ], "name": "nonces", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function", "constant": true }, { "inputs": [ { "internalType": "address", "name": "", "type": "address" } ], "name": "numCheckpoints", "outputs": [ { "internalType": "uint32", "name": "", "type": "uint32" } ], "stateMutability": "view", "type": "function", "constant": true }, { "inputs": [], "name": "owner", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "stateMutability": "view", "type": "function", "constant": true }, { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "symbol", "outputs": [ { "internalType": "string", "name": "", "type": "string" } ], "stateMutability": "view", "type": "function", "constant": true }, { "inputs": [], "name": "totalSupply", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function", "constant": true }, { "inputs": [ { "internalType": "address", "name": "recipient", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "transfer", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "sender", "type": "address" }, { "internalType": "address", "name": "recipient", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "transferFrom", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "transferOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "_to", "type": "address" }, { "internalType": "uint256", "name": "_amount", "type": "uint256" } ], "name": "mint", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "mint", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "delegator", "type": "address" } ], "name": "delegates", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "stateMutability": "view", "type": "function", "constant": true }, { "inputs": [ { "internalType": "address", "name": "delegatee", "type": "address" } ], "name": "delegate", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "delegatee", "type": "address" }, { "internalType": "uint256", "name": "nonce", "type": "uint256" }, { "internalType": "uint256", "name": "expiry", "type": "uint256" }, { "internalType": "uint8", "name": "v", "type": "uint8" }, { "internalType": "bytes32", "name": "r", "type": "bytes32" }, { "internalType": "bytes32", "name": "s", "type": "bytes32" } ], "name": "delegateBySig", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "account", "type": "address" } ], "name": "getCurrentVotes", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function", "constant": true }, { "inputs": [ { "internalType": "address", "name": "account", "type": "address" }, { "internalType": "uint256", "name": "blockNumber", "type": "uint256" } ], "name": "getPriorVotes", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function", "constant": true }]

當我使用這個 abi 並嘗試在 testnet 上驗證和發布我的契約時,我收到以下錯誤:

Error! Invalid constructor arguments provided. Please verify that they are in ABI-encoded format

我怎樣才能得到正確的格式 abi,​​以便我可以驗證我的契約。

更新: 我嘗試使用 truffle-plugin-verify 來驗證 truffle 上的智能合約,它給了我以下錯誤。它再次指向 Context.sol 文件,但我不明白為什麼,因為該文件在 GSN 文件夾中對我可見。

Cannot find module '@pancakeswap/pancake-swap-lib/contracts/GSN/Context.sol'
Require stack:
- C:\Users\DELL\node_modules\truffle-plugin-verify\verify.js
- C:\Users\DELL\AppData\Roaming\npm\node_modules\truffle\node_modules\original-require\index.js
- C:\Users\DELL\AppData\Roaming\npm\node_modules\truffle\build\cli.bundled.js
Failed to verify 1 contract(s): NiftToken

NiftToken.sol

//SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

import "@pancakeswap/pancake-swap-lib/contracts/token/BEP20/BEP20.sol";

// NiftToken with Governance.
contract NiftToken is BEP20("NiftySwap Token", "NIFT") {
   /// @notice Creates `_amount` token to `_to`. Must only be called by the owner (MasterChef).
   function mint(address _to, uint256 _amount) public onlyOwner {
       _mint(_to, _amount);
       _moveDelegates(address(0), _delegates[_to], _amount);
   }

   // Copied and modified from YAM code:
   // https://github.com/yam-finance/yam-protocol/blob/master/contracts/token/YAMGovernanceStorage.sol
   // https://github.com/yam-finance/yam-protocol/blob/master/contracts/token/YAMGovernance.sol
   // Which is copied and modified from COMPOUND:
   // https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/Comp.sol

   /// @notice A record of each accounts delegate
   mapping(address => address) internal _delegates;

   /// @notice A checkpoint for marking number of votes from a given block
   struct Checkpoint {
       uint32 fromBlock;
       uint256 votes;
   }

   /// @notice A record of votes checkpoints for each account, by index
   mapping(address => mapping(uint32 => Checkpoint)) public checkpoints;

   /// @notice The number of checkpoints for each account
   mapping(address => uint32) public numCheckpoints;

   /// @notice The EIP-712 typehash for the contract's domain
   bytes32 public constant DOMAIN_TYPEHASH =
       keccak256(
           "EIP712Domain(string name,uint256 chainId,address verifyingContract)"
       );

   /// @notice The EIP-712 typehash for the delegation struct used by the contract
   bytes32 public constant DELEGATION_TYPEHASH =
       keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");

   /// @notice A record of states for signing / validating signatures
   mapping(address => uint256) public nonces;

   /// @notice An event thats emitted when an account changes its delegate
   event DelegateChanged(
       address indexed delegator,
       address indexed fromDelegate,
       address indexed toDelegate
   );

   /// @notice An event thats emitted when a delegate account's vote balance changes
   event DelegateVotesChanged(
       address indexed delegate,
       uint256 previousBalance,
       uint256 newBalance
   );

   /**
    * @notice Delegate votes from `msg.sender` to `delegatee`
    * @param delegator The address to get delegatee for
    */
   function delegates(address delegator) external view returns (address) {
       return _delegates[delegator];
   }

   /**
    * @notice Delegate votes from `msg.sender` to `delegatee`
    * @param delegatee The address to delegate votes to
    */
   function delegate(address delegatee) external {
       return _delegate(msg.sender, delegatee);
   }

   /**
    * @notice Delegates votes from signatory to `delegatee`
    * @param delegatee The address to delegate votes to
    * @param nonce The contract state required to match the signature
    * @param expiry The time at which to expire the signature
    * @param v The recovery byte of the signature
    * @param r Half of the ECDSA signature pair
    * @param s Half of the ECDSA signature pair
    */
   function delegateBySig(
       address delegatee,
       uint256 nonce,
       uint256 expiry,
       uint8 v,
       bytes32 r,
       bytes32 s
   ) external {
       bytes32 domainSeparator =
           keccak256(
               abi.encode(
                   DOMAIN_TYPEHASH,
                   keccak256(bytes(name())),
                   getChainId(),
                   address(this)
               )
           );

       bytes32 structHash =
           keccak256(
               abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry)
           );

       bytes32 digest =
           keccak256(
               abi.encodePacked("\x19\x01", domainSeparator, structHash)
           );

       address signatory = ecrecover(digest, v, r, s);
       require(
           signatory != address(0),
           "NIFT::delegateBySig: invalid signature"
       );
       require(
           nonce == nonces[signatory]++,
           "NIFT::delegateBySig: invalid nonce"
       );
       require(now <= expiry, "NIFT::delegateBySig: signature expired");
       return _delegate(signatory, delegatee);
   }

   /**
    * @notice Gets the current votes balance for `account`
    * @param account The address to get votes balance
    * @return The number of current votes for `account`
    */
   function getCurrentVotes(address account) external view returns (uint256) {
       uint32 nCheckpoints = numCheckpoints[account];
       return
           nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;
   }

   /**
    * @notice Determine the prior number of votes for an account as of a block number
    * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
    * @param account The address of the account to check
    * @param blockNumber The block number to get the vote balance at
    * @return The number of votes the account had as of the given block
    */
   function getPriorVotes(address account, uint256 blockNumber)
       external
       view
       returns (uint256)
   {
       require(
           blockNumber < block.number,
           "NIFT::getPriorVotes: not yet determined"
       );

       uint32 nCheckpoints = numCheckpoints[account];
       if (nCheckpoints == 0) {
           return 0;
       }

       // First check most recent balance
       if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {
           return checkpoints[account][nCheckpoints - 1].votes;
       }

       // Next check implicit zero balance
       if (checkpoints[account][0].fromBlock > blockNumber) {
           return 0;
       }

       uint32 lower = 0;
       uint32 upper = nCheckpoints - 1;
       while (upper > lower) {
           uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow
           Checkpoint memory cp = checkpoints[account][center];
           if (cp.fromBlock == blockNumber) {
               return cp.votes;
           } else if (cp.fromBlock < blockNumber) {
               lower = center;
           } else {
               upper = center - 1;
           }
       }
       return checkpoints[account][lower].votes;
   }

   function _delegate(address delegator, address delegatee) internal {
       address currentDelegate = _delegates[delegator];
       uint256 delegatorBalance = balanceOf(delegator); // balance of underlying NIFTs (not scaled);
       _delegates[delegator] = delegatee;

       emit DelegateChanged(delegator, currentDelegate, delegatee);

       _moveDelegates(currentDelegate, delegatee, delegatorBalance);
   }

   function _moveDelegates(
       address srcRep,
       address dstRep,
       uint256 amount
   ) internal {
       if (srcRep != dstRep && amount > 0) {
           if (srcRep != address(0)) {
               // decrease old representative
               uint32 srcRepNum = numCheckpoints[srcRep];
               uint256 srcRepOld =
                   srcRepNum > 0
                       ? checkpoints[srcRep][srcRepNum - 1].votes
                       : 0;
               uint256 srcRepNew = srcRepOld.sub(amount);
               _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);
           }

           if (dstRep != address(0)) {
               // increase new representative
               uint32 dstRepNum = numCheckpoints[dstRep];
               uint256 dstRepOld =
                   dstRepNum > 0
                       ? checkpoints[dstRep][dstRepNum - 1].votes
                       : 0;
               uint256 dstRepNew = dstRepOld.add(amount);
               _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);
           }
       }
   }

   function _writeCheckpoint(
       address delegatee,
       uint32 nCheckpoints,
       uint256 oldVotes,
       uint256 newVotes
   ) internal {
       uint32 blockNumber =
           safe32(
               block.number,
               "NIFT::_writeCheckpoint: block number exceeds 32 bits"
           );

       if (
           nCheckpoints > 0 &&
           checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber
       ) {
           checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;
       } else {
           checkpoints[delegatee][nCheckpoints] = Checkpoint(
               blockNumber,
               newVotes
           );
           numCheckpoints[delegatee] = nCheckpoints + 1;
       }

       emit DelegateVotesChanged(delegatee, oldVotes, newVotes);
   }

   function safe32(uint256 n, string memory errorMessage)
       internal
       pure
       returns (uint32)
   {
       require(n < 2**32, errorMessage);
       return uint32(n);
   }

   function getChainId() internal pure returns (uint256) {
       uint256 chainId;
       assembly {
           chainId := chainid()
       }
       return chainId;
   }
}

上下文.sol

// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity >=0.4.0;

/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
contract Context {
   // Empty internal constructor, to prevent people from mistakenly deploying
   // an instance of this contract, which should be used via inheritance.
   constructor() internal {}

   function _msgSender() internal view returns (address payable) {
       return msg.sender;
   }

   function _msgData() internal view returns (bytes memory) {
       this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
       return msg.data;
   }
}

當您點擊“Compile ww1.sol”時,remix 將編譯該solidity 文件中的所有合約。

編譯完成後ww1.sol,如果你改成Context (Context.sol)NiftToken (ww1.sol)注意:改成後不要再點擊編譯NiftToken)然後點擊編譯詳情,你會看到NiftToken的ABI

例子:

在此處輸入圖像描述

對於第二季度,

驗證此契約時不需要 ABI,因為契約的建構子不接受任何參數(也會自動獲取),因此您可以將其留空並驗證。

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