您正在查看: Ethereum-优秀转载 分类下的文章

以太坊合约中是否可以获取交易hash?

答案:不能
txhash 是keccak256(signedTransaction).
此 keccak256 函数可用作 Solidity 函数 http://solidity.readthedocs.io/en/v0.4.21/units-and-global-variables.html

所以你需要构造,signedTransaction因为这个值没有暴露于可靠性,参见。https://stackoverflow.com/questions/49803424/how-can-we-access-rlp-encoded-signed-raw-transaction-in-solidity

signedTransaction 需要的参数是

  1. nonce
  2. gas price
  3. gas limit
  4. to
  5. value in wei
  6. data
  7. ecdsaV
  8. ecdsaR
  9. ecdsaS

值 3 不是直接可用的,但您可以在代码执行的任何时候获取当前剩余的 gas,并从中计算出执行开始后可用的气体量。值 1、7、8 和 9(nonce 和签名值)不能使用solidity,也不能使用汇编代码(可以在solidity 源代码文件中内联编写)。所以很遗憾该问题无法解决。

https://ethereum.stackexchange.com/questions/45648/how-to-calculate-the-assigned-txhash-of-a-transaction
https://github.com/ethereum/EIPs/issues/901

为什么LINK使用ERC-677标准发行token

等等,LINK不是ERC20吗,怎么又成了ERC677了?
别急,我们先从ERC20开始说起。

ERC20是一套协议标准,代码角度来说就是一套接口API。在这个协议标准下,只要实现了协议标准所规定的方法,都可以作为ERC20代币的实现。协议规定必须实现的方法有:

// 1. 代币发行总量
function totalSupply() public view returns (uint256)

// 2. _owner账户的代币余额
function balanceOf(address _owner) public view returns (uint256 balance)

// 3. 转移_value数量的代币到_to地址
function transfer(address _to, uint256 _value) public returns (bool success)

// 4. 从_address地址转移_value数量的代币到_to地址
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)

// 5. 允许_spender可以提取总额为_value数量的代币,提取不限次数
function approve(address _spender, uint256 _value) public returns (bool success)

// 6. 返回_spender还可以从_owner提取的代币数量
function allowance(address _owner, address _spender) public view returns (uint256 remaining)

除了这几个方法,ERC20还规定了两个事件:

// 当成功转移token时,触发Transfer事件,记录转账的发送方、接收方和转账金额
event Transfer(address indexed _from, address indexed _to, uint256 _value)

// 当调用approval函数成功时,触发Approval事件,记录批准的所有方、获取方和批准金额
event Approval(address indexed _owner, address indexed _spender, uint256 _value)

以上基本上就是ERC20代币的全部内容了。由于LINK代币不仅仅是代币,还承担了链上与链下数据传递的功能,所以如果使用ERC20代币的标准无法满足这个需求,于是LINK选择了ERC677协议标准来实现。

ERC677标准是ERC20的一个扩展,它继承了ERC20的所有方法和事件,由Chainlink的CTO Steve Ellis首次提出。ERC677除了包含了ERC20的所有方法和事件之外,增加了一个transferAndCall 方法:

function onTokenTransfer(address from, uint256 amount, bytes data) returns (bool success)

接收合约就可以在这个方法中定义自己的业务逻辑,可以在发生转账的时候自动触发。换句话说,智能合约中的业务逻辑,可以通过代币转账的方式来触发自动运行。这就给了智能合约的应用场景有了很大的想象空间。比如LINK的token合约就是一个ERC677合约,而Chainlink的Oracle合约,是一个可以接收ERC677的合约,它含有onTokenTransfer方法,可以在收到LINK的转账的时候执行预言机相关的业务逻辑。

LINK token contract:

...

  /**
  * @dev 转移token到合约地址,并携带额外数据
  * @param _to 转到的地址
  * @param _value 转账金额
  * @param _data 传递给接受合约的额外数据
  */
  function transferAndCall(address _to, uint _value, bytes _data)
    public
    returns (bool success)
  {
    super.transfer(_to, _value);
    Transfer(msg.sender, _to, _value, _data);
    if (isContract(_to)) {
      contractFallback(_to, _value, _data);
    }
    return true;
  }

...

Oracle 合约:

...

  /**
    * @notice 在LINK通过`transferAndCall`方法发送到合约时被调用
    * @dev 负载数据的前两个字节会被`_sender`和 `_amount`的值覆盖来保证正确性。并会调用oracleRequest方法
    * @param _sender 发送方地址
    * @param _amount 发送的LINK数量(单位是wei)
    * @param _data 交易的负载数据
    */
  function onTokenTransfer(
    address _sender,
    uint256 _amount,
    bytes _data
  )
    public
    onlyLINK
    validRequestLength(_data)
    permittedFunctionsForLINK(_data)
  {
    assembly {
      // solium-disable-next-line security/no-low-level-calls
      mstore(add(_data, 36), _sender) // ensure correct sender is passed
      // solium-disable-next-line security/no-low-level-calls
      mstore(add(_data, 68), _amount)    // ensure correct amount is passed
    }
    // solium-disable-next-line security/no-low-level-calls
    require(address(this).delegatecall(_data), "Unable to create request"); // calls oracleRequest
  }

...

总结:

LINK代币合约是ERC677合约,它是ERC20合约的一个扩展,兼容ERC20协议标准。它可以在转账时携带数据,并触发接收合约的业务逻辑,这一特点可以帮助智能合约扩大应用场景。

