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 })