github.com/MetalBlockchain/subnet-evm@v0.4.9/contract-examples/test/fee_manager.ts (about)

     1  // (c) 2019-2022, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
     5  import { expect } from "chai";
     6  import {
     7    BigNumber,
     8    Contract,
     9    ContractFactory,
    10  } from "ethers"
    11  import { ethers } from "hardhat"
    12  
    13  // make sure this is always an admin for the precompile
    14  const adminAddress: string = "0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC"
    15  const FEE_MANAGER = "0x0200000000000000000000000000000000000003";
    16  
    17  const ROLES = {
    18    NONE: 0,
    19    ENABLED: 1,
    20    ADMIN: 2
    21  };
    22  
    23  const C_FEES = {
    24    gasLimit: 8_000_000, // gasLimit
    25    targetBlockRate: 2, // targetBlockRate
    26    minBaseFee: 25_000_000_000, // minBaseFee
    27    targetGas: 15_000_000, // targetGas
    28    baseFeeChangeDenominator: 36, // baseFeeChangeDenominator
    29    minBlockGasCost: 0, // minBlockGasCost
    30    maxBlockGasCost: 1_000_000, // maxBlockGasCost
    31    blockGasCostStep: 100_000 // blockGasCostStep
    32  }
    33  
    34  const WAGMI_FEES = {
    35    gasLimit: 20_000_000, // gasLimit
    36    targetBlockRate: 2, // targetBlockRate
    37    minBaseFee: 1_000_000_000, // minBaseFee
    38    targetGas: 100_000_000, // targetGas
    39    baseFeeChangeDenominator: 48, // baseFeeChangeDenominator
    40    minBlockGasCost: 0, // minBlockGasCost
    41    maxBlockGasCost: 10_000_000, // maxBlockGasCost
    42    blockGasCostStep: 100_000 // blockGasCostStep
    43  }
    44  
    45  // TODO: These tests keep state to the next state. It means that some tests cases assumes some preconditions
    46  // set by previous test cases. We should make these tests stateless.
    47  describe("ExampleFeeManager", function () {
    48    this.timeout("30s")
    49  
    50    let owner: SignerWithAddress
    51    let contract: Contract
    52    let manager: SignerWithAddress
    53    let nonEnabled: SignerWithAddress
    54    let managerPrecompile: Contract
    55    let ownerPrecompile: Contract
    56    before(async function () {
    57      owner = await ethers.getSigner(adminAddress);
    58      const contractF: ContractFactory = await ethers.getContractFactory("ExampleFeeManager", { signer: owner })
    59      contract = await contractF.deploy()
    60      await contract.deployed()
    61      const contractAddress: string = contract.address
    62      console.log(`Contract deployed to: ${contractAddress}`)
    63  
    64      managerPrecompile = await ethers.getContractAt("IFeeManager", FEE_MANAGER, manager);
    65      ownerPrecompile = await ethers.getContractAt("IFeeManager", FEE_MANAGER, owner);
    66  
    67      const signers: SignerWithAddress[] = await ethers.getSigners()
    68      manager = signers.slice(-1)[0]
    69      nonEnabled = signers.slice(-2)[0]
    70  
    71      let tx = await ownerPrecompile.setEnabled(manager.address);
    72      await tx.wait()
    73  
    74      tx = await owner.sendTransaction({
    75        to: manager.address,
    76        value: ethers.utils.parseEther("1")
    77      })
    78      await tx.wait()
    79  
    80      tx = await owner.sendTransaction({
    81        to: nonEnabled.address,
    82        value: ethers.utils.parseEther("1")
    83      })
    84      await tx.wait()
    85    });
    86  
    87    it("should add contract deployer as owner", async function () {
    88      const contractOwnerAddr: string = await contract.owner()
    89      expect(owner.address).to.be.equal(contractOwnerAddr)
    90    });
    91  
    92    it("contract should not be able to change fee without enabled", async function () {
    93      let contractRole = await managerPrecompile.readAllowList(contract.address);
    94      expect(contractRole).to.be.equal(ROLES.NONE)
    95      try {
    96        let tx = await contract.enableWAGMIFees()
    97        await tx.wait()
    98      }
    99      catch (err) {
   100        return
   101      }
   102      expect.fail("should have errored")
   103    })
   104  
   105    it("contract should be added to manager list", async function () {
   106      let adminRole = await ownerPrecompile.readAllowList(adminAddress);
   107      expect(adminRole).to.be.equal(ROLES.ADMIN)
   108      let contractRole = await ownerPrecompile.readAllowList(contract.address);
   109      expect(contractRole).to.be.equal(ROLES.NONE)
   110  
   111      let enableTx = await ownerPrecompile.setEnabled(contract.address);
   112      await enableTx.wait()
   113      contractRole = await ownerPrecompile.readAllowList(contract.address);
   114      expect(contractRole).to.be.equal(ROLES.ENABLED)
   115    });
   116  
   117    it("admin should be able to change fees through contract", async function () {
   118      const testFees = {
   119        gasLimit: 12_345_678, // gasLimit
   120        targetBlockRate: 2, // targetBlockRate
   121        minBaseFee: 1_234_567, // minBaseFee
   122        targetGas: 100_000_000, // targetGas
   123        baseFeeChangeDenominator: 48, // baseFeeChangeDenominator
   124        minBlockGasCost: 0, // minBlockGasCost
   125        maxBlockGasCost: 10_000_000, // maxBlockGasCost
   126        blockGasCostStep: 100_000 // blockGasCostStep
   127      }
   128      var res = await contract.getCurrentFeeConfig()
   129      expect(res.gasLimit).to.be.not.equal(testFees.gasLimit)
   130      expect(res.minBaseFee).to.be.not.equal(testFees.minBaseFee)
   131  
   132      let enableTx = await contract.enableCustomFees(testFees)
   133      let txRes = await enableTx.wait()
   134  
   135      var res = await contract.getCurrentFeeConfig()
   136      expect(res.gasLimit).to.be.equal(testFees.gasLimit)
   137      expect(res.minBaseFee).to.be.equal(testFees.minBaseFee)
   138  
   139      var res = await contract.getFeeConfigLastChangedAt()
   140      expect(res).to.be.equal(txRes.blockNumber)
   141    })
   142  
   143    it("admin should be able to enable wagmi fees through contract", async function () {
   144      var res = await contract.getCurrentFeeConfig()
   145      expect(res.gasLimit).to.be.not.equal(WAGMI_FEES.gasLimit)
   146      expect(res.minBaseFee).to.be.not.equal(WAGMI_FEES.minBaseFee)
   147      // set wagmi fees now
   148      let enableTx = await contract.enableWAGMIFees({
   149        maxFeePerGas: WAGMI_FEES.minBaseFee * 2,
   150        maxPriorityFeePerGas: WAGMI_FEES.minBaseFee
   151      })
   152      let txRes = await enableTx.wait()
   153  
   154      res = await contract.getCurrentFeeConfig()
   155      expect(res.gasLimit).to.be.equal(WAGMI_FEES.gasLimit)
   156      expect(res.minBaseFee).to.be.equal(WAGMI_FEES.minBaseFee)
   157  
   158      var res = await contract.getFeeConfigLastChangedAt()
   159      expect(res).to.be.equal(txRes.blockNumber)
   160    })
   161  
   162    it("should let low fee tx to be in mempool", async function () {
   163      var res = await contract.getCurrentFeeConfig()
   164      expect(res.minBaseFee).to.be.equal(WAGMI_FEES.minBaseFee)
   165  
   166      var testMaxFeePerGas = WAGMI_FEES.minBaseFee + 10000
   167  
   168      let tx = await owner.sendTransaction({
   169        to: manager.address,
   170        value: ethers.utils.parseEther("0.1"),
   171        maxFeePerGas: testMaxFeePerGas,
   172        maxPriorityFeePerGas: 0
   173      });
   174      let confirmedTx = await tx.wait()
   175      expect(confirmedTx.confirmations).to.be.greaterThanOrEqual(1)
   176    })
   177  
   178    it("should not let low fee tx to be in mempool", async function () {
   179  
   180      let enableTx = await contract.enableCustomFees(C_FEES)
   181      await enableTx.wait()
   182      let getRes = await contract.getCurrentFeeConfig()
   183      expect(getRes.minBaseFee).to.be.equal(C_FEES.minBaseFee)
   184  
   185      var testMaxFeePerGas = C_FEES.minBaseFee - 100000
   186  
   187      // send tx with lower han C_FEES minBaseFee
   188      try {
   189        let tx = await owner.sendTransaction({
   190          to: manager.address,
   191          value: ethers.utils.parseEther("0.1"),
   192          maxFeePerGas: testMaxFeePerGas,
   193          maxPriorityFeePerGas: 10000
   194        });
   195        await tx.wait()
   196      }
   197      catch (err) {
   198        expect(err.toString()).to.include("max fee per gas less than block base fee")
   199        return
   200      }
   201      expect.fail("should have errored")
   202    })
   203  
   204    it("should be able to get current fee config", async function () {
   205      let enableTx = await contract.enableCustomFees(C_FEES,
   206        {
   207          maxFeePerGas: C_FEES.minBaseFee * 2,
   208          maxPriorityFeePerGas: 0
   209        })
   210      await enableTx.wait()
   211  
   212      var res = await contract.getCurrentFeeConfig()
   213      expect(res.gasLimit).to.be.equal(C_FEES.gasLimit)
   214  
   215      var res = await contract.connect(manager).getCurrentFeeConfig()
   216      expect(res.gasLimit).to.be.equal(C_FEES.gasLimit)
   217  
   218      var res = await contract.connect(nonEnabled).getCurrentFeeConfig()
   219      expect(res.gasLimit).to.be.equal(C_FEES.gasLimit)
   220    });
   221  
   222    it("nonEnabled should not be able to set fee config", async function () {
   223      let nonEnabledRole = await ownerPrecompile.readAllowList(nonEnabled.address);
   224  
   225      expect(nonEnabledRole).to.be.equal(ROLES.NONE)
   226      try {
   227        await contract.connect(nonEnabled).enableWAGMIFees({
   228          maxFeePerGas: C_FEES.minBaseFee * 2,
   229          maxPriorityFeePerGas: 0
   230        })
   231      }
   232      catch (err) {
   233        return
   234      }
   235      expect.fail("should have errored")
   236    })
   237  
   238    it("manager should be able to change fees through contract", async function () {
   239      let enableTx = await contract.connect(manager).enableCustomFees(WAGMI_FEES,
   240        {
   241          maxFeePerGas: C_FEES.minBaseFee * 2,
   242          maxPriorityFeePerGas: 0
   243        })
   244      await enableTx.wait()
   245  
   246      var res = await contract.connect(manager).getCurrentFeeConfig()
   247      expect(res.minBaseFee).to.be.equal(WAGMI_FEES.minBaseFee)
   248    })
   249  
   250  
   251    it("non-enabled should not be able to change fees through contract", async function () {
   252      try {
   253        let enableTx = await contract.connect(nonEnabled).enableCustomFees(WAGMI_FEES,
   254          {
   255            maxFeePerGas: WAGMI_FEES.minBaseFee * 2,
   256            maxPriorityFeePerGas: 0
   257          })
   258        await enableTx.wait()
   259      }
   260      catch (err) {
   261        return
   262      }
   263      expect.fail("should have errored")
   264    })
   265  })