参考

https://eips.ethereum.org/EIPS/eip-20
http://blockchainers.org/index.php/2018/02/08/token-erc-comparison-for-fungible-tokens/
https://github.com/ethereum/EIPs/issues/677
https://etherscan.io/address/0x514910771af9ca656af840dff83e8264ecf986ca#code
https://etherscan.io/address/0x64fe692be4b42f4ac9d4617ab824e088350c11c2#code

转载自:https://learnblockchain.cn/article/588

openzeppelin ERC20合约的使用

推荐 :https://wizard.openzeppelin.com/

basic erc20

Snapshot 1

`// SPDX-License-Identifier: MIT␊
pragma solidity ^0.8.2;␊
␊
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";␊
␊
contract MyToken is ERC20 {␊
    constructor() ERC20("MyToken", "MTK") {}␊
}␊
`

erc20 with snapshots

Snapshot 1

`// SPDX-License-Identifier: MIT␊
pragma solidity ^0.8.2;␊
␊
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";␊
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Snapshot.sol";␊
import "@openzeppelin/contracts/access/Ownable.sol";␊
␊
contract MyToken is ERC20, ERC20Snapshot, Ownable {␊
    constructor() ERC20("MyToken", "MTK") {}␊
␊
    function snapshot() public onlyOwner {␊
        _snapshot();␊
    }␊
␊
    // The following functions are overrides required by Solidity.␊
␊
    function _beforeTokenTransfer(address from, address to, uint256 amount)␊
        internal␊
        override(ERC20, ERC20Snapshot)␊
    {␊
        super._beforeTokenTransfer(from, to, amount);␊
    }␊
}␊
`

erc20 burnable

Snapshot 1

`// SPDX-License-Identifier: MIT␊
pragma solidity ^0.8.2;␊
␊
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";␊
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";␊
␊
contract MyToken is ERC20, ERC20Burnable {␊
    constructor() ERC20("MyToken", "MTK") {}␊
}␊
`

erc20 burnable with snapshots

Snapshot 1

`// SPDX-License-Identifier: MIT␊
pragma solidity ^0.8.2;␊
␊
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";␊
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";␊
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Snapshot.sol";␊
import "@openzeppelin/contracts/access/Ownable.sol";␊
␊
contract MyToken is ERC20, ERC20Burnable, ERC20Snapshot, Ownable {␊
    constructor() ERC20("MyToken", "MTK") {}␊
␊
    function snapshot() public onlyOwner {␊
        _snapshot();␊
    }␊
␊
    // The following functions are overrides required by Solidity.␊
␊
    function _beforeTokenTransfer(address from, address to, uint256 amount)␊
        internal␊
        override(ERC20, ERC20Snapshot)␊
    {␊
        super._beforeTokenTransfer(from, to, amount);␊
    }␊
}␊
`

erc20 pausable

Snapshot 1

`// SPDX-License-Identifier: MIT␊
pragma solidity ^0.8.2;␊
␊
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";␊
import "@openzeppelin/contracts/security/Pausable.sol";␊
import "@openzeppelin/contracts/access/Ownable.sol";␊
␊
contract MyToken is ERC20, Pausable, Ownable {␊
    constructor() ERC20("MyToken", "MTK") {}␊
␊
    function pause() public onlyOwner {␊
        _pause();␊
    }␊
␊
    function unpause() public onlyOwner {␊
        _unpause();␊
    }␊
␊
    function _beforeTokenTransfer(address from, address to, uint256 amount)␊
        internal␊
        whenNotPaused␊
        override␊
    {␊
        super._beforeTokenTransfer(from, to, amount);␊
    }␊
}␊
`

erc20 pausable with roles

Snapshot 1

`// SPDX-License-Identifier: MIT␊
pragma solidity ^0.8.2;␊
␊
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";␊
import "@openzeppelin/contracts/security/Pausable.sol";␊
import "@openzeppelin/contracts/access/AccessControl.sol";␊
␊
contract MyToken is ERC20, Pausable, AccessControl {␊
    bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");␊
␊
    constructor() ERC20("MyToken", "MTK") {␊
        _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);␊
        _setupRole(PAUSER_ROLE, msg.sender);␊
    }␊
␊
    function pause() public onlyRole(PAUSER_ROLE) {␊
        _pause();␊
    }␊
␊
    function unpause() public onlyRole(PAUSER_ROLE) {␊
        _unpause();␊
    }␊
␊
    function _beforeTokenTransfer(address from, address to, uint256 amount)␊
        internal␊
        whenNotPaused␊
        override␊
    {␊
        super._beforeTokenTransfer(from, to, amount);␊
    }␊
}␊
`

erc20 burnable pausable

Snapshot 1

`// SPDX-License-Identifier: MIT␊
pragma solidity ^0.8.2;␊
␊
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";␊
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";␊
import "@openzeppelin/contracts/security/Pausable.sol";␊
import "@openzeppelin/contracts/access/Ownable.sol";␊
␊
contract MyToken is ERC20, ERC20Burnable, Pausable, Ownable {␊
    constructor() ERC20("MyToken", "MTK") {}␊
␊
    function pause() public onlyOwner {␊
        _pause();␊
    }␊
␊
    function unpause() public onlyOwner {␊
        _unpause();␊
    }␊
␊
    function _beforeTokenTransfer(address from, address to, uint256 amount)␊
        internal␊
        whenNotPaused␊
        override␊
    {␊
        super._beforeTokenTransfer(from, to, amount);␊
    }␊
}␊
`

