UNPKG

ox

Version:

Ethereum Standard Library

381 lines (337 loc) 9.66 kB
import { AbiConstructor } from 'ox' import { describe, expect, test } from 'vp/test' import { Constructor } from '../../../contracts/generated.js' import { seaportContractConfig } from '../../../test/constants/abis.js' import { address } from '../../../test/constants/addresses.js' import { anvilMainnet } from '../../../test/prool.js' describe('decode', () => { test('default', () => { { const abiConstructor = AbiConstructor.from('constructor()') const encoded = AbiConstructor.encode(abiConstructor, { bytecode: Constructor.bytecode.object, }) expect( AbiConstructor.decode(abiConstructor, { bytecode: Constructor.bytecode.object, data: encoded, }), ).toBe(undefined) } expect( AbiConstructor.decode([], { bytecode: '0xdeadbeef', data: '0xdeadbeef', }), ).toBe(undefined) { const encoded = AbiConstructor.encode( [AbiConstructor.from('constructor()')], { bytecode: Constructor.bytecode.object, }, ) expect( AbiConstructor.decode([AbiConstructor.from('constructor()')], { bytecode: Constructor.bytecode.object, data: encoded, }), ).toBe(undefined) } }) test('behavior: args', () => { { const abiConstructor = AbiConstructor.from( 'constructor(address, uint256)', ) const encoded = AbiConstructor.encode(abiConstructor, { bytecode: Constructor.bytecode.object, args: [address.vitalik, 123n], }) expect( AbiConstructor.decode(abiConstructor, { bytecode: Constructor.bytecode.object, data: encoded, }), ).toMatchInlineSnapshot(` [ "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", 123n, ] `) } { const encoded = AbiConstructor.encode(Constructor.abi, { bytecode: Constructor.bytecode.object, args: [address.vitalik, 123n], }) expect( AbiConstructor.decode(Constructor.abi, { bytecode: Constructor.bytecode.object, data: encoded, }), ).toMatchInlineSnapshot(` [ "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", 123n, ] `) } }) test('options: checksumAddress = false', () => { const abiConstructor = AbiConstructor.from('constructor(address, uint256)') const encoded = AbiConstructor.encode(abiConstructor, { bytecode: Constructor.bytecode.object, args: [address.vitalik, 123n], }) expect( AbiConstructor.decode(abiConstructor, { bytecode: Constructor.bytecode.object, checksumAddress: false, data: encoded, }), ).toMatchInlineSnapshot(` [ "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", 123n, ] `) }) test('behavior: network', async () => { const abiConstructor = AbiConstructor.fromAbi(Constructor.abi) const data = AbiConstructor.encode(abiConstructor, { bytecode: Constructor.bytecode.object, args: [address.vitalik, 123n], }) const hash = await anvilMainnet.request({ method: 'eth_sendTransaction', params: [ { data, }, ], }) await anvilMainnet.request({ method: 'evm_mine', params: { blocks: '0x1' }, }) const { input } = (await anvilMainnet.request({ method: 'eth_getTransactionByHash', params: [hash], }))! expect( AbiConstructor.decode(abiConstructor, { bytecode: Constructor.bytecode.object, data: input, }), ).toMatchInlineSnapshot(` [ "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", 123n, ] `) }) test('error: bytecode does not match data prefix', () => { const abiConstructor = AbiConstructor.from('constructor(address, uint256)') expect(() => AbiConstructor.decode(abiConstructor, { bytecode: '0x6080604052deadbeef', data: '0xcafebabe000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045000000000000000000000000000000000000000000000000000000000000007b', }), ).toThrowErrorMatchingInlineSnapshot(` [AbiConstructor.BytecodeMismatchError: Provided \`data\` does not start with the provided \`bytecode\`. Bytecode: 0x6080604052deadbe... Data: 0xcafebabe00000000...] `) }) test('error: no constructor with encoded args', () => { expect(() => AbiConstructor.decode([], { bytecode: '0xdeadbeef', data: '0xdeadbeef00', }), ).toThrowErrorMatchingInlineSnapshot( `[AbiItem.NotFoundError: ABI item with name "constructor" not found.]`, ) }) }) describe('encode', () => { test('default', () => { { const abiConstructor = AbiConstructor.from('constructor()') expect( AbiConstructor.encode(abiConstructor, { bytecode: '0xdeadbeef', }), ).toBe('0xdeadbeef') } expect( AbiConstructor.encode([AbiConstructor.from('constructor()')], { bytecode: '0xdeadbeef', }), ).toBe('0xdeadbeef') expect( AbiConstructor.encode([], { bytecode: '0xdeadbeef', }), ).toBe('0xdeadbeef') }) test('behavior: args', () => { { const abiConstructor = AbiConstructor.from( 'constructor(address, uint256)', ) expect( AbiConstructor.encode(abiConstructor, { bytecode: '0xdeadbeef', args: [address.vitalik, 123n], }), ).toBe( '0xdeadbeef000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045000000000000000000000000000000000000000000000000000000000000007b', ) } expect( AbiConstructor.encode(Constructor.abi, { bytecode: '0xdeadbeef', args: [address.vitalik, 123n], }), ).toBe( '0xdeadbeef000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045000000000000000000000000000000000000000000000000000000000000007b', ) }) test('behavior: network', async () => { const abiConstructor = AbiConstructor.fromAbi(Constructor.abi) const data = AbiConstructor.encode(abiConstructor, { bytecode: Constructor.bytecode.object, args: [address.vitalik, 123n], }) const hash = await anvilMainnet.request({ method: 'eth_sendTransaction', params: [ { data, }, ], }) await anvilMainnet.request({ method: 'evm_mine', params: { blocks: '0x1' }, }) const { contractAddress } = (await anvilMainnet.request({ method: 'eth_getTransactionReceipt', params: [hash], }))! expect(contractAddress).toBeDefined() }) }) describe('format', () => { test('default', () => { const approve = AbiConstructor.from({ inputs: [{ name: 'owner', type: 'address' }], payable: false, stateMutability: 'nonpayable', type: 'constructor', }) const formatted = AbiConstructor.format(approve) expect(formatted).toMatchInlineSnapshot(`"constructor(address owner)"`) }) }) describe('from', () => { test('default', () => { const abiConstructor = AbiConstructor.from({ inputs: [{ name: 'owner', type: 'address' }], payable: false, stateMutability: 'nonpayable', type: 'constructor', }) expect(abiConstructor).toMatchInlineSnapshot(` { "hash": "0xf8a6c595894ab588edd59e406425331fe9ad3266445da35ab4aa27007b7a602a", "inputs": [ { "name": "owner", "type": "address", }, ], "payable": false, "stateMutability": "nonpayable", "type": "constructor", } `) }) test('behavior: human readable', () => { const abiConstructor = AbiConstructor.from('constructor(address owner)') expect(abiConstructor).toMatchInlineSnapshot(` { "hash": "0xf8a6c595894ab588edd59e406425331fe9ad3266445da35ab4aa27007b7a602a", "inputs": [ { "name": "owner", "type": "address", }, ], "stateMutability": "nonpayable", "type": "constructor", } `) }) test('behavior: human readable (struct)', () => { const abiConstructor = AbiConstructor.from([ 'struct Foo { address owner }', 'constructor(Foo foo)', ]) expect(abiConstructor).toMatchInlineSnapshot(` { "hash": "0x046f6226ce02998a10b2101bbeb1a3bd095efb55989b57f3781e659a4a2a8011", "inputs": [ { "components": [ { "name": "owner", "type": "address", }, ], "name": "foo", "type": "tuple", }, ], "stateMutability": "nonpayable", "type": "constructor", } `) }) }) describe('fromAbi', () => { test('default', () => { const abiConstructor = AbiConstructor.fromAbi(seaportContractConfig.abi) expect(abiConstructor).toMatchInlineSnapshot(` { "inputs": [ { "name": "conduitController", "type": "address", }, ], "stateMutability": "nonpayable", "type": "constructor", } `) }) test('error: no constructor', () => { expect(() => AbiConstructor.fromAbi([])).toThrowErrorMatchingInlineSnapshot( `[AbiItem.NotFoundError: ABI item with name "constructor" not found.]`, ) }) }) test('exports', () => { expect(Object.keys(AbiConstructor)).toMatchInlineSnapshot(` [ "decode", "encode", "format", "from", "fromAbi", "BytecodeMismatchError", ] `) })