github.com/ethereum-optimism/optimism@v1.7.2/packages/web3js-plugin/src/plugin.spec.ts (about) 1 import { beforeAll, describe, expect, test } from 'vitest' 2 import { z } from 'zod' 3 import Web3, { Contract, FMT_BYTES, FMT_NUMBER } from 'web3' 4 import { 5 l2StandardBridgeABI, 6 l2StandardBridgeAddress, 7 optimistABI, 8 optimistAddress, 9 } from '@eth-optimism/contracts-ts' 10 11 import { OptimismPlugin } from './plugin' 12 13 const defaultProvider = 'https://mainnet.optimism.io' 14 const provider = z 15 .string() 16 .url() 17 .default(defaultProvider) 18 .parse(process.env['VITE_L2_RPC_URL']) 19 if (provider === defaultProvider) 20 console.warn( 21 'Warning: Using default public provider, this could cause tests to fail due to rate limits. Set the VITE_L2_RPC_URL env to override default provider' 22 ) 23 24 describe('OptimismPlugin', () => { 25 let web3: Web3 26 27 beforeAll(() => { 28 web3 = new Web3(provider) 29 web3.registerPlugin(new OptimismPlugin()) 30 }) 31 32 test('should be registered under .op namespace', () => 33 expect(web3.op).toMatchInlineSnapshot(` 34 OptimismPlugin { 35 "_accountProvider": { 36 "create": [Function], 37 "decrypt": [Function], 38 "encrypt": [Function], 39 "hashMessage": [Function], 40 "privateKeyToAccount": [Function], 41 "recover": [Function], 42 "recoverTransaction": [Function], 43 "sign": [Function], 44 "signTransaction": [Function], 45 "wallet": Wallet [], 46 }, 47 "_emitter": EventEmitter { 48 "_events": {}, 49 "_eventsCount": 0, 50 "_maxListeners": undefined, 51 Symbol(kCapture): false, 52 }, 53 "_gasPriceOracleContract": undefined, 54 "_requestManager": Web3RequestManager { 55 "_emitter": EventEmitter { 56 "_events": { 57 "BEFORE_PROVIDER_CHANGE": [Function], 58 "PROVIDER_CHANGED": [Function], 59 }, 60 "_eventsCount": 2, 61 "_maxListeners": undefined, 62 Symbol(kCapture): false, 63 }, 64 "_provider": HttpProvider { 65 "clientUrl": "https://opt-mainnet.g.alchemy.com/v2/OVlbpe9COlhG-ijOXGvL_phb5ns6p9-w", 66 "httpProviderOptions": undefined, 67 }, 68 "useRpcCallSpecification": undefined, 69 }, 70 "_subscriptionManager": Web3SubscriptionManager { 71 "_subscriptions": Map {}, 72 "registeredSubscriptions": { 73 "logs": [Function], 74 "newBlockHeaders": [Function], 75 "newHeads": [Function], 76 "newPendingTransactions": [Function], 77 "pendingTransactions": [Function], 78 "syncing": [Function], 79 }, 80 "requestManager": Web3RequestManager { 81 "_emitter": EventEmitter { 82 "_events": { 83 "BEFORE_PROVIDER_CHANGE": [Function], 84 "PROVIDER_CHANGED": [Function], 85 }, 86 "_eventsCount": 2, 87 "_maxListeners": undefined, 88 Symbol(kCapture): false, 89 }, 90 "_provider": HttpProvider { 91 "clientUrl": "https://opt-mainnet.g.alchemy.com/v2/OVlbpe9COlhG-ijOXGvL_phb5ns6p9-w", 92 "httpProviderOptions": undefined, 93 }, 94 "useRpcCallSpecification": undefined, 95 }, 96 "tolerateUnlinkedSubscription": false, 97 }, 98 "_wallet": Wallet [], 99 "config": { 100 "blockHeaderTimeout": 10, 101 "defaultAccount": undefined, 102 "defaultBlock": "latest", 103 "defaultChain": "mainnet", 104 "defaultCommon": undefined, 105 "defaultHardfork": "london", 106 "defaultMaxPriorityFeePerGas": "0x9502f900", 107 "defaultNetworkId": undefined, 108 "defaultTransactionType": "0x0", 109 "enableExperimentalFeatures": { 110 "useRpcCallSpecification": false, 111 "useSubscriptionWhenCheckingBlockTimeout": false, 112 }, 113 "handleRevert": false, 114 "maxListenersWarningThreshold": 100, 115 "transactionBlockTimeout": 50, 116 "transactionBuilder": undefined, 117 "transactionConfirmationBlocks": 24, 118 "transactionConfirmationPollingInterval": undefined, 119 "transactionPollingInterval": 1000, 120 "transactionPollingTimeout": 750000, 121 "transactionReceiptPollingInterval": undefined, 122 "transactionSendTimeout": 750000, 123 "transactionTypeParser": undefined, 124 }, 125 "pluginNamespace": "op", 126 "providers": { 127 "HttpProvider": [Function], 128 "WebsocketProvider": [Function], 129 }, 130 } 131 `)) 132 133 describe('should return a bigint by default', () => { 134 test('getBaseFee', async () => 135 expect(await web3.op.getBaseFee()).toBeTypeOf('bigint')) 136 137 test('getDecimals should return 6n', async () => 138 expect(await web3.op.getDecimals()).toBe(BigInt(6))) 139 140 test('getGasPrice', async () => 141 expect(await web3.op.getGasPrice()).toBeTypeOf('bigint')) 142 143 test('getL1BaseFee', async () => 144 expect(await web3.op.getL1BaseFee()).toBeTypeOf('bigint')) 145 146 test('getOverhead should return 188n', async () => 147 expect(await web3.op.getOverhead()).toBe(BigInt(188))) 148 149 test('getScalar should return 684000n', async () => 150 expect(await web3.op.getScalar()).toBe(BigInt(684000))) 151 }) 152 153 describe('should return a number', () => { 154 const numberFormat = { number: FMT_NUMBER.NUMBER, bytes: FMT_BYTES.HEX } 155 156 test('getBaseFee', async () => 157 expect(await web3.op.getBaseFee(numberFormat)).toBeTypeOf('number')) 158 159 test('getDecimals should return 6', async () => 160 expect(await web3.op.getDecimals(numberFormat)).toBe(6)) 161 162 test('getGasPrice', async () => 163 expect(await web3.op.getGasPrice(numberFormat)).toBeTypeOf('number')) 164 165 test('getL1BaseFee', async () => 166 expect(await web3.op.getL1BaseFee(numberFormat)).toBeTypeOf('number')) 167 168 test('getOverhead should return 188', async () => 169 expect(await web3.op.getOverhead(numberFormat)).toBe(188)) 170 171 test('getScalar should return 684000', async () => 172 expect(await web3.op.getScalar(numberFormat)).toBe(684000)) 173 }) 174 175 test('getVersion should return the string 1.0.0', async () => 176 expect(await web3.op.getVersion()).toBe('1.0.0')) 177 178 describe('Contract transaction gas estimates - optimistABI.burn', () => { 179 let optimistContract: Contract<typeof optimistABI> 180 let encodedBurnMethod: string 181 182 beforeAll(() => { 183 optimistContract = new web3.eth.Contract(optimistABI) 184 encodedBurnMethod = optimistContract.methods 185 .burn('0x77194aa25a06f932c10c0f25090f3046af2c85a6') 186 .encodeABI() 187 }) 188 189 describe('should return a bigint by default', () => { 190 test('getL1Fee', async () => { 191 expect( 192 await web3.op.getL1Fee({ 193 chainId: '0xa', 194 data: encodedBurnMethod, 195 type: '0x2', 196 }) 197 ).toBeTypeOf('bigint') 198 }) 199 200 test('getL1GasUsed should return 1884n', async () => 201 expect( 202 await web3.op.getL1GasUsed({ 203 chainId: '0xa', 204 data: encodedBurnMethod, 205 type: '0x2', 206 }) 207 ).toBe(BigInt(1884))) 208 209 test('estimateFees', async () => 210 expect( 211 await web3.op.estimateFees({ 212 chainId: 10, 213 data: encodedBurnMethod, 214 type: 2, 215 to: optimistAddress[10], 216 from: '0x77194aa25a06f932c10c0f25090f3046af2c85a6', 217 }) 218 ).toBeTypeOf('bigint')) 219 220 test('getL2Fee', async () => { 221 expect( 222 await web3.op.getL2Fee({ 223 chainId: '0xa', 224 data: encodedBurnMethod, 225 type: '0x2', 226 to: optimistAddress[10], 227 from: '0x77194aa25a06f932c10c0f25090f3046af2c85a6', 228 }) 229 ).toBeTypeOf('bigint') 230 }) 231 232 test('estimateFees', async () => 233 expect( 234 await web3.op.estimateFees({ 235 chainId: 10, 236 data: encodedBurnMethod, 237 type: 2, 238 to: optimistAddress[10], 239 from: '0x77194aa25a06f932c10c0f25090f3046af2c85a6', 240 }) 241 ).toBeTypeOf('bigint')) 242 }) 243 244 describe('should return a hexString', () => { 245 const hexStringFormat = { number: FMT_NUMBER.HEX, bytes: FMT_BYTES.HEX } 246 247 test('getL1Fee', async () => { 248 expect( 249 await web3.op.getL1Fee( 250 { 251 chainId: '0xa', 252 data: encodedBurnMethod, 253 type: '0x2', 254 }, 255 hexStringFormat 256 ) 257 ).toBeTypeOf('string') 258 }) 259 260 test('getL1GasUsed should return 0x75c', async () => 261 expect( 262 await web3.op.getL1GasUsed( 263 { 264 chainId: '0xa', 265 data: encodedBurnMethod, 266 type: '0x2', 267 }, 268 hexStringFormat 269 ) 270 ).toBe('0x75c')) 271 272 test('estimateFees', async () => 273 expect( 274 await web3.op.estimateFees( 275 { 276 chainId: 10, 277 data: encodedBurnMethod, 278 type: 2, 279 to: optimistAddress[10], 280 from: '0x77194aa25a06f932c10c0f25090f3046af2c85a6', 281 }, 282 hexStringFormat 283 ) 284 ).toBeTypeOf('string')) 285 }) 286 }) 287 288 describe('Contract transaction gas estimates - l2StandardBridgeABI.withdraw', () => { 289 let l2BridgeContract: Contract<typeof l2StandardBridgeABI> 290 let encodedWithdrawMethod: string 291 292 beforeAll(() => { 293 l2BridgeContract = new Contract( 294 l2StandardBridgeABI, 295 l2StandardBridgeAddress[420] 296 ) 297 encodedWithdrawMethod = l2BridgeContract.methods 298 .withdraw( 299 // l2 token address 300 '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000', 301 // amount 302 Web3.utils.toWei('0.00000001', 'ether'), 303 // l1 gas 304 0, 305 // extra data 306 '0x00' 307 ) 308 .encodeABI() 309 }) 310 311 describe('should return a bigint by default', () => { 312 test('getL1Fee', async () => { 313 expect( 314 await web3.op.getL1Fee({ 315 chainId: '0xa', 316 data: encodedWithdrawMethod, 317 type: '0x2', 318 }) 319 ).toBeTypeOf('bigint') 320 }) 321 322 test('getL1GasUsed should return 2592n', async () => 323 expect( 324 await web3.op.getL1GasUsed({ 325 chainId: '0xa', 326 data: encodedWithdrawMethod, 327 type: '0x2', 328 }) 329 ).toBe(BigInt(2592))) 330 331 test('estimateFees', async () => 332 expect( 333 await web3.op.estimateFees({ 334 chainId: 10, 335 data: encodedWithdrawMethod, 336 value: Web3.utils.toWei('0.00000001', 'ether'), 337 type: 2, 338 to: l2StandardBridgeAddress[420], 339 from: '0x6387a88a199120aD52Dd9742C7430847d3cB2CD4', 340 maxFeePerGas: Web3.utils.toWei('0.2', 'gwei'), 341 maxPriorityFeePerGas: Web3.utils.toWei('0.1', 'gwei'), 342 }) 343 ).toBeTypeOf('bigint')) 344 }) 345 }) 346 })