erc20 burnable pausable with snapshots

Snapshot 1

`// SPDX-License-Identifier: MIT␊
pragma solidity ^0.8.2;␊
␊
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";␊
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";␊
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Snapshot.sol";␊
import "@openzeppelin/contracts/access/Ownable.sol";␊
import "@openzeppelin/contracts/security/Pausable.sol";␊
␊
contract MyToken is ERC20, ERC20Burnable, ERC20Snapshot, Ownable, Pausable {␊
    constructor() ERC20("MyToken", "MTK") {}␊
␊
    function snapshot() public onlyOwner {␊
        _snapshot();␊
    }␊
␊
    function pause() public onlyOwner {␊
        _pause();␊
    }␊
␊
    function unpause() public onlyOwner {␊
        _unpause();␊
    }␊
␊
    function _beforeTokenTransfer(address from, address to, uint256 amount)␊
        internal␊
        whenNotPaused␊
        override(ERC20, ERC20Snapshot)␊
    {␊
        super._beforeTokenTransfer(from, to, amount);␊
    }␊
}␊
`

erc20 preminted

Snapshot 1

`// SPDX-License-Identifier: MIT␊
pragma solidity ^0.8.2;␊
␊
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";␊
␊
contract MyToken is ERC20 {␊
    constructor() ERC20("MyToken", "MTK") {␊
        _mint(msg.sender, 1000 * 10 ** decimals());␊
    }␊
}␊
`

erc20 premint of 0

Snapshot 1

`// SPDX-License-Identifier: MIT␊
pragma solidity ^0.8.2;␊
␊
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";␊
␊
contract MyToken is ERC20 {␊
    constructor() ERC20("MyToken", "MTK") {}␊
}␊
`

erc20 mintable

Snapshot 1

`// SPDX-License-Identifier: MIT␊
pragma solidity ^0.8.2;␊
␊
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";␊
import "@openzeppelin/contracts/access/Ownable.sol";␊
␊
contract MyToken is ERC20, Ownable {␊
    constructor() ERC20("MyToken", "MTK") {}␊
␊
    function mint(address to, uint256 amount) public onlyOwner {␊
        _mint(to, amount);␊
    }␊
}␊
`

erc20 mintable with roles

Snapshot 1

`// SPDX-License-Identifier: MIT␊
pragma solidity ^0.8.2;␊
␊
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";␊
import "@openzeppelin/contracts/access/AccessControl.sol";␊
␊
contract MyToken is ERC20, AccessControl {␊
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");␊
␊
    constructor() ERC20("MyToken", "MTK") {␊
        _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);␊
        _setupRole(MINTER_ROLE, msg.sender);␊
    }␊
␊
    function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {␊
        _mint(to, amount);␊
    }␊
}␊
`

erc20 permit

Snapshot 1

`// SPDX-License-Identifier: MIT␊
pragma solidity ^0.8.2;␊
␊
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";␊
import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";␊
␊
contract MyToken is ERC20, ERC20Permit {␊
    constructor() ERC20("MyToken", "MTK") ERC20Permit("MyToken") {}␊
}␊
`

erc20 votes

Snapshot 1

`// SPDX-License-Identifier: MIT␊
pragma solidity ^0.8.2;␊
␊
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";␊
import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";␊
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol";␊
␊
contract MyToken is ERC20, ERC20Permit, ERC20Votes {␊
    constructor() ERC20("MyToken", "MTK") ERC20Permit("MyToken") {}␊
␊
    // The following functions are overrides required by Solidity.␊
␊
    function _afterTokenTransfer(address from, address to, uint256 amount)␊
        internal␊
        override(ERC20, ERC20Votes)␊
    {␊
        super._afterTokenTransfer(from, to, amount);␊
    }␊
␊
    function _mint(address to, uint256 amount)␊
        internal␊
        override(ERC20, ERC20Votes)␊
    {␊
        super._mint(to, amount);␊
    }␊
␊
    function _burn(address account, uint256 amount)␊
        internal␊
        override(ERC20, ERC20Votes)␊
    {␊
        super._burn(account, amount);␊
    }␊
}␊
`

erc20 flashmint

Snapshot 1

`// SPDX-License-Identifier: MIT␊
pragma solidity ^0.8.2;␊
␊
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";␊
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20FlashMint.sol";␊
␊
contract MyToken is ERC20, ERC20FlashMint {␊
    constructor() ERC20("MyToken", "MTK") {}␊
}␊
`

erc20 full upgradeable transparent

Snapshot 1

`// SPDX-License-Identifier: MIT␊
pragma solidity ^0.8.2;␊
␊
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";␊
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol";␊
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20SnapshotUpgradeable.sol";␊
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";␊
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";␊
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol";␊
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20VotesUpgradeable.sol";␊
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20FlashMintUpgradeable.sol";␊
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";␊
␊
contract MyToken is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, ERC20SnapshotUpgradeable, AccessControlUpgradeable, PausableUpgradeable, ERC20PermitUpgradeable, ERC20VotesUpgradeable, ERC20FlashMintUpgradeable {␊
    bytes32 public constant SNAPSHOT_ROLE = keccak256("SNAPSHOT_ROLE");␊
    bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");␊
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");␊
␊
    function initialize() initializer public {␊
        __ERC20_init("MyToken", "MTK");␊
        __ERC20Burnable_init();␊
        __ERC20Snapshot_init();␊
        __AccessControl_init();␊
        __Pausable_init();␊
        __ERC20Permit_init("MyToken");␊
        __ERC20FlashMint_init();␊
␊
        _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);␊
        _setupRole(SNAPSHOT_ROLE, msg.sender);␊
        _setupRole(PAUSER_ROLE, msg.sender);␊
        _mint(msg.sender, 2000 * 10 ** decimals());␊
        _setupRole(MINTER_ROLE, msg.sender);␊
    }␊
␊
    function snapshot() public onlyRole(SNAPSHOT_ROLE) {␊
        _snapshot();␊
    }␊
␊
    function pause() public onlyRole(PAUSER_ROLE) {␊
        _pause();␊
    }␊
␊
    function unpause() public onlyRole(PAUSER_ROLE) {␊
        _unpause();␊
    }␊
␊
    function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {␊
        _mint(to, amount);␊
    }␊
␊
    function _beforeTokenTransfer(address from, address to, uint256 amount)␊
        internal␊
        whenNotPaused␊
        override(ERC20Upgradeable, ERC20SnapshotUpgradeable)␊
    {␊
        super._beforeTokenTransfer(from, to, amount);␊
    }␊
␊
    // The following functions are overrides required by Solidity.␊
␊
    function _afterTokenTransfer(address from, address to, uint256 amount)␊
        internal␊
        override(ERC20Upgradeable, ERC20VotesUpgradeable)␊
    {␊
        super._afterTokenTransfer(from, to, amount);␊
    }␊
␊
    function _mint(address to, uint256 amount)␊
        internal␊
        override(ERC20Upgradeable, ERC20VotesUpgradeable)␊
    {␊
        super._mint(to, amount);␊
    }␊
␊
    function _burn(address account, uint256 amount)␊
        internal␊
        override(ERC20Upgradeable, ERC20VotesUpgradeable)␊
    {␊
        super._burn(account, amount);␊
    }␊
}␊
`

erc20 full upgradeable uups

Snapshot 1

`// SPDX-License-Identifier: MIT␊
pragma solidity ^0.8.2;␊
␊
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";␊
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol";␊
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20SnapshotUpgradeable.sol";␊
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";␊
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";␊
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol";␊
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20VotesUpgradeable.sol";␊
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20FlashMintUpgradeable.sol";␊
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";␊
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";␊
␊
contract MyToken is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, ERC20SnapshotUpgradeable, AccessControlUpgradeable, PausableUpgradeable, ERC20PermitUpgradeable, ERC20VotesUpgradeable, ERC20FlashMintUpgradeable, UUPSUpgradeable {␊
    bytes32 public constant SNAPSHOT_ROLE = keccak256("SNAPSHOT_ROLE");␊
    bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");␊
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");␊
    bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE");␊
␊
    function initialize() initializer public {␊
        __ERC20_init("MyToken", "MTK");␊
        __ERC20Burnable_init();␊
        __ERC20Snapshot_init();␊
        __AccessControl_init();␊
        __Pausable_init();␊
        __ERC20Permit_init("MyToken");␊
        __ERC20FlashMint_init();␊
        __UUPSUpgradeable_init();␊
␊
        _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);␊
        _setupRole(SNAPSHOT_ROLE, msg.sender);␊
        _setupRole(PAUSER_ROLE, msg.sender);␊
        _mint(msg.sender, 2000 * 10 ** decimals());␊
        _setupRole(MINTER_ROLE, msg.sender);␊
        _setupRole(UPGRADER_ROLE, msg.sender);␊
    }␊
␊
    function snapshot() public onlyRole(SNAPSHOT_ROLE) {␊
        _snapshot();␊
    }␊
␊
    function pause() public onlyRole(PAUSER_ROLE) {␊
        _pause();␊
    }␊
␊
    function unpause() public onlyRole(PAUSER_ROLE) {␊
        _unpause();␊
    }␊
␊
    function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {␊
        _mint(to, amount);␊
    }␊
␊
    function _beforeTokenTransfer(address from, address to, uint256 amount)␊
        internal␊
        whenNotPaused␊
        override(ERC20Upgradeable, ERC20SnapshotUpgradeable)␊
    {␊
        super._beforeTokenTransfer(from, to, amount);␊
    }␊
␊
    function _authorizeUpgrade(address newImplementation)␊
        internal␊
        onlyRole(UPGRADER_ROLE)␊
        override␊
    {}␊
␊
    // The following functions are overrides required by Solidity.␊
␊
    function _afterTokenTransfer(address from, address to, uint256 amount)␊
        internal␊
        override(ERC20Upgradeable, ERC20VotesUpgradeable)␊
    {␊
        super._afterTokenTransfer(from, to, amount);␊
    }␊
␊
    function _mint(address to, uint256 amount)␊
        internal␊
        override(ERC20Upgradeable, ERC20VotesUpgradeable)␊
    {␊
        super._mint(to, amount);␊
    }␊
␊
    function _burn(address account, uint256 amount)␊
        internal␊
        override(ERC20Upgradeable, ERC20VotesUpgradeable)␊
    {␊
        super._burn(account, amount);␊
    }␊
}␊
`

转载自:https://github.com/OpenZeppelin/contracts-wizard/blob/0dbf5d669adcdb8e801fbb67a269fc7931613d66/packages/core/src/erc20.test.ts.md

了解如何在 MetaMask 中设置交易 gas 费用

常见问题

EIP-1559 是什么?

EIP-1559 将改变以太坊的市场机制来支付交易费用。从根本上讲,EIP-1559 摆脱了首价拍卖,取而代之的是固定价格拍卖。这一变化的意义在于,提交交易的人不必猜测需要多少 gas,因为下一个区块中将包含明确的“基本费用”。对于想要优先处理交易的用户或应用程序,他们可以添加“小费”以支付矿工费用。您可以在此处更详细地了解 EIP-1559 以及它将如何改变以太坊。

EIP-1559 会使 ETH 通货紧缩吗?

EIP-1559
烧伤花掉的交易费基本费用的ETH。该 ETH 从供应中移除。在 EIP-1559 下,ETH 变得更加稀缺,因为以太坊上的所有交易都会消耗一定数量的 ETH。

对 EIP-1559 的通货紧缩程度进行准确建模是很困难的,因为您必须预测诸如预期交易之类的变量,甚至更难预测的是预期网络拥堵。从理论上讲,发生的交易越多,基本费用的燃烧对整个以太坊供应的通货紧缩压力就越大。根据网络上发生的交易数量,ETH 供应可能会在不同时间减少或膨胀更多

在与 Proof of Stake 合并后,Justin Drake 的模型估计每天将发行 1,000 ETH,并将燃烧 6,000 ETH 作为“最佳猜测”。假设有更多验证者加入,Staking APR 为 6.7%,那么年供应变化将为 -160 万 ETH,年供应率降低 1.4%。

尽管人们越来越意识到 MEV 和潜在的 EIP 会带来更高的透明度,但我们可以预期,随着机构金融交易者使用 DeFi 协议,套利机会只会变得更加复杂。这可能意味着每个区块的小费最终可能会比基本费用多得多。朱苏和Hasu实际预测,不到一半的今天的费用可以通过EIP
1559年

已经烧掉了多少 ETH?

你可以在这里跟踪。

作为 EIP-1559 的用户,我有什么变化?

这个想法是使用户的gas费用或多或少透明。因此,钱包将能够有更好的估计并使交易费用更可预测。他们不必过多依赖外部预言机,因为基本费用由协议本身管理。将有额外的用户体验优势,例如自动化费用竞标机制,从而减少交易确认的延迟。

此更改何时推出?

EIP-1559 将于 8 月 5 日在以太坊主网上上线,届时我们将开始推出此更改。目前,它在 Ropsten、Rinkeby、Goerli 网络中可用。

费用

EIP-1559 会使汽油更便宜吗?

不,这不是 EIP 的意图。作为更可预测的基本费用的副作用,如果我们假设费用的可预测性意味着用户不会频繁地为 Gas 多付钱,那么 EIP-1559 可能会导致 Gas 价格有所下降。使用 EIP-1559,在区块填充超过 50% 后,基础费用将增加和减少 12.5%。例如,如果一个区块 100% 满,基础费用增加 12.5%;如果是 50%,基本费用将相同;如果是 0%,基本费用将减少 12.5%。

应用程序向汇总和第 2 层的持续移动将大大降低费用。

如何设置正确的gas费用?

MetaMask 在设置 gas 费用时会为您提供三个选项:

  • 高:这是掉期或其他时间敏感交易的最佳选择。如果掉期处理时间过长,它通常会失败,您可能会损失资金。
  • 中:这有利于发送资产、提取资产或其他非时间敏感但重要的交易。
  • 低:仅应为处理时间不太重要的交易选择较低的 gas 费用。由于费用较低,很难预测您的交易何时(或是否)会成功。

我应该编辑gas费用吗?

您可以在高、中或低汽油费之间进行选择。请参阅上面的问题以了解这些含义。此外,您可以在“高级选项”设置中编辑您的 gas 限额、优先费用和最高费用。这将覆盖 MetaMask 为您“推荐”的低、中或高设置。

我的交易在 EIP-1559 上的速度有多快?

这暂时还不得而知。预测是由于 gas 费的可预测性,交易将进行得更快。

汽油费是如何计算的?

Gas 费用由区块的满量决定。EIP-1559 建立了交易包含的市场费率,并允许以太坊拥有双倍的区块空间(通过将每个区块的最大 gas 限制从 12.5M 增加到 25M)。然后它将块定位为只有 50% 满。

当网络利用率 > 50% 时,基础费用增加
当网络利用率 < 50% 时,基础费用减少

随着时间的推移,以太坊的区块大小将平均为相同的大小,但这种额外的容量允许具有交易包容性的灵活性。从本质上讲,它将消除设置天然气价格以进行交易的额外步骤。

MetaMask 的汽油费是否比其他任何地方都高?

不,MetaMask 使用与其他钱包如何估算 gas 价格类似的 gas 估算预言机的汇编。我们相信我们可以提供有竞争力的气体估算。

估计的gas费用与我实际支付的费用有多少不同?

估计的gas费用是一个范围。此范围的上限是用户将为交易支付的最高金额。在 EIP-1559 推出后,我们应该能够从我们的 gas 估计范围分析我们的交易包含率。

我应该考虑采用不同的方法来为掉期交易和其他交易设置 gas 费用吗?

MetaMask 将提供三个选项来设置 gas 费用:高、中和低(更多详细信息在“我如何设置正确的 gas 费用?”上方的常见问题解答中),并且会预先选择我们认为与您的交易类型相关的费用。如果您愿意,可以更改此设置,但我们会提供最佳建议。对于掉期等时间敏感的交易,我们建议并会预先选择“高”的gas费用。

什么是基本费用/最高费用/优先费用/等。是什么意思?

有关(新)术语的详细定义,请参阅我们的词汇表

由于我设置了“最高优先费用”,我如何才能看到我实际为交易支付的金额?

您可以查看已支付的估计 gas 费用的交易活动,或在区块浏览器(如 Etherscan)上查看交易收据中的“有效GasPrice”。

我可以在没有优先费(“矿工小费”)的情况下进行交易吗?

是的,你可以,但有可能其他交易(确实包括优先费)将被优先考虑,因为矿工被激励包含优先费的交易。

典型用户会选择“小费”金额还是为用户预选的总费用的一部分?

“小费”将作为用户在提交交易时看到的总体“汽油费”中包含在内。您还可以“编辑汽油费”以增加或减少称为“优先费”的“小费”。

在哪里可以看到他们为小费支付的费用?像 Etherscan 这样的区块浏览器现在会显示这些信息吗?

大多数工具将相应更新以显示与 EIP 相关的新信息。交易收据中现在将有一个“effectiveGasPrice”,它返回交易执行后支付的价格(即基本费用+优先费用)。

集成

EIP-1559 如何与 MetaMask 上的 Trezor/Ledger 集成一起工作?

Trezor 和 Ledger 尚不支持 EIP-1559,因此 MetaMask 将回退到 EIP-1559 之前的气体控制。

是在钱包还是 dapp 级别上实现?换句话说,我所有的 dapp 连接都会显示钱包中的新界面,还是只显示采用 EIP-1559 的 dapp?

如果 dapp 尚未切换到新的 EIP-1559 字段,MetaMask 将检测到这一点并使用 gasPrice 作为 maxFeePerGas。这意味着用户可能会为他们的交易多付钱。

用户体验

EIP-1559 还能如何改变钱包用户体验?

这将因钱包而异。这个想法是让基于区块需求的费用对用户更加透明。像 MetaMask 这样的钱包将能够有更好的估计,并且不必过多依赖外部预言机,因为基本费用由协议本身管理。此外,在使用 MetaMask 时,您可以决定高、中或低 gas 费。虽然会预先选择推荐类型,但用户可以在确认交易之前进行更改。此外,用户可以在“高级”设置中更改最高费用、最高优先费用和 Gwei。这样做将覆盖初始的高、中或低设置。

在网络拥塞期间,用户体验是否会有所不同?

在网络严重拥堵期间,基本费用将根据每个区块超过理想气体限制的需求量调整 12.5%,直到需求减弱。与首价拍卖不同,用户将更好地了解网络的拥堵程度,因为基本费用有多高。如果它太拥挤,用户可以支付或不支付该价格,就像他们在商店购买商品一样。或者,他们提交较低的费用并等待未来价格下跌。

开发者常见问题

作为 EIP-1559 的开发人员,我有什么变化?

我们建议 dapp 开发者和网络在伦敦分叉发生后立即分别切换到 EIP-1559 字段和区块头。如果不是,传统的 gasPrice 将用作 maxFeePerGas,这意味着用户可能会为他们的交易支付过高的费用。

如何使用 MetaMask 为我的 dapp 实施 EIP-1559?

您可以通读EIP-1559 规范,也可以查看Ethereum 的 JSON-RPC 规范中的 EIP-1559 部分。

是在用户级别还是 dapp 级别上实现?换句话说,如果我实施 EIP-1559,我的所有 dapp 用户会看到新的 gas 费用设置,还是只有同意采用 EIP-1559 的用户?

两者都是。用户通过客户端(钱包)与以太坊网络交互。用户还可以通过 dapp 与网络交互。如果 dapp 没有切换到新的 EIP-1559 字段,MetaMask 将检测到这一点并显示 1559 之前的气体估计 UI。

谁估计 gas 估计值,dapp 还是 MetaMask?

MetaMask.

所有的客户团队都准备好迎接 EIP-1559 了吗?

是的,客户规格已被冻结。伦敦硬分叉发布时间表如下

是否有关于复仇dapps任何潜在的风险?

答:所有的改变都是有风险的,但以太坊社区在强大的软件开发和协调方面有着良好的记录。EIP-1559 给对时间敏感的网络参与者(例如预言机)带来了一些潜在风险。Oracle 通常提供支持 DeFi 生态系统中各种参与者所需的定价信息。例如,Compound 需要知道用户抵押品的估值(即价格 x 资产数量),以确定他们的头寸是否需要清算。这些资产的估值必须不断更新,Compound 依靠预言机来更新这些信息。可以在这篇文章中找到有关这方面的更多信息。

对于伦敦硬分叉,我的项目可能需要考虑哪些更改?

EIP-1559(和 EIP-3198)的技术变化可能会影响您的项目,包括新的区块格式、新的交易格式、用于选择 gas 价格的新值、新的 JSON RPC 调用和几个 JSON RPC 的行为改变调用。有关这些更改的详细信息,请参阅此Infura 博客文章

词汇表

EIP-1559(以太坊改进协议 1559)

该提案最初由 Vitalik Buterin 创建,目的是通过不向矿工支付以太坊用户通过竞标天然气费而支付的天然气费来降低每笔交易的成本。以太坊用户现在可以根据网络的内部平均值对交易的平均汽油价格进行更准确的估计。如果我们假设费用的可预测性意味着用户不会频繁地为 gas 支付过高的费用,那么更可预测的基本费用的副作用可能会导致 gas 价格有所下降。有关 EIP-1559 将如何改变以太坊的更多信息,请参见此处

Gas fee

Gas 是指以太坊区块链上的交易费用。这是用户为验证或完成交易而支付的费用。

Base fee(基本费用)

由协议产生。表示将交易包含在区块中(即完成交易)所需的最小 gasUsed 乘数。这是交易费用中被烧掉的部分。

Max Priority fee - 即优先费或矿工的小费

MetaMask 最初将根据前一个区块的历史记录设置此金额。但是,用户将被允许在高级设置中编辑此金额。它被添加到交易中并代表支付给矿工的交易费用的一部分。

Max fee

MetaMask 最初将根据前一个区块的历史记录设置此金额。但是,用户将被允许在高级设置中编辑此金额。它代表用户愿意为其交易支付的最大金额(包括基本费用和最高优先级费用)。每gas最高费用与基本费用+最高优先费用之间的差额将“退还”给用户。

Gas limit

交易可能消耗的最大gas单位数量。

Gwei

Gwei 是以太的单位,最小的面额,代表 gigawei(或 1,000,000,000)。¹ Gwei 用于支付 gas 费用,或者说是用户支付的费用,以补偿处理和验证交易所需的计算能量在复仇blockchain.²

Slippage (滑点)

滑点是报价和执行价格之间的预期百分比差异。

原文:https://metamask.io/1559

争议不断的EIP-1559即将到来,它会造成哪些影响?

伦敦升级来临

以太坊基金会于7月15日公布了伦敦升级最新进展,本次升级将在主网达到12965000区块高度时被激活,具体时间预计在8月3日至5日之间。

V神在7月24号的世界区块链大会上演讲时说到:“当现在的PoW链完成了它的使命,PoW链上的一切都转移到PoS链上之后,就算是进入了以太坊2.0。但在两条链合并前期,将会执行一些较小的升级,引入分片,搭配Rollup,理想状态下可实现每秒10万笔交易。”而即将在PoW链上进行的伦敦分叉就是合并前期的一次重要升级。

从2015年开始,以太坊经历了数次升级,它们帮助以太坊不断完善并走向2.0时代。

什么是EIP-1559

以太坊的网络升级通过链下治理实施,社区成员提出以太坊改进提案(Ethereum Improvement Proposal,EIP)并对升级所要采用的EIP内容达成一致,由开发团队更新客户端,最后矿工使用最新版的以太坊客户端并通过硬分叉升级。

伦敦硬分叉升级中包含了五个以太坊改进提案,包括EIP-1559、EIP-3198、EIP-3529、EIP-3541和EIP-3554。伦敦升级因EIP-1559备受瞩目,其将改进现有的手续费机制,并将持续销毁ETH。

目前以太坊的交易手续费(Gas费)计算机制中一部分由创建者设置,创建者设置的交易费用多少会影响到矿工打包的先后顺序。矿工提供了在以太坊上运行交易和智能合约的计算能力,他们通常会优先处理设定高Gas费的用户的交易,以最大限度地获得区块奖励。

同样,为了能够更快完成交易,交易创建者也会设置更高的手续费来激励矿工。因此,在这种机制的刺激下,导致竞争巨大、Gas费不断上升、效率极低,并导致验证节点总价超付,增加了成本。

为了改善用户体验,V神和以太坊核心开发人员提出EIP-1559改进提案,在EIP-1559提案中,交易手续费将被拆分为两部分:基础费+矿工小费。其中基础费是交易所需的最少花费,由系统直接销毁,小费归矿工所有。

基础费用是用户在以太坊上发送交易或完成操作所需的最低Gas价格。它根据以太坊上每个区块使用的空间大小而波动。理想情况下,以太坊上的每个区块最多可容纳1500万Gas。然而在网络拥堵时,EIP-1559将允许块大小增加到这个数量的两倍。如果区块包含的Gas超过1500万,基础费将提高12.5%,反之如果低于1500万,将降低12.5%,直至趋于零。这种调整旨在确保以太坊的Gas费趋向于平均每区块约1500万Gas。

矿工小费指的是用户可以选择在最低基本费用的基础上再支付额外费用,该费用将直接支付给矿工,以激励矿工优先处理某些交易。EIP-1559中的小费是可选的,仅用于需要最快网络确认时间的用户。

EIP-1559对我们会产生哪些影响?

那么,EIP-1559设定的相对固定的Gas基础费的作用有哪些呢?

其一,可以降低ETH的通胀率。目前,ETH的供应量是无限的,每产生一个新的区块,就会有两枚新的ETH诞生,因此,它是有通胀的属性在的。但EIP-1559对于Gas基础费的销毁机制可能会带来一种局面,在交易活跃度较高时,用户支付基础费用销毁的ETH总量可能会抵消并大于通过区块奖励新发行的ETH总额,这将意味着ETH供应量出现负增长。如果交易不活跃,销毁的基础费少于出块奖励,那也可以促进ETH数量不会过分减少,使其达到一种平衡状态。

其二,降低以太坊交易费用波动性。根据EIP-1559,Gas基础费只能增减12.5%,这为以太坊的交易费用带来了稳定性。但是,降低波动性不代表降低交易费用,高费用问题主要是由于处理交易的网络容量有限造成的。以太坊费用机制的变化不能改变网络一次能够处理多少交易。这属于以太坊的可拓展性问题,需要交给Layer 2扩容方案和未来的分片技术。

基于EIP-1559的手续费机制和作用,我们可以看到它将主要影响三种不同类型的利益相关者:ETH投资者、矿工和用户。

(一)ETH投资者

基础费的销毁降低了ETH的通胀率。如果以太坊交易非常活跃时,甚至可能出现其销毁量高于新增量的情况,在这种情况下,ETH会变成通缩资产。

现在每天ETH的产出是13000枚左右,年通胀率约为4%。Dune Analytics的数据显示,如果按照EIP-1559的方式,一年内预计销毁2937123枚以太坊,占增发量的61.9%,可以把通胀率降低到1.5%,这个数值要比比特币1.8%的通胀率更低。通过销毁基础费,在一定程度上会提升ETH的价值,有利于长期持有ETH的投资者们。

(二)矿工

表面来看,EIP-1559中基础费的销毁会极大地削减矿工收入。但这是绝对的吗?

我们首先来看一下矿工的收入来源是什么。目前,矿工收入来源于交易手续费和区块奖励。当EIP-1559落实之后,交易手续费拆分为基础费和矿工小费,其中基础费被销毁。但随着以太坊上DEX的崛起,还有一种矿工收入出现,即矿工可提取价值(MEV)。MEV是一种可变的收入来源,DEX交易者可能比普通用户更看重链上交易执行的速度和顺序,矿工可利用这一点从DEX交易者那里获得更多的回报。

由于DEX越来越受欢迎,MEV变得越来越有利可图。研究和开发组织Flashbots估计,MEV的日收入已从2021年初的50万美元增长到2021年6月的600多万美元。

因此,在EIP-1559之后,矿工的MEV部分的收益比例有可能会越来越多。EIP-1559对矿工的收益肯定会有影响,但可能不一定有想象中的大。矿工依然有机会获得不错的收益。此外,EIP-1559本身会对ETH带来增值效应,这对所有人都是有利的。

(三)用户

对于以太坊的用户来说,高昂的费用是目前最紧迫的问题之一。EIP-1559并不会解决这个问题,并没有改变以太坊本身一次只能处理有限数量交易的事实。EIP-1559的主要作用是可以优化和提高以太坊手续费的使用效率。

EIP-1559提高了以太坊费用方式的透明度和可见性。过去用户在支付手续费时,需要根据网络拥堵情况和近期Gas费估算手续费多少。如果过少等待时间会变长,过多则造成浪费。从区块层面看,EIP-1559的方案每次区块之间的基础费变化幅度最多为12.5%,根据规则用户能预测并支付相对准确的手续费,以提高用户体验。

EIP-1559面临的风险

EIP-1559关于手续费的改变可以为以太坊带来好的一面,但技术是双刃剑,有好处但也同样伴随着风险。

对于矿工来说,随着EIP-1559的激活,他们的收入将减少。矿工将失去大额的交易手续费,而只能从寻求交易优先权的用户那里获得小费。改变奖励机制本身不会影响以太坊处理区块或计算的能力。然而,却存在着不满的矿工离开网络、破坏网络或启动竞争链的可能性。如果有很大一部分以太坊矿工退出或造反,区块时间和网络安全将受到负面影响。

对于用户和DAPP开发者,EIP-1559的激活可能不会表现得像理论上那样有效。如果不能实现承诺的费用市场效率,可能会导致用户和开发者的幻想破灭。如果发生这种情况,以太坊的竞争对手,如Binance Smart Chain和Cardano(按市值计算仅次于以太坊的两个最大的智能合约区块链平台),无疑将抓住机会抢占市场份额。

最后,EIP-1559的激活还带来了不可预见的错误或恶意的用户行为的风险。这在私人测试网络上测试EIP-1559的过程中,已经发现了一些。

以太坊的新时代

EIP-1559通过让手续费更有效率来提升用户体验,但不能从根本上解决网络拥堵和高手续费的问题,这需要通过Layer 2扩容或者以太坊2.0来实现。

EIP-1559将极大地增强以太坊上处理交易的用户体验。当然,矿工们会担心EIP-1559的费用销毁方面,但EIP-1559的总体好处远远超过费用销毁,将对终端用户产生积极的影响。

随着EIP-1559、Layer 2以及PoS的推进,以太坊及ETH会有向好的变化,其中也会潜藏一些危机。不过,如果一切都能顺利落地,这会开启以太坊的新时代,对整个加密领域的格局产生非常重大的影响。

转载自:https://zhuanlan.zhihu.com/p/395153612

其他

https://notes.ethereum.org/@vbuterin/eip-1559-faq
https://zhuanlan.zhihu.com/p/393196358
https://zhuanlan.zhihu.com/p/396948190
https://zhuanlan.zhihu.com/p/361104358