it('should execute one by one', async () => {
            await fc.assert(
                fc.asyncProperty(valuesArbitrary, async (values) => {
                    fc.pre(values.length > 0)

                    const tasks = values.map((value) => jest.fn().mockResolvedValue(value))

                    await sequence(tasks)

                    tasks.reduce((task1, task2) => {
                        return expect(task1).toHaveBeenCalledBefore(task2), task2
                    })
                })
            )
        })


unknown

it('should resolve with the return value of a synchronous task', async () => {
            await fc.assert(
                fc.asyncProperty(valueArbitrary, async (value) => {
                    const task = jest.fn().mockReturnValue(value)
                    const handleError = jest.fn()

                    await expect(mapError(task, handleError)).resolves.toBe(value)
                    expect(handleError).not.toHaveBeenCalled()
                })
            )
        })

Summary: `mapError` resolves with the return value of a synchronous task without invoking the error handler.


it('should resolve with the return value of a synchronous task', async () => {
            await fc.assert(
                fc.asyncProperty(valueArbitrary, async (value) => {
                    const task = jest.fn().mockReturnValue(value)
                    const handleError = jest.fn()

                    await expect(tapError(task, handleError)).resolves.toBe(value)
                    expect(handleError).not.toHaveBeenCalled()
                })
            )
        })

Summary: `tapError` resolves with the return value of a synchronous task and does not call `handleError`.


it('should throw', () => {
                fc.assert(
                    fc.property(numAttemptsArbitrary, (numAttempts) => {
                        expect(() => createSimpleRetryStrategy(numAttempts)).toThrow()
                    })
                )
            })

Summary: `createSimpleRetryStrategy` should throw an exception when invoked with various values of `numAttempts`.


it('should return a function that returns true until numAttempts is reached', () => {
                    fc.assert(
                        fc.property(numAttemptsArbitrary, (numAttempts) => {
                            const strategy = createSimpleRetryStrategy(numAttempts)

                            // The first N attempts should return true since we want to retry them
                            for (let attempt = 1; attempt <= numAttempts; attempt++) {
                                expect(strategy(attempt, 'error', [], [])).toBeTruthy()
                            }

                            // The N+1th attempt should return false
                            expect(strategy(numAttempts + 1, 'error', [], [])).toBeFalsy()
                        })
                    )
                })

Summary: A function created by `createSimpleRetryStrategy` should return true for attempts up to `numAttempts` and false for the `numAttempts + 1` attempt.


it('should not throw if called with an array of networks defined in hardhat config', () => {
            fc.assert(
                fc.property(definedNetworksArrayArbitrary, (networks) => {
                    expect(assertDefinedNetworks(networks)).toBe(networks)
                })
            )
        })


it('should not throw if called with a Set of networks defined in hardhat config', () => {
            fc.assert(
                fc.property(definedNetworksSetArbitrary, (networks) => {
                    expect(assertDefinedNetworks(networks)).toBe(networks)
                })
            )
        })


it('should throw if called if a network has not been defined in an array', () => {
            fc.assert(
                fc.property(definedNetworksArrayArbitrary, fc.string(), (networks, network) => {
                    fc.pre(!definedNetworks.includes(network))

                    expect(() => assertDefinedNetworks([...networks, network])).toThrow()
                })
            )
        })


it('should throw if called if a network has not been defined in a Set', () => {
            fc.assert(
                fc.property(definedNetworksSetArbitrary, fc.string(), (networks, network) => {
                    fc.pre(!definedNetworks.includes(network))

                    expect(() => assertDefinedNetworks(networks.add(network))).toThrow()
                })
            )
        })


it('should work goddammit', async () => {
            await fc.assert(
                fc.asyncProperty(portArbitrary, anvilOptionsRecordArbitrary, async (port, anvilOptions) => {
                    const simulationConfig = resolveSimulationConfig({ port }, hre.config)
                    const spec = serializeDockerComposeSpec(createSimulationComposeSpec(simulationConfig, anvilOptions))

                    await writeFile(SPEC_FILE_PATH, spec)

                    const result = validateSpec()

                    expect(result.stderr.toString('utf8')).toBe('')
                    expect(result.status).toBe(0)
                }),
                { numRuns: 20 }
            )
        })


it('should pass the original value if contract is already an OmniPoint', async () => {
            await fc.assert(
                fc.asyncProperty(pointArbitrary, async (point) => {
                    const contractFactory = jest.fn().mockRejectedValue('Oh no')
                    const transformer = createOmniPointHardhatTransformer(contractFactory)

                    const transformed = await transformer(point)

                    expect(transformed).toBe(point)
                    expect(contractFactory).not.toHaveBeenCalled()
                })
            )
        })


it('should call the contractFactory if contract is not an OmniPoint', async () => {
            await fc.assert(
                fc.asyncProperty(pointHardhatArbitrary, evmAddressArbitrary, async (point, address) => {
                    fc.pre(!isOmniPoint(point))

                    const contract = new Contract(address, [])
                    const contractFactory = jest
                        .fn()
                        .mockImplementation(async (point: OmniPointHardhat) => ({ eid: point.eid, contract }))
                    const transformer = createOmniPointHardhatTransformer(contractFactory)

                    const transformed = await transformer(point)

                    expect(transformed).toEqual({ ...point, address })
                    expect(contractFactory).toHaveBeenCalledTimes(1)
                    expect(contractFactory).toHaveBeenCalledWith(point)
                })
            )
        })


it('should add the contractName if point is not an OmniPoint', async () => {
            await fc.assert(
                fc.asyncProperty(pointHardhatArbitrary, evmAddressArbitrary, async (point, address) => {
                    fc.pre(!isOmniPoint(point))

                    const contract = new Contract(address, [])
                    const contractFactory = jest
                        .fn()
                        .mockImplementation(async (point: OmniPointHardhat) => ({ eid: point.eid, contract }))
                    const transformer = createOmniPointHardhatTransformer(contractFactory)

                    const transformed = await transformer(point)

                    expect(transformed).toEqual({ eid: point.eid, address, contractName: point.contractName })
                    expect(contractFactory).toHaveBeenCalledTimes(1)
                    expect(contractFactory).toHaveBeenCalledWith(point)
                })
            )
        })


it('should call the pointTransformer on the point', async () => {
            await fc.assert(
                fc.asyncProperty(
                    pointHardhatArbitrary,
                    evmAddressArbitrary,
                    fc.anything(),
                    async (point, address, config) => {
                        fc.pre(!isOmniPoint(point))

                        const pointTransformer = jest.fn().mockImplementation(async (point: OmniPointHardhat) => ({
                            eid: point.eid,
                            address: address,
                        }))
                        const transformer = createOmniNodeHardhatTransformer(pointTransformer)

                        const node = await transformer({ contract: point, config })

                        expect(node).toEqual({ point: { eid: point.eid, address }, config })
                        expect(pointTransformer).toHaveBeenCalledTimes(1)
                        expect(pointTransformer).toHaveBeenCalledWith(point)
                    }
                )
            )
        })


it('should call the pointTransformer on from and to', async () => {
            await fc.assert(
                fc.asyncProperty(
                    pointHardhatArbitrary,
                    pointHardhatArbitrary,
                    evmAddressArbitrary,
                    fc.anything(),
                    async (from, to, address, config) => {
                        const pointTransformer = jest.fn().mockImplementation(async (point: OmniPointHardhat) => ({
                            eid: point.eid,
                            address,
                        }))
                        const transformer = createOmniEdgeHardhatTransformer(pointTransformer)

                        const edge = await transformer({ from, to, config })

                        expect(edge).toEqual({
                            vector: { from: { eid: from.eid, address }, to: { eid: to.eid, address } },
                            config,
                        })
                        expect(pointTransformer).toHaveBeenCalledTimes(2)
                        expect(pointTransformer).toHaveBeenCalledWith(from)
                        expect(pointTransformer).toHaveBeenCalledWith(to)
                    }
                )
            )
        })


it('should call the nodeTransformer and edgeTransformer for every node and edge and return the result', async () => {
            await fc.assert(
                fc.asyncProperty(
                    fc.array(nodeHardhatArbitrary),
                    fc.array(edgeHardhatArbitrary),
                    async (contracts, connections) => {
                        const nodeTransformer = jest.fn().mockImplementation(async (node) => ({ node }))
                        const edgeTransformer = jest.fn().mockImplementation(async (edge) => ({ edge }))
                        const transformer = createOmniGraphHardhatTransformer(nodeTransformer, edgeTransformer)

                        const graph = await transformer({ contracts, connections })

                        expect(graph.contracts).toEqual(contracts.map((node) => ({ node })))
                        expect(graph.connections).toEqual(connections.map((edge) => ({ edge })))
                    }
                )
            )
        })


it('should support sequential applicative', async () => {
            await fc.assert(
                fc.asyncProperty(
                    fc.array(nodeHardhatArbitrary),
                    fc.array(edgeHardhatArbitrary),
                    async (contracts, connections) => {
                        const nodeTransformer = jest.fn().mockImplementation(async (node) => ({ node }))
                        const edgeTransformer = jest.fn().mockImplementation(async (edge) => ({ edge }))
                        const transformerSequential = createOmniGraphHardhatTransformer(
                            nodeTransformer,
                            edgeTransformer,
                            sequence
                        )
                        const transformerParallel = createOmniGraphHardhatTransformer(
                            nodeTransformer,
                            edgeTransformer,
                            parallel
                        )

                        const graphSequential = await transformerSequential({ contracts, connections })
                        const graphParallel = await transformerParallel({ contracts, connections })

                        expect(graphSequential).toEqual(graphParallel)
                    }
                )
            )
        })


it('should just work', () => {
            fc.assert(
                fc.property(endpointArbitrary, evmAddressArbitrary, (eid, address) => {
                    const omniDeployment: OmniDeployment = { eid, deployment: { address } as Deployment }

                    expect(omniDeploymentToPoint(omniDeployment)).toEqual({ eid, address })
                })
            )
        })


it('should just work', () => {
            fc.assert(
                fc.property(endpointArbitrary, evmAddressArbitrary, (eid, address) => {
                    const omniDeployment: OmniDeployment = { eid, deployment: { address, abi: [] } as Deployment }
                    const omniContract = omniDeploymentToContract(omniDeployment)

                    // chai is not great with deep equality on class instances so we need to compare the result property by property
                    expect(omniContract.eid).toBe(eid)
                    expect(omniContract.contract.address).toBe(address)
                    expect(omniContract.contract.interface.fragments).toEqual([])
                })
            )
        })


it('should fall back on getting the artifact based on the deployments if artifact not found', async () => {
                await fc.assert(
                    fc.asyncProperty(evmAddressArbitrary, async (address) => {
                        const environmentFactory = createGetHreByEid(hre)
                        const contractFactory = createContractFactory(environmentFactory)

                        const env = await environmentFactory(EndpointId.ETHEREUM_V2_MAINNET)
                        jest.spyOn(env.deployments, 'getArtifact').mockRejectedValue(new Error(`oh no`))
                        jest.spyOn(env.deployments, 'getDeploymentsFromAddress').mockResolvedValue([
                            {
                                address,
                                abi: [],
                            },
                        ])

                        // Then check whether the factory will get it for us
                        const deployment = await contractFactory({
                            eid: EndpointId.ETHEREUM_V2_MAINNET,
                            address,
                            contractName: 'MyContract',
                        })

                        expect(deployment).toEqual({
                            eid: EndpointId.ETHEREUM_V2_MAINNET,
                            contract: expect.any(Contract),
                        })
                        expect(env.deployments.getArtifact).toHaveBeenCalledWith('MyContract')
                        expect(env.deployments.getDeploymentsFromAddress).toHaveBeenCalledWith(address)
                    })
                )
            })


it('should reject when eid does not exist', async () => {
                await fc.assert(
                    fc.asyncProperty(evmAddressArbitrary, async (address) => {
                        const contractFactory = createContractFactory()

                        await expect(() =>
                            contractFactory({ eid: EndpointId.CANTO_TESTNET, address })
                        ).rejects.toBeTruthy()
                    })
                )
            })


it('should reject when contract has not been deployed', async () => {
                await fc.assert(
                    fc.asyncProperty(evmAddressArbitrary, async (address) => {
                        const contractFactory = createContractFactory()

                        await expect(() =>
                            contractFactory({ eid: EndpointId.ETHEREUM_V2_MAINNET, address })
                        ).rejects.toThrow(/Could not find a deployment for address/)
                    })
                )
            })


it('should resolve when there is only one deployment for the contract', async () => {
                await fc.assert(
                    fc.asyncProperty(evmAddressArbitrary, async (address) => {
                        const environmentFactory = createGetHreByEid(hre)
                        const contractFactory = createContractFactory(environmentFactory)

                        const env = await environmentFactory(EndpointId.ETHEREUM_V2_MAINNET)
                        jest.spyOn(env.deployments, 'getDeploymentsFromAddress').mockResolvedValue([
                            {
                                address,
                                abi: [],
                            },
                        ])

                        // Then check whether the factory will get it for us
                        const deployment = await contractFactory({
                            eid: EndpointId.ETHEREUM_V2_MAINNET,
                            address,
                        })

                        expect(deployment).toEqual({
                            eid: EndpointId.ETHEREUM_V2_MAINNET,
                            contract: expect.any(Contract),
                        })
                        expect(env.deployments.getDeploymentsFromAddress).toHaveBeenCalledWith(address)
                    })
                )
            })


it('should merge ABIs when there are multiple deployments with the same address (proxy deployments)', async () => {
                await fc.assert(
                    fc.asyncProperty(evmAddressArbitrary, async (address) => {
                        const environmentFactory = createGetHreByEid(hre)
                        const contractFactory = createContractFactory(environmentFactory)

                        const env = await environmentFactory(EndpointId.ETHEREUM_V2_MAINNET)
                        jest.spyOn(env.deployments, 'getDeploymentsFromAddress').mockResolvedValue([
                            {
                                address,
                                abi: [
                                    { name: 'implementation', outputs: [], stateMutability: 'view', type: 'function' },
                                ],
                            },
                            {
                                address,
                                abi: [
                                    { name: 'contractMethod', outputs: [], stateMutability: 'view', type: 'function' },
                                ],
                            },
                        ])

                        // Then check whether the factory will get it for us
                        const omniContract = await contractFactory({
                            eid: EndpointId.ETHEREUM_V2_MAINNET,
                            address,
                        })

                        expect(omniContract).toEqual({
                            eid: EndpointId.ETHEREUM_V2_MAINNET,
                            contract: expect.any(Contract),
                        })
                        expect(omniContract.contract.implementation).toBeInstanceOf(Function)
                        expect(omniContract.contract.contractMethod).toBeInstanceOf(Function)
                    })
                )
            })


it('should reject if contractFactory rejects', async () => {
            await fc.assert(
                fc.asyncProperty(pointArbitrary, async (point) => {
                    const error = new Error()
                    const contractFactory = jest.fn().mockRejectedValue(error)
                    const connectedContractFactory = createConnectedContractFactory(contractFactory)

                    await expect(connectedContractFactory(point)).rejects.toBe(error)
                })
            )
        })


it('should reject if providerFactory rejects', async () => {
            await fc.assert(
                fc.asyncProperty(pointArbitrary, async (point) => {
                    const error = new Error()
                    const contractFactory = jest.fn().mockResolvedValue(new Contract(makeZeroAddress(undefined), []))
                    const providerFactory = jest.fn().mockRejectedValue(error)
                    const connectedContractFactory = createConnectedContractFactory(contractFactory, providerFactory)

                    await expect(connectedContractFactory(point)).rejects.toBe(error)
                })
            )
        })


it('should return a connected contract', async () => {
            await fc.assert(
                fc.asyncProperty(pointArbitrary, async (point) => {
                    const contract = new Contract(makeZeroAddress(undefined), [])
                    const provider = new JsonRpcProvider()
                    const contractFactory = jest.fn().mockResolvedValue({ eid: point.eid, contract })
                    const providerFactory = jest.fn().mockResolvedValue(provider)
                    const connectedContractFactory = createConnectedContractFactory(contractFactory, providerFactory)

                    const connectedOmniContract = await connectedContractFactory(point)

                    expect(connectedOmniContract.eid).toBe(point.eid)
                    expect(connectedOmniContract.contract).not.toBe(contract)
                    expect(connectedOmniContract.contract).toBeInstanceOf(Contract)
                    expect(connectedOmniContract.contract.provider).toBe(provider)
                })
            )
        })


it('should throw if negative index is passed', () => {
            fc.assert(
                fc.property(fc.integer({ max: -1 }), (index) => {
                    expect(() => signer.parse('signer', String(index))).toThrow()
                })
            )
        })


it('should return the address if valid address is passed', () => {
            fc.assert(
                fc.property(evmAddressArbitrary, (address) => {
                    expect(signer.parse('signer', address)).toEqual({ type: 'address', address })
                })
            )
        })


it('should return the index if non-negative index is passed', () => {
            fc.assert(
                fc.property(fc.integer({ min: 0 }), (index) => {
                    expect(signer.parse('signer', String(index))).toEqual({ type: 'index', index })
                })
            )
        })


it('should parse all valid endpoint IDs', () => {
            fc.assert(
                fc.property(endpointArbitrary, (eid) => {
                    expect(types.eid.parse('eid', String(eid))).toEqual(eid)
                })
            )
        })


it('should parse all valid endpoint labels', () => {
            fc.assert(
                fc.property(endpointArbitrary, (eid) => {
                    expect(types.eid.parse('eid', EndpointId[eid]!)).toEqual(eid)
                })
            )
        })


it('should not parse invalid strings', () => {
            fc.assert(
                fc.property(fc.string(), (eid) => {
                    // We filter out the values that by any slim chance could be valid endpoint IDs
                    fc.pre(EndpointId[eid] == null)
                    fc.pre(EndpointId[parseInt(eid)] == null)

                    expect(() => types.eid.parse('eid', eid)).toThrow()
                })
            )
        })


it('should not parse invalid numbers', () => {
            fc.assert(
                fc.property(fc.integer(), (eid) => {
                    fc.pre(EndpointId[eid] == null)

                    expect(() => types.eid.parse('eid', String(eid))).toThrow()
                })
            )
        })


it('should return undefined if called with undefined definition', async () => {
            await fc.assert(
                fc.asyncProperty(endpointArbitrary, async (eid) => {
                    await expect(createSignerAddressOrIndexFactory()(eid)).resolves.toBeUndefined()
                })
            )
        })


it('should return address if called with address definition', async () => {
            await fc.assert(
                fc.asyncProperty(evmAddressArbitrary, endpointArbitrary, async (address, eid) => {
                    await expect(createSignerAddressOrIndexFactory({ type: 'address', address })(eid)).resolves.toBe(
                        address
                    )
                })
            )
        })


it('should return index if called with index definition', async () => {
            await fc.assert(
                fc.asyncProperty(fc.integer(), endpointArbitrary, async (index, eid) => {
                    await expect(createSignerAddressOrIndexFactory({ type: 'index', index })(eid)).resolves.toBe(index)
                })
            )
        })


it('should reject if called with a missing named definition', async () => {
            const mockGetNamedAccounts = jest.fn().mockResolvedValue({ wombat: '0xwombat' })
            const mockHre = {
                getNamedAccounts: mockGetNamedAccounts,
            }
            const hreFactory = jest.fn().mockResolvedValue(mockHre)

            await fc.assert(
                fc.asyncProperty(endpointArbitrary, async (eid) => {
                    await expect(
                        createSignerAddressOrIndexFactory({ type: 'named', name: 'no-wombat' }, hreFactory)(eid)
                    ).rejects.toThrow(`Missing named account 'no-wombat' for eid ${formatEid(eid)}`)
                })
            )
        })


it('should resolve with an address if called with a defined named definition', async () => {
            const mockGetNamedAccounts = jest.fn().mockResolvedValue({ wombat: '0xwombat' })
            const mockHre = {
                getNamedAccounts: mockGetNamedAccounts,
            }
            const hreFactory = jest.fn().mockResolvedValue(mockHre)

            await fc.assert(
                fc.asyncProperty(endpointArbitrary, async (eid) => {
                    await expect(
                        createSignerAddressOrIndexFactory({ type: 'named', name: 'wombat' }, hreFactory)(eid)
                    ).resolves.toBe('0xwombat')
                })
            )
        })


it('should not run tsc', async () => {
            await fc.assert(
                fc.asyncProperty(fc.oneof(fc.string(), fc.constantFrom(undefined)), async (env) => {
                    fc.pre(env !== 'production')

                    const plugin = createDeclarationBuild({ enabled: undefined })

                    await plugin.buildEnd.call(pluginContext)

                    expect(spawnSyncMock).not.toHaveBeenCalled()
                })
            )
        })


it('executorLzReceiveOption', async () => {
        // sanity check that generated options are the same with value as 0 and not provided.
        expect(Options.newOptions().addExecutorLzReceiveOption(1, 0)).toEqual(
            Options.newOptions().addExecutorLzReceiveOption(1)
        )
        await fc.assert(
            fc.asyncProperty(
                omnicounterIncrementTypeArbitrary,
                gasLimitArbitrary,
                nativeDropArbitrary,

                // Test the generation and submission of arbitrary LZ_RECEIVE Options.  The transaction should succeed,
                // and the options from the transaction receipt logs should match the generated input.
                async (type, gasLimit, nativeDrop) => {
                    const options = Options.newOptions().addExecutorLzReceiveOption(gasLimit, nativeDrop)
                    const packetSentEvents = await incrementAndReturnLogs(type, options)
                    expect(packetSentEvents).toEqual([
                        expect.objectContaining({
                            args: expect.objectContaining({
                                options: expect.toEqualCaseInsensitive(options.toHex()),
                            }),
                        }),
                    ])
                    const rawPacketOptions = packetSentEvents[0]!.args.options
                    expect(rawPacketOptions).toEqualCaseInsensitive(options.toHex())

                    // test decoding
                    const packetOptions = Options.fromOptions(rawPacketOptions)
                    const decodedExecutorLzReceiveOption = packetOptions.decodeExecutorLzReceiveOption()
                    expect(decodedExecutorLzReceiveOption).toEqual({
                        gas: gasLimit,
                        value: nativeDrop,
                    })
                    expect(packetOptions.decodeExecutorNativeDropOption()).toEqual([])
                    expect(packetOptions.decodeExecutorComposeOption()).toEqual([])
                    expect(packetOptions.decodeExecutorOrderedExecutionOption()).toEqual(false)
                }
            ),
            { numRuns: 20 }
        )
    })


it('executorComposeOption', async () => {
        await fc.assert(
            fc.asyncProperty(
                omnicounterIncrementTypeArbitrary,
                composedIndexArbitrary,
                gasLimitArbitrary,
                nativeDropArbitrary,

                // Test the generation and submission of arbitrary COMPOSE Options.  The transaction should succeed, and
                // the options from the transaction receipt logs should match the generated input.
                async (type, index, gasLimit, nativeDrop) => {
                    const options = Options.newOptions()
                        .addExecutorComposeOption(index, gasLimit, nativeDrop)
                        // We also need to add a lzReceive option to avoid Executor_ZeroLzReceiveGasProvided error
                        .addExecutorLzReceiveOption(MIN_GAS_LIMIT)
                    const packetSentEvents = await incrementAndReturnLogs(type, options)
                    expect(packetSentEvents).toEqual([
                        expect.objectContaining({
                            args: expect.objectContaining({
                                options: expect.toEqualCaseInsensitive(options.toHex()),
                            }),
                        }),
                    ])
                    const rawPacketOptions = packetSentEvents[0]!.args.options
                    expect(rawPacketOptions).toEqualCaseInsensitive(options.toHex())

                    // test decoding
                    const packetOptions = Options.fromOptions(rawPacketOptions)
                    const decodedExecutorComposeOptions = packetOptions.decodeExecutorComposeOption()
                    expect(decodedExecutorComposeOptions).toEqual([
                        {
                            index,
                            gas: gasLimit,
                            value: nativeDrop,
                        },
                    ])
                    expect(packetOptions.decodeExecutorLzReceiveOption()).toEqual({
                        gas: MIN_GAS_LIMIT,
                        value: BigInt(0),
                    })
                    expect(packetOptions.decodeExecutorNativeDropOption()).toEqual([])
                    expect(packetOptions.decodeExecutorOrderedExecutionOption()).toEqual(false)
                }
            ),
            { numRuns: 20 }
        )
    })


it('executorLzNativeDrop', async () => {
        const address = await ethSigner.signer.getAddress()
        await fc.assert(
            fc.asyncProperty(
                omnicounterIncrementTypeArbitrary,
                nativeDropArbitrary,

                // Test the generation and submission of arbitrary NATIVE_DROP Options.  The transaction should succeed,
                // and the options from the transaction receipt logs should match the generated input.
                async (type, nativeDrop) => {
                    const options = Options.newOptions()
                        .addExecutorNativeDropOption(nativeDrop, address)
                        // We also need to add a lzReceive option to avoid Executor_ZeroLzReceiveGasProvided error
                        .addExecutorLzReceiveOption(MIN_GAS_LIMIT)
                    const packetSentEvents = await incrementAndReturnLogs(type, options)
                    expect(packetSentEvents).toEqual([
                        expect.objectContaining({
                            args: expect.objectContaining({
                                options: expect.toEqualCaseInsensitive(options.toHex()),
                            }),
                        }),
                    ])
                    const rawPacketOptions = packetSentEvents[0]!.args.options
                    expect(rawPacketOptions).toEqualCaseInsensitive(options.toHex())

                    // test decoding
                    const packetOptions = Options.fromOptions(rawPacketOptions)
                    const decodedExecutorNativeDropOptions = packetOptions.decodeExecutorNativeDropOption()
                    expect(decodedExecutorNativeDropOptions).toEqual([
                        {
                            amount: nativeDrop,
                            receiver: expect.toEqualCaseInsensitive(makeBytes32(address)),
                        },
                    ])
                    expect(packetOptions.decodeExecutorLzReceiveOption()).toEqual({
                        gas: MIN_GAS_LIMIT,
                        value: BigInt(0),
                    })
                    expect(packetOptions.decodeExecutorComposeOption()).toEqual([])
                    expect(packetOptions.decodeExecutorOrderedExecutionOption()).toEqual(false)
                }
            ),
            { numRuns: 20 }
        )
    })


it('executorOrderedExecutionOption', async () => {
        await fc.assert(
            fc.asyncProperty(
                omnicounterIncrementTypeArbitrary,

                // Test the generation and submission of arbitrary ORDERED Options.  The transaction should succeed, and the
                // options from the transaction receipt logs should match the generated input.
                async (type) => {
                    const options = Options.newOptions()
                        .addExecutorOrderedExecutionOption()
                        // We also need to add a lzReceive option to avoid Executor_ZeroLzReceiveGasProvided error
                        .addExecutorLzReceiveOption(MIN_GAS_LIMIT)
                    const packetSentEvents = await incrementAndReturnLogs(type, options)
                    expect(packetSentEvents).toHaveLength(1)
                    const rawPacketOptions = packetSentEvents[0]!.args.options.toLowerCase()
                    expect(rawPacketOptions).toBe(options.toHex().toLowerCase())

                    // test decoding
                    const packetOptions = Options.fromOptions(rawPacketOptions)
                    expect(packetOptions.decodeExecutorOrderedExecutionOption()).toBe(true)
                    expect(packetOptions.decodeExecutorLzReceiveOption()).toEqual({
                        gas: MIN_GAS_LIMIT,
                        value: BigInt(0),
                    })
                    expect(packetOptions.decodeExecutorComposeOption()).toEqual([])
                    expect(packetOptions.decodeExecutorNativeDropOption()).toEqual([])
                }
            ),
            { numRuns: 10 }
        )
    })


it('stacked options', async () => {
        // custom gasLimit arbitrary so "stacked" compose options won't have a gasLimit sum that overflows MAX_UINT_128
        const stackedGasLimitArbitrary: fc.Arbitrary<bigint> = fc.bigInt({
            min: MIN_GAS_LIMIT,
            max: BigInt('0xFFFFFFFFFFFFFFFF'),
        })

        // custom nativeDrop arbitrary so "stacked" compose options won't have a nativeDrop sum that exceeds DEFAULT_MAX_NATIVE_DROP
        const stackedValueArbitrary: fc.Arbitrary<bigint> = fc.bigInt({
            min: DEFAULT_MIN_NATIVE_DROP,
            max: DEFAULT_MAX_NATIVE_DROP / BigInt(4),
        })

        const address = await ethSigner.signer.getAddress()
        await fc.assert(
            fc.asyncProperty(
                omnicounterIncrementTypeArbitrary,
                composedIndexArbitrary,
                stackedGasLimitArbitrary,
                stackedValueArbitrary,

                // Test the generation of multiple Options in a single Packet.  The transaction should succeed.  Options
                // should be decoded to match inputs.  gasLimit and nativeDrop should be summed for Packets that have
                // multiple COMPOSE options for the same index.
                async (type, index, gasLimit, stackedValue) => {
                    const options = Options.newOptions()
                        .addExecutorComposeOption(index, gasLimit, stackedValue)
                        .addExecutorLzReceiveOption(gasLimit, stackedValue)
                        .addExecutorNativeDropOption(stackedValue, address)
                        .addExecutorComposeOption(index, gasLimit, stackedValue) // Repeat executor compose option to make sure values/gasLimits are summed

                    const packetSentEvents = await incrementAndReturnLogs(type, options)
                    expect(packetSentEvents).toEqual([
                        expect.objectContaining({
                            args: expect.objectContaining({
                                options: expect.toEqualCaseInsensitive(options.toHex()),
                            }),
                        }),
                    ])
                    const packetOptions = Options.fromOptions(packetSentEvents[0]!.args.options)

                    // check executorComposeOption
                    const packetComposeOptions = packetOptions.decodeExecutorComposeOption()
                    expect(packetComposeOptions).toEqual([
                        {
                            index,
                            gas: gasLimit * BigInt(2),
                            // compose options with same index are summed (in this specific case, just multiplied by 2)
                            value: stackedValue * BigInt(2),
                        },
                    ])

                    // check executorLzReceiveOption
                    const packetLzReceiveOption = packetOptions.decodeExecutorLzReceiveOption()
                    expect(packetLzReceiveOption).toEqual({
                        gas: gasLimit,
                        value: stackedValue,
                    })

                    // check executorNativeDropOption
                    const packetNativeDropOptions = packetOptions.decodeExecutorNativeDropOption()
                    expect(packetNativeDropOptions).toEqual([
                        {
                            amount: stackedValue,
                            receiver: expect.toEqualCaseInsensitive(makeBytes32(address)),
                        },
                    ])
                }
            )
        )
    })


it('should pass an error through if it already is a ContractError', async () => {
            await fc.assert(
                fc.asyncProperty(endpointArbitrary, async (eid) => {
                    const errorParser = await createContractErrorParser({ contract, eid })
                    const error = new RevertError('A reason is worth a million bytes')
                    const parsedError = await errorParser(error)

                    expect(parsedError).toBe(error)
                })
            )
        })


it('should parse assert/panic', async () => {
            await fc.assert(
                fc.asyncProperty(endpointArbitrary, async (eid) => {
                    const errorParser = await createContractErrorParser({ contract, eid })
                    const error = await assertFailed(contract.throwWithAssert())
                    const parsedError = await errorParser(error)

                    expect(parsedError).toEqual(new PanicError(BigInt(1)))
                })
            )
        })


it('should parse assert/panic with code', async () => {
            await fc.assert(
                fc.asyncProperty(endpointArbitrary, async (eid) => {
                    const errorParser = await createContractErrorParser({ contract, eid })
                    const error = await assertFailed(contract.throwWithAssertWithCode())
                    const parsedError = await errorParser(error)

                    expect(parsedError).toEqual(new PanicError(BigInt(18)))
                })
            )
        })


it('should parse revert with arguments', async () => {
            await fc.assert(
                fc.asyncProperty(endpointArbitrary, async (eid) => {
                    const errorParser = await createContractErrorParser({ contract, eid })
                    const error = await assertFailed(contract.throwWithRevertAndArgument('my bad'))
                    const parsedError = await errorParser(error)

                    expect(parsedError).toEqual(new RevertError('my bad'))
                })
            )
        })


it('should parse require with an argument', async () => {
            await fc.assert(
                fc.asyncProperty(endpointArbitrary, async (eid) => {
                    const errorParser = await createContractErrorParser({ contract, eid })
                    const error = await assertFailed(contract.throwWithRequireAndArgument('my bad'))
                    const parsedError = await errorParser(error)

                    expect(parsedError).toEqual(new RevertError('my bad'))
                })
            )
        })


it('should parse require with a custom error with no arguments', async () => {
            await fc.assert(
                fc.asyncProperty(endpointArbitrary, async (eid) => {
                    const errorParser = await createContractErrorParser({ contract, eid })
                    const error = await assertFailed(contract.throwWithCustomErrorAndNoArguments())
                    const parsedError = await errorParser(error)

                    expect(parsedError).toEqual(new CustomError('CustomErrorWithNoArguments', []))
                })
            )
        })


it('should parse require with a custom error with an argument', async () => {
            await fc.assert(
                fc.asyncProperty(endpointArbitrary, fc.string(), async (eid, arg) => {
                    const errorParser = await createContractErrorParser({ contract, eid })
                    const error = await assertFailed(contract.throwWithCustomErrorAndArgument(arg))
                    const parsedError = await errorParser(error)

                    expect(parsedError).toEqual(new CustomError('CustomErrorWithAnArgument', [arg]))
                })
            )
        })


it('should parse string', async () => {
            await fc.assert(
                fc.asyncProperty(endpointArbitrary, fc.string(), async (eid, message) => {
                    const errorParser = await createContractErrorParser({ contract, eid })
                    const parsedError = await errorParser(message)

                    expect(parsedError).toEqual(new UnknownError(`Unknown error: ${message}`))
                })
            )
        })


it('should parse an Error', async () => {
            await fc.assert(
                fc.asyncProperty(endpointArbitrary, fc.string(), async (eid, message) => {
                    const errorParser = await createContractErrorParser({ contract, eid })
                    const error = new Error(message)
                    const parsedError = await errorParser(error)

                    expect(parsedError).toEqual(new UnknownError(`Unknown error: ${error}`))
                })
            )
        })


it('should never reject', async () => {
            await fc.assert(
                fc.asyncProperty(endpointArbitrary, fc.anything(), async (eid, error) => {
                    const errorParser = await createContractErrorParser({ contract, eid })
                    const parsedError = await errorParser(error)

                    expect(parsedError).toBeInstanceOf(UnknownError)
                    expect(parsedError.reason).toBeUndefined()
                    expect(parsedError.message).toMatch(/Unknown error: /)
                })
            )
        })


it('child no arg event', async () => {
        const receipt = await (await child.emitNoArgEvent()).wait()
        expect(parseLogs(receipt, parent)).toMatchSnapshot()
        expect(parseLogsWithName(receipt, parent, 'NoArgEvent')).toEqual([]) // only the child should emit the event
        expect(parseLogsWithName(receipt, child, 'NoArgEvent')).toHaveLength(1)
        expect(parseLogsWithName(receipt, parallel, 'NoArgEvent')).toEqual([]) // parallel logs should be empty

        fc.assert(
            fc.property(fc.string(), (name) => {
                fc.pre(name !== 'NoArgEvent')
                expect(parseLogsWithName(receipt, parent, name)).toEqual([])
            })
        )
    })


it('not parse an event with one arg from a different contract', async () => {
        await fc.assert(
            fc.asyncProperty(fc.integer({ min: 0 }), async (arg) => {
                const receipt = await (await child.emitOneArgEvent(arg)).wait()
                expect(parseLogsWithName(receipt, parent, 'OneArgEvent')).toEqual([])
            }),
            { numRuns: 10 }
        )
    })


it('not parse an event with one arg with unknown name', async () => {
        await fc.assert(
            fc.asyncProperty(fc.integer({ min: 0 }), fc.string(), async (arg, name) => {
                fc.pre(name !== 'OneArgEvent')

                const receipt = await (await child.emitOneArgEvent(arg)).wait()
                expect(parseLogsWithName(receipt, parent, name)).toEqual([])
            }),
            { numRuns: 10 }
        )
    })


it('not parse an event with many args from a different contract', async () => {
        const eventNameArbitrary = fc.constantFrom('NoArgEvent', 'OneArgEvent', 'FourArgEvent')

        await fc.assert(
            fc.asyncProperty(fc.integer({ min: 0, max: 10 }), eventNameArbitrary, async (count, name) => {
                const receipt = await (await child.emitMany(count)).wait()

                expect(parseLogsWithName(receipt, child, name)).toHaveLength(count)
                expect(parseLogsWithName(receipt, parent, name)).toEqual([])
            }),
            { numRuns: 10 }
        )
    })


it('not parse an event with many args with unknown name from a different contract', async () => {
        await fc.assert(
            fc.asyncProperty(fc.integer({ min: 0, max: 10 }), fc.string(), async (count, name) => {
                fc.pre(name !== 'NoArgEvent')
                fc.pre(name !== 'OneArgEvent')
                fc.pre(name !== 'FourArgEvent')

                const receipt = await (await child.emitMany(count)).wait()

                expect(parseLogsWithName(receipt, parent, name)).toEqual([])
            }),
            { numRuns: 10 }
        )
    })


it('should parse a custom an error with an argument coming from the contract itself', async () => {
            const errorParser = await createErrorParser()

            await fc.assert(
                fc.asyncProperty(fc.string(), async (arg) => {
                    const error = await assertFailed(contract.throwWithCustomErrorAndArgument(arg))
                    const parsedError = await errorParser(error)

                    expect(parsedError).toEqual(new CustomError('CustomErrorWithAnArgument', [arg]))
                })
            )
        })


it('should parse a custom an error with an argument coming from a nested contract', async () => {
            const errorParser = await createErrorParser()

            await fc.assert(
                fc.asyncProperty(fc.string(), async (arg) => {
                    const error = await assertFailed(contract.throwNestedWithCustomErrorAndArgument(arg))
                    const parsedError = await errorParser(error)

                    expect(parsedError).toEqual(new CustomError('NestedCustomErrorWithAnArgument', [arg]))
                })
            )
        })


it('should parse a custom an error with an different arguments defined in more contracts coming from the contract itself', async () => {
            const errorParser = await createErrorParser()

            await fc.assert(
                fc.asyncProperty(fc.string(), async (arg) => {
                    const error = await assertFailed(contract.throwWithCommonErrorAndArgument(arg))
                    const parsedError = await errorParser(error)

                    expect(parsedError).toEqual(new CustomError('CommonErrorWithAnArgument', [arg]))
                })
            )
        })


it('should parse a custom an error with different arguments defined in more contracts coming from a nested contract', async () => {
            const errorParser = await createErrorParser()

            await fc.assert(
                fc.asyncProperty(fc.integer({ min: 0 }), async (arg) => {
                    const error = await assertFailed(contract.throwNestedWithCommonErrorAndArgument(arg))
                    const parsedError = await errorParser(error)

                    expect(parsedError).toEqual(new CustomError('CommonErrorWithAnArgument', [BigNumber.from(arg)]))
                })
            )
        })


it('should never reject', async () => {
            const errorParser = await createErrorParser()

            await fc.assert(
                fc.asyncProperty(fc.anything(), async (error) => {
                    const parsedError = await errorParser(error)

                    expect(parsedError).toBeInstanceOf(UnknownError)
                    expect(parsedError.reason).toBeUndefined()
                    expect(parsedError.message).toMatch(/Unknown error: /)
                })
            )
        })


it('should succeed with a valid config', () => {
            fc.assert(
                fc.property(oappNodeConfigArbitrary, (config) => {
                    expect(OAppNodeConfigSchema.parse(config)).toEqual(config)
                })
            )
        })


it('should pass any additional properties through', () => {
            fc.assert(
                fc.property(
                    oappNodeConfigArbitrary,
                    fc.dictionary(fc.string(), fc.anything()),
                    (config, extraProperties) => {
                        const combined = Object.assign({}, extraProperties, config)

                        expect(combined).toMatchObject(OAppNodeConfigSchema.parse(combined))
                    }
                )
            )
        })


it('should call owner on the contract', async () => {
            await fc.assert(
                fc.asyncProperty(omniContractArbitrary, evmAddressArbitrary, async (omniContract, owner) => {
                    omniContract.contract.owner.mockResolvedValue(owner)

                    const sdk = new OApp(omniContract)
                    const ownable = Object.assign(sdk, OwnableMixin)

                    expect(await ownable.getOwner()).toBe(owner)
                    expect(omniContract.contract.owner).toHaveBeenCalledTimes(1)
                })
            )
        })


it('should return true if the owner addresses match', async () => {
            await fc.assert(
                fc.asyncProperty(omniContractArbitrary, evmAddressArbitrary, async (omniContract, owner) => {
                    omniContract.contract.owner.mockResolvedValue(owner)

                    const sdk = new OApp(omniContract)
                    const ownable = Object.assign(sdk, OwnableMixin)

                    expect(await ownable.hasOwner(owner)).toBeTruthy()
                })
            )
        })


it('should return false if the owner addresses do not match', async () => {
            await fc.assert(
                fc.asyncProperty(
                    omniContractArbitrary,
                    evmAddressArbitrary,
                    evmAddressArbitrary,
                    async (omniContract, owner, user) => {
                        fc.pre(!areBytes32Equal(owner, user))

                        omniContract.contract.owner.mockResolvedValue(owner)

                        const sdk = new OApp(omniContract)
                        const ownable = Object.assign(sdk, OwnableMixin)

                        expect(await ownable.hasOwner(user)).toBeFalsy()
                    }
                )
            )
        })


it('should encode data for a transferOwnership call', async () => {
            await fc.assert(
                fc.asyncProperty(omniContractArbitrary, evmAddressArbitrary, async (omniContract, owner) => {
                    const sdk = new OApp(omniContract)
                    const ownable = Object.assign(sdk, OwnableMixin)
                    const encodeFunctionData = omniContract.contract.interface.encodeFunctionData as jest.Mock

                    encodeFunctionData.mockClear()

                    await ownable.setOwner(owner)

                    expect(encodeFunctionData).toHaveBeenCalledTimes(1)
                    expect(encodeFunctionData).toHaveBeenCalledWith('transferOwnership', [owner])
                })
            )
        })


it('should call peers on the contract', async () => {
            await fc.assert(
                fc.asyncProperty(omniContractArbitrary, endpointArbitrary, async (omniContract, peerEid) => {
                    const sdk = new OApp(omniContract)

                    await sdk.getPeer(peerEid)

                    expect(omniContract.contract.peers).toHaveBeenCalledTimes(1)
                    expect(omniContract.contract.peers).toHaveBeenCalledWith(peerEid)
                })
            )
        })


it('should return undefined if peers() returns a zero address, null or undefined', async () => {
                await fc.assert(
                    fc.asyncProperty(
                        omniContractArbitrary,
                        evmEndpointArbitrary,
                        nullishAddressArbitrary,
                        async (omniContract, peerEid, peer) => {
                            omniContract.contract.peers.mockResolvedValue(peer)

                            const sdk = new OApp(omniContract)

                            await expect(sdk.getPeer(peerEid)).resolves.toBeUndefined()
                        }
                    )
                )
            })


it('should return an address if peers() returns a non-null bytes', async () => {
                await fc.assert(
                    fc.asyncProperty(
                        omniContractArbitrary,
                        evmEndpointArbitrary,
                        evmAddressArbitrary,
                        async (omniContract, peerEid, peer) => {
                            fc.pre(!isZero(peer))

                            omniContract.contract.peers.mockResolvedValue(peer)

                            const sdk = new OApp(omniContract)

                            await expect(sdk.getPeer(peerEid)).resolves.toBe(peer)
                        }
                    )
                )
            })


it('should return undefined if peers() returns a zero address, null or undefined', async () => {
                await fc.assert(
                    fc.asyncProperty(
                        omniContractArbitrary,
                        solanaEndpointArbitrary,
                        nullishAddressArbitrary,
                        async (omniContract, peerEid, peer) => {
                            omniContract.contract.peers.mockResolvedValue(peer)

                            const sdk = new OApp(omniContract)

                            await expect(sdk.getPeer(peerEid)).resolves.toBeUndefined()
                        }
                    )
                )
            })


it('should return an address if peers() returns a non-null bytes', async () => {
                await fc.assert(
                    fc.asyncProperty(
                        omniContractArbitrary,
                        evmEndpointArbitrary,
                        solanaEndpointArbitrary,
                        solanaAddressArbitrary,
                        async (omniContract, eid, peerEid, peer) => {
                            // For Solana we need to take the native address format and turn it into EVM bytes32
                            //
                            // We do this by normalizing the value into a UInt8Array,
                            // then denormalizing it using an EVM eid
                            const peerBytes = normalizePeer(peer, peerEid)
                            const peerHex = makeBytes32(peerBytes)

                            fc.pre(!isZero(peerHex))

                            omniContract.contract.peers.mockResolvedValue(peerHex)

                            const sdk = new OApp(omniContract)

                            await expect(sdk.getPeer(peerEid)).resolves.toBe(peer)
                        }
                    )
                )
            })


it('should return undefined if peers() returns a zero address, null or undefined', async () => {
                await fc.assert(
                    fc.asyncProperty(
                        omniContractArbitrary,
                        aptosEndpointArbitrary,
                        nullishAddressArbitrary,
                        async (omniContract, peerEid, peer) => {
                            omniContract.contract.peers.mockResolvedValue(peer)

                            const sdk = new OApp(omniContract)

                            await expect(sdk.getPeer(peerEid)).resolves.toBeUndefined()
                        }
                    )
                )
            })


it('should return an address if peers() returns a non-null bytes', async () => {
                await fc.assert(
                    fc.asyncProperty(
                        omniContractArbitrary,
                        aptosEndpointArbitrary,
                        aptosAddressArbitrary,
                        async (omniContract, peerEid, peer) => {
                            fc.pre(!isZero(peer))

                            omniContract.contract.peers.mockResolvedValue(peer)

                            const sdk = new OApp(omniContract)

                            await expect(sdk.getPeer(peerEid)).resolves.toBe(peer)
                        }
                    )
                )
            })


it('should return true if peers returns a zero address', async () => {
                    await fc.assert(
                        fc.asyncProperty(
                            omniContractArbitrary,
                            evmEndpointArbitrary,
                            nullishAddressArbitrary,
                            nullishAddressArbitrary,
                            async (omniContract, peerEid, peer, probePeer) => {
                                omniContract.contract.peers.mockResolvedValue(peer)

                                const sdk = new OApp(omniContract)

                                await expect(sdk.hasPeer(peerEid, probePeer)).resolves.toBe(true)
                            }
                        )
                    )
                })


it('should return false if peers returns a non-zero address', async () => {
                    await fc.assert(
                        fc.asyncProperty(
                            omniContractArbitrary,
                            evmEndpointArbitrary,
                            nullishAddressArbitrary,
                            evmAddressArbitrary,
                            async (omniContract, peerEid, peer, probePeer) => {
                                fc.pre(!isZero(probePeer))

                                omniContract.contract.peers.mockResolvedValue(peer)

                                const sdk = new OApp(omniContract)

                                await expect(sdk.hasPeer(peerEid, probePeer)).resolves.toBe(false)
                            }
                        )
                    )
                })


it('should return true if peers() returns a matching bytes32', async () => {
                    await fc.assert(
                        fc.asyncProperty(
                            omniContractArbitrary,
                            evmEndpointArbitrary,
                            evmAddressArbitrary,
                            async (omniContract, peerEid, peer) => {
                                omniContract.contract.peers.mockResolvedValue(makeBytes32(peer))

                                const sdk = new OApp(omniContract)

                                await expect(sdk.hasPeer(peerEid, peer)).resolves.toBe(true)
                                await expect(sdk.hasPeer(peerEid, makeBytes32(peer))).resolves.toBe(true)
                            }
                        )
                    )
                })


it('should return true if peers returns a zero address', async () => {
                    await fc.assert(
                        fc.asyncProperty(
                            omniContractArbitrary,
                            solanaEndpointArbitrary,
                            nullishAddressArbitrary,
                            async (omniContract, peerEid, peer) => {
                                omniContract.contract.peers.mockResolvedValue(peer)

                                const sdk = new OApp(omniContract)

                                await expect(sdk.hasPeer(peerEid, undefined)).resolves.toBe(true)
                            }
                        )
                    )
                })


it('should return false if peers returns a different value', async () => {
                    await fc.assert(
                        fc.asyncProperty(
                            omniContractArbitrary,
                            solanaEndpointArbitrary,
                            solanaAddressArbitrary,
                            solanaAddressArbitrary,
                            async (omniContract, peerEid, peer, probePeer) => {
                                fc.pre(
                                    !areBytes32Equal(normalizePeer(peer, peerEid), normalizePeer(probePeer, peerEid))
                                )

                                const peerHex = makeBytes32(normalizePeer(peer, peerEid))

                                omniContract.contract.peers.mockResolvedValue(peerHex)

                                const sdk = new OApp(omniContract)

                                await expect(sdk.hasPeer(peerEid, probePeer)).resolves.toBe(false)
                            }
                        )
                    )
                })


it('should return true if peers() returns a matching value', async () => {
                    await fc.assert(
                        fc.asyncProperty(
                            omniContractArbitrary,
                            solanaEndpointArbitrary,
                            solanaAddressArbitrary,
                            async (omniContract, peerEid, peer) => {
                                const peerHex = makeBytes32(normalizePeer(peer, peerEid))

                                omniContract.contract.peers.mockResolvedValue(peerHex)

                                const sdk = new OApp(omniContract)

                                await expect(sdk.hasPeer(peerEid, peer)).resolves.toBe(true)
                            }
                        )
                    )
                })


it('should return true if peers returns a zero address', async () => {
                    await fc.assert(
                        fc.asyncProperty(
                            omniContractArbitrary,
                            aptosEndpointArbitrary,
                            nullishAddressArbitrary,
                            nullishAddressArbitrary,
                            async (omniContract, peerEid, peer, probePeer) => {
                                omniContract.contract.peers.mockResolvedValue(peer)

                                const sdk = new OApp(omniContract)

                                await expect(sdk.hasPeer(peerEid, probePeer)).resolves.toBe(true)
                            }
                        )
                    )
                })


it('should return false if peers returns a non-zero address', async () => {
                    await fc.assert(
                        fc.asyncProperty(
                            omniContractArbitrary,
                            aptosEndpointArbitrary,
                            nullishAddressArbitrary,
                            aptosAddressArbitrary,
                            async (omniContract, peerEid, peer, probePeer) => {
                                fc.pre(!isZero(probePeer))

                                omniContract.contract.peers.mockResolvedValue(peer)

                                const sdk = new OApp(omniContract)

                                await expect(sdk.hasPeer(peerEid, probePeer)).resolves.toBe(false)
                            }
                        )
                    )
                })


it('should return true if peers() returns a matching bytes32', async () => {
                    await fc.assert(
                        fc.asyncProperty(
                            omniContractArbitrary,
                            aptosEndpointArbitrary,
                            aptosAddressArbitrary,
                            async (omniContract, peerEid, peer) => {
                                omniContract.contract.peers.mockResolvedValue(makeBytes32(peer))

                                const sdk = new OApp(omniContract)

                                await expect(sdk.hasPeer(peerEid, peer)).resolves.toBe(true)
                                await expect(sdk.hasPeer(peerEid, makeBytes32(peer))).resolves.toBe(true)
                            }
                        )
                    )
                })


it('should encode data for a setPeer call', async () => {
                await fc.assert(
                    fc.asyncProperty(
                        omniContractArbitrary,
                        evmEndpointArbitrary,
                        evmAddressArbitrary,
                        async (omniContract, peerEid, peerAddress) => {
                            const sdk = new OApp(omniContract)
                            const encodeFunctionData = omniContract.contract.interface.encodeFunctionData

                            ;(encodeFunctionData as jest.Mock).mockClear()

                            await sdk.setPeer(peerEid, peerAddress)

                            expect(encodeFunctionData).toHaveBeenCalledTimes(1)
                            expect(encodeFunctionData).toHaveBeenCalledWith('setPeer', [
                                peerEid,
                                makeBytes32(peerAddress),
                            ])
                        }
                    )
                )
            })


it('should return an OmniTransaction', async () => {
                await fc.assert(
                    fc.asyncProperty(
                        omniContractArbitrary,
                        evmEndpointArbitrary,
                        evmAddressArbitrary,
                        fc.string(),
                        async (omniContract, peerEid, peerAddress, data) => {
                            const encodeFunctionData = omniContract.contract.interface.encodeFunctionData as jest.Mock
                            encodeFunctionData.mockReturnValue(data)

                            const sdk = new OApp(omniContract)
                            const transaction = await sdk.setPeer(peerEid, peerAddress)

                            expect(transaction).toEqual({
                                data,
                                description: `Setting peer for eid ${peerEid} (${formatEid(peerEid)}) to address ${makeBytes32(peerAddress)}`,
                                point: {
                                    eid: omniContract.eid,
                                    address: omniContract.contract.address,
                                },
                            })
                        }
                    )
                )
            })


it('should encode data for a setPeer call', async () => {
                await fc.assert(
                    fc.asyncProperty(
                        omniContractArbitrary,
                        solanaEndpointArbitrary,
                        solanaAddressArbitrary,
                        async (omniContract, peerEid, peerAddress) => {
                            const sdk = new OApp(omniContract)
                            const encodeFunctionData = omniContract.contract.interface.encodeFunctionData

                            ;(encodeFunctionData as jest.Mock).mockClear()

                            await sdk.setPeer(peerEid, peerAddress)

                            expect(encodeFunctionData).toHaveBeenCalledTimes(1)
                            expect(encodeFunctionData).toHaveBeenCalledWith('setPeer', [
                                peerEid,
                                makeBytes32(normalizePeer(peerAddress, peerEid)),
                            ])
                        }
                    )
                )
            })


it('should return an OmniTransaction', async () => {
                await fc.assert(
                    fc.asyncProperty(
                        omniContractArbitrary,
                        solanaEndpointArbitrary,
                        solanaAddressArbitrary,
                        fc.string(),
                        async (omniContract, peerEid, peerAddress, data) => {
                            const encodeFunctionData = omniContract.contract.interface.encodeFunctionData as jest.Mock
                            encodeFunctionData.mockReturnValue(data)

                            const sdk = new OApp(omniContract)
                            const transaction = await sdk.setPeer(peerEid, peerAddress)

                            expect(transaction).toEqual({
                                data,
                                description: `Setting peer for eid ${peerEid} (${formatEid(peerEid)}) to address ${makeBytes32(normalizePeer(peerAddress, peerEid))}`,
                                point: {
                                    eid: omniContract.eid,
                                    address: omniContract.contract.address,
                                },
                            })
                        }
                    )
                )
            })


it('should encode data for a setPeer call', async () => {
                await fc.assert(
                    fc.asyncProperty(
                        omniContractArbitrary,
                        aptosEndpointArbitrary,
                        aptosAddressArbitrary,
                        async (omniContract, peerEid, peerAddress) => {
                            const sdk = new OApp(omniContract)
                            const encodeFunctionData = omniContract.contract.interface.encodeFunctionData

                            ;(encodeFunctionData as jest.Mock).mockClear()

                            await sdk.setPeer(peerEid, peerAddress)

                            expect(encodeFunctionData).toHaveBeenCalledTimes(1)
                            expect(encodeFunctionData).toHaveBeenCalledWith('setPeer', [
                                peerEid,
                                makeBytes32(peerAddress),
                            ])
                        }
                    )
                )
            })


it('should return an OmniTransaction', async () => {
                await fc.assert(
                    fc.asyncProperty(
                        omniContractArbitrary,
                        aptosEndpointArbitrary,
                        aptosAddressArbitrary,
                        fc.string(),
                        async (omniContract, peerEid, peerAddress, data) => {
                            const encodeFunctionData = omniContract.contract.interface.encodeFunctionData as jest.Mock
                            encodeFunctionData.mockReturnValue(data)

                            const sdk = new OApp(omniContract)
                            const transaction = await sdk.setPeer(peerEid, peerAddress)

                            expect(transaction).toEqual({
                                data,
                                description: `Setting peer for eid ${peerEid} (${formatEid(peerEid)}) to address ${makeBytes32(peerAddress)}`,
                                point: {
                                    eid: omniContract.eid,
                                    address: omniContract.contract.address,
                                },
                            })
                        }
                    )
                )
            })


it('should reject if the call to endpoint() rejects', async () => {
            await fc.assert(
                fc.asyncProperty(omniContractArbitrary, async (omniContract) => {
                    omniContract.contract.endpoint.mockRejectedValue('No you did not')

                    const sdk = new OApp(omniContract)

                    await expect(sdk.getEndpointSDK()).rejects.toThrow(/Failed to get EndpointV2 address for OApp/)
                })
            )
        })


it('should reject if the call to endpoint() resolves with a zeroish address', async () => {
            await fc.assert(
                fc.asyncProperty(
                    omniContractArbitrary,
                    nullishAddressArbitrary,
                    async (omniContract, endpointAddress) => {
                        omniContract.contract.endpoint.mockResolvedValue(endpointAddress)

                        const sdk = new OApp(omniContract)

                        await expect(sdk.getEndpointSDK()).rejects.toThrow(
                            /EndpointV2 cannot be instantiated: EndpointV2 address has been set to a zero value for OApp/
                        )
                    }
                )
            )
        })


it('should return an EndpointV2 if the call to endpoint() resolves with a non-zeroish address', async () => {
            await fc.assert(
                fc.asyncProperty(omniContractArbitrary, evmAddressArbitrary, async (omniContract, endpointAddress) => {
                    fc.pre(!isZero(endpointAddress))

                    omniContract.contract.endpoint.mockResolvedValue(endpointAddress)

                    const sdk = new OApp(omniContract)
                    const endpoint = await sdk.getEndpointSDK()

                    expect(endpoint).toBeInstanceOf(EndpointV2)
                    expect(endpoint.point).toEqual({ eid: sdk.point.eid, address: endpointAddress })
                })
            )
        })


it('should return the contract name', async () => {
            await fc.assert(
                fc.asyncProperty(omniContractArbitrary, fc.string(), async (omniContract, name) => {
                    omniContract.contract.name.mockResolvedValue(name)

                    const sdk = new ERC20(omniContract)

                    await expect(sdk.getName()).resolves.toBe(name)

                    expect(omniContract.contract.name).toHaveBeenCalledTimes(1)
                })
            )
        })


it('should return the contract symbol', async () => {
            await fc.assert(
                fc.asyncProperty(omniContractArbitrary, fc.string(), async (omniContract, symbol) => {
                    omniContract.contract.symbol.mockResolvedValue(symbol)

                    const sdk = new ERC20(omniContract)

                    await expect(sdk.getSymbol()).resolves.toBe(symbol)

                    expect(omniContract.contract.symbol).toHaveBeenCalledTimes(1)
                })
            )
        })


it('should return the contract decimals', async () => {
            await fc.assert(
                fc.asyncProperty(omniContractArbitrary, fc.integer({ min: 1 }), async (omniContract, decimals) => {
                    omniContract.contract.decimals.mockResolvedValue(decimals)

                    const sdk = new ERC20(omniContract)

                    await expect(sdk.getDecimals()).resolves.toBe(decimals)

                    expect(omniContract.contract.decimals).toHaveBeenCalledTimes(1)
                })
            )
        })


it('should return the user balance', async () => {
            await fc.assert(
                fc.asyncProperty(
                    omniContractArbitrary,
                    evmAddressArbitrary,
                    fc.bigInt({ min: BigInt(0) }),
                    async (omniContract, user, balance) => {
                        omniContract.contract.balanceOf.mockResolvedValue(BigNumber.from(balance))

                        const sdk = new ERC20(omniContract)

                        await expect(sdk.getBalanceOf(user)).resolves.toBe(balance)

                        expect(omniContract.contract.balanceOf).toHaveBeenCalledTimes(1)
                        expect(omniContract.contract.balanceOf).toHaveBeenCalledWith(user)
                    }
                )
            )
        })


it('should return the user balance', async () => {
            await fc.assert(
                fc.asyncProperty(
                    omniContractArbitrary,
                    evmAddressArbitrary,
                    evmAddressArbitrary,
                    fc.bigInt({ min: BigInt(0) }),
                    async (omniContract, owner, spender, allowance) => {
                        omniContract.contract.allowance.mockResolvedValue(BigNumber.from(allowance))

                        const sdk = new ERC20(omniContract)

                        await expect(sdk.getAllowance(owner, spender)).resolves.toBe(allowance)

                        expect(omniContract.contract.allowance).toHaveBeenCalledTimes(1)
                        expect(omniContract.contract.allowance).toHaveBeenCalledWith(owner, spender)
                    }
                )
            )
        })


it('should not attempt to register libraries multiple times', async () => {
            await fc.assert(
                fc.asyncProperty(
                    pointArbitrary,
                    pointArbitrary,
                    pointArbitrary,
                    addressArbitrary,
                    async (pointA, pointB, pointC, libraryAddress) => {
                        fc.pre(!arePointsEqual(pointA, pointB))
                        fc.pre(!arePointsEqual(pointB, pointC))
                        fc.pre(!arePointsEqual(pointC, pointA))

                        const config: EndpointV2EdgeConfig = {
                            defaultReceiveLibrary: libraryAddress,
                            defaultSendLibrary: libraryAddress,
                        }

                        const graph: EndpointV2OmniGraph = {
                            contracts: [],
                            connections: [
                                {
                                    vector: { from: pointA, to: pointB },
                                    config,
                                },
                                {
                                    vector: { from: pointA, to: pointC },
                                    config,
                                },
                                {
                                    vector: { from: pointB, to: pointA },
                                    config,
                                },
                                {
                                    vector: { from: pointB, to: pointC },
                                    config,
                                },
                                {
                                    vector: { from: pointC, to: pointA },
                                    config,
                                },
                                {
                                    vector: { from: pointC, to: pointB },
                                    config,
                                },
                            ],
                        }

                        const createSdk = jest.fn((point: OmniPoint) => new MockSDK(point) as unknown as IEndpointV2)
                        const result = await configureEndpointV2RegisterLibraries(graph, createSdk)

                        // The result should not contain any duplicate library registrations
                        expect(result).toEqual([
                            { point: pointA, data: `0xREGISTERLIBRARY ${libraryAddress}` },
                            { point: pointB, data: `0xREGISTERLIBRARY ${libraryAddress}` },
                            { point: pointC, data: `0xREGISTERLIBRARY ${libraryAddress}` },
                        ])
                    }
                )
            )
        })


it('should sort requiredDVNs and optionalDVNs before encoding', async () => {
            fc.assert(
                fc.property(dvnsArbitrary, (dvns) => {
                    const sortedDvns = [...dvns].sort((a, b) => a.localeCompare(b))
                    const ulnConfigUnsorted: UlnReadUlnConfig = {
                        executor: AddressZero,
                        optionalDVNThreshold: 0,
                        optionalDVNs: dvns,
                        requiredDVNs: dvns,
                    }

                    const ulnConfigSorted: UlnReadUlnConfig = {
                        ...ulnConfigUnsorted,
                        optionalDVNs: sortedDvns,
                        requiredDVNs: sortedDvns,
                    }

                    const ulnConfigEncodedUnsorted = ulnSdk.encodeUlnConfig(ulnConfigUnsorted)
                    const ulnConfigEncodedSorted = ulnSdk.encodeUlnConfig(ulnConfigSorted)
                    expect(ulnConfigEncodedSorted).toBe(ulnConfigEncodedUnsorted)
                }),
                { numRuns: 20 }
            )
        })


it('should sort requiredDVNs and optionalDVNs', async () => {
            await fc.assert(
                fc.asyncProperty(channelIdArbitrary, dvnsArbitrary, async (eid, dvns) => {
                    const sortedDvns = [...dvns].sort((a, b) => a.localeCompare(b))
                    const ulnConfigUnsorted: UlnReadUlnConfig = {
                        executor: AddressZero,
                        optionalDVNThreshold: 0,
                        optionalDVNs: dvns,
                        requiredDVNs: dvns,
                    }

                    const ulnConfigSorted: UlnReadUlnConfig = {
                        ...ulnConfigUnsorted,
                        optionalDVNs: sortedDvns,
                        requiredDVNs: sortedDvns,
                    }

                    // Let's check that both the sorted and the unsorted config produce the same transaction
                    const transactionUnsorted = await ulnSdk.setDefaultUlnConfig(eid, ulnConfigUnsorted)
                    const transactionsSorted = await ulnSdk.setDefaultUlnConfig(eid, ulnConfigSorted)
                    expect(transactionUnsorted).toEqual(transactionsSorted)

                    // And let's check that the encoding call is correct and the DVNs are sorted
                    expect(transactionsSorted.data).toBe(
                        ulnSdk.contract.contract.interface.encodeFunctionData('setDefaultReadLibConfigs', [
                            [
                                {
                                    eid,
                                    config: {
                                        executor: AddressZero,
                                        optionalDVNThreshold: 0,
                                        optionalDVNs: sortedDvns.map(addChecksum),
                                        requiredDVNs: sortedDvns.map(addChecksum),
                                        requiredDVNCount: sortedDvns.length,
                                        optionalDVNCount: sortedDvns.length,
                                    },
                                },
                            ],
                        ])
                    )
                }),
                { numRuns: 20 }
            )
        })


it('should default the missing attributes', async () => {
            await fc.assert(
                fc.asyncProperty(channelIdArbitrary, dvnsArbitrary, async (eid, dvns) => {
                    const sortedDvns = [...dvns].sort((a, b) => a.localeCompare(b))
                    const ulnUserConfig: UlnReadUlnUserConfig = {
                        requiredDVNs: dvns,
                    }
                    const ulnConfig: UlnReadUlnConfig = {
                        requiredDVNs: dvns,
                        executor: AddressZero,
                        optionalDVNThreshold: 0,
                        optionalDVNs: [],
                    }

                    // Let's check that both the sorted and the unsorted config produce the same transaction
                    const transactionsWithDefaults = await ulnSdk.setDefaultUlnConfig(eid, ulnUserConfig)
                    const transactionsWithFullConfig = await ulnSdk.setDefaultUlnConfig(eid, ulnConfig)
                    expect(transactionsWithDefaults).toEqual(transactionsWithFullConfig)

                    // And let's check that the encoding call is correct and the DVNs are sorted
                    expect(transactionsWithDefaults.data).toBe(
                        ulnSdk.contract.contract.interface.encodeFunctionData('setDefaultReadLibConfigs', [
                            [
                                {
                                    eid,
                                    config: {
                                        executor: ulnConfig.executor,
                                        optionalDVNThreshold: ulnConfig.optionalDVNThreshold,
                                        optionalDVNs: ulnConfig.optionalDVNs,
                                        requiredDVNs: sortedDvns.map(addChecksum),
                                        requiredDVNCount: ulnConfig.requiredDVNs.length,
                                        optionalDVNCount: ulnConfig.optionalDVNs.length,
                                    },
                                },
                            ],
                        ])
                    )
                }),
                { numRuns: 20 }
            )
        })


it('should return true if the configs are identical', async () => {
            await fc.assert(
                fc.asyncProperty(
                    channelIdArbitrary,
                    evmAddressArbitrary,
                    ulnConfigArbitrary,
                    async (channelId, oapp, ulnConfig) => {
                        getAppUlnConfigSpy.mockReset()
                        getAppUlnConfigSpy.mockResolvedValue(ulnConfig)

                        await expect(ulnSdk.hasAppUlnConfig(channelId, oapp, ulnConfig)).resolves.toBeTruthy()
                    }
                ),
                { numRuns: 20 }
            )
        })


it('should return true if config has extra properties', async () => {
            await fc.assert(
                fc.asyncProperty(
                    channelIdArbitrary,
                    evmAddressArbitrary,
                    ulnConfigArbitrary,
                    fc.object(),
                    async (channelId, oapp, ulnConfig, extra) => {
                        getAppUlnConfigSpy.mockReset()
                        getAppUlnConfigSpy.mockResolvedValue(ulnConfig)

                        await expect(
                            ulnSdk.hasAppUlnConfig(channelId, oapp, {
                                ...extra,
                                ...ulnConfig,
                            })
                        ).resolves.toBeTruthy()
                    }
                ),
                { numRuns: 20 }
            )
        })


it('should return true if configs with defaults are identical', async () => {
            await fc.assert(
                fc.asyncProperty(
                    channelIdArbitrary,
                    evmAddressArbitrary,
                    dvnsArbitrary,
                    async (channelId, oapp, dvns) => {
                        const ulnUserConfig: UlnReadUlnUserConfig = {
                            requiredDVNs: dvns,
                        }
                        const ulnConfig: UlnReadUlnConfig = {
                            requiredDVNs: dvns,
                            optionalDVNs: [],
                            optionalDVNThreshold: 0,
                            executor: AddressZero,
                        }

                        getAppUlnConfigSpy.mockReset()
                        getAppUlnConfigSpy.mockResolvedValue(ulnConfig)

                        await expect(ulnSdk.hasAppUlnConfig(channelId, oapp, ulnUserConfig)).resolves.toBeTruthy()
                    }
                ),
                { numRuns: 20 }
            )
        })


it('should return false if configs with defaults are not identical', async () => {
            await fc.assert(
                fc.asyncProperty(
                    channelIdArbitrary,
                    evmAddressArbitrary,
                    ulnConfigArbitrary,
                    async (channelId, oapp, ulnConfig) => {
                        // We only want to test againsts configs that are not
                        // equal to the default config
                        fc.pre(
                            ulnConfig.executor !== AddressZero ||
                                ulnConfig.optionalDVNThreshold !== 0 ||
                                ulnConfig.optionalDVNs.length !== 0
                        )

                        const ulnUserConfig: UlnReadUlnUserConfig = {
                            requiredDVNs: ulnConfig.requiredDVNs,
                        }

                        getAppUlnConfigSpy.mockReset()
                        getAppUlnConfigSpy.mockResolvedValue(ulnConfig)

                        await expect(ulnSdk.hasAppUlnConfig(channelId, oapp, ulnUserConfig)).resolves.toBeFalsy()
                    }
                ),
                { numRuns: 20 }
            )
        })


it('should return true if the configs are identical except for the dvn casing', async () => {
            await fc.assert(
                fc.asyncProperty(
                    channelIdArbitrary,
                    evmAddressArbitrary,
                    ulnConfigArbitrary,
                    async (channelId, oapp, ulnConfig) => {
                        getAppUlnConfigSpy.mockReset()
                        getAppUlnConfigSpy.mockResolvedValue(ulnConfig)

                        await expect(
                            ulnSdk.hasAppUlnConfig(channelId, oapp, {
                                ...ulnConfig,
                                requiredDVNs: ulnConfig.requiredDVNs.map(addChecksum),
                                optionalDVNs: ulnConfig.optionalDVNs.map(addChecksum),
                            })
                        ).resolves.toBeTruthy()
                    }
                ),
                { numRuns: 20 }
            )
        })


it('should return true if the configs are identical except for the dvn sorting and casing', async () => {
            await fc.assert(
                fc.asyncProperty(
                    channelIdArbitrary,
                    evmAddressArbitrary,
                    ulnConfigArbitrary,
                    async (channelId, oapp, ulnConfig) => {
                        getAppUlnConfigSpy.mockReset()
                        getAppUlnConfigSpy.mockResolvedValue(ulnConfig)

                        await expect(
                            ulnSdk.hasAppUlnConfig(channelId, oapp, {
                                ...ulnConfig,
                                requiredDVNs: ulnConfig.requiredDVNs.map(addChecksum).sort(compareBytes32Ascending),
                                optionalDVNs: ulnConfig.optionalDVNs.map(addChecksum).sort(compareBytes32Ascending),
                            })
                        ).resolves.toBeTruthy()
                    }
                ),
                { numRuns: 20 }
            )
        })


it('should return false if the confirmations are different', async () => {
            await fc.assert(
                fc.asyncProperty(
                    channelIdArbitrary,
                    evmAddressArbitrary,
                    ulnConfigArbitrary,
                    evmAddressArbitrary,
                    async (channelId, oapp, ulnConfig, executor) => {
                        fc.pre(executor !== ulnConfig.executor)

                        getAppUlnConfigSpy.mockReset()
                        getAppUlnConfigSpy.mockResolvedValue(ulnConfig)

                        await expect(
                            ulnSdk.hasAppUlnConfig(channelId, oapp, {
                                ...ulnConfig,
                                executor,
                            })
                        ).resolves.toBeFalsy()
                    }
                ),
                { numRuns: 20 }
            )
        })


it('should return false if the optionalDVNThresholds are different', async () => {
            await fc.assert(
                fc.asyncProperty(
                    channelIdArbitrary,
                    evmAddressArbitrary,
                    ulnConfigArbitrary,
                    fc.integer(),
                    async (channelId, oapp, ulnConfig, optionalDVNThreshold) => {
                        fc.pre(optionalDVNThreshold !== ulnConfig.optionalDVNThreshold)

                        getAppUlnConfigSpy.mockReset()
                        getAppUlnConfigSpy.mockResolvedValue(ulnConfig)

                        await expect(
                            ulnSdk.hasAppUlnConfig(channelId, oapp, {
                                ...ulnConfig,
                                optionalDVNThreshold,
                            })
                        ).resolves.toBeFalsy()
                    }
                ),
                { numRuns: 20 }
            )
        })


it('should return false if the requiredDVNs are different', async () => {
            await fc.assert(
                fc.asyncProperty(
                    channelIdArbitrary,
                    evmAddressArbitrary,
                    ulnConfigArbitrary,
                    dvnsArbitrary,
                    async (channelId, oapp, ulnConfig, extraRequiredDVNs) => {
                        getAppUlnConfigSpy.mockReset()
                        getAppUlnConfigSpy.mockResolvedValue(ulnConfig)

                        await expect(
                            ulnSdk.hasAppUlnConfig(channelId, oapp, {
                                ...ulnConfig,
                                requiredDVNs: [...ulnConfig.requiredDVNs, ...extraRequiredDVNs],
                            })
                        ).resolves.toBeFalsy()
                    }
                ),
                { numRuns: 20 }
            )
        })


it('should return false if the optionalDVNs are different', async () => {
            await fc.assert(
                fc.asyncProperty(
                    channelIdArbitrary,
                    evmAddressArbitrary,
                    ulnConfigArbitrary,
                    dvnsArbitrary,
                    async (channelId, oapp, ulnConfig, extraOptionalDVNs) => {
                        getAppUlnConfigSpy.mockReset()
                        getAppUlnConfigSpy.mockResolvedValue(ulnConfig)

                        await expect(
                            ulnSdk.hasAppUlnConfig(channelId, oapp, {
                                ...ulnConfig,
                                optionalDVNs: [...ulnConfig.optionalDVNs, ...extraOptionalDVNs],
                            })
                        ).resolves.toBeFalsy()
                    }
                ),
                { numRuns: 20 }
            )
        })


it('should sort requiredDVNs and optionalDVNs before encoding', async () => {
            fc.assert(
                fc.property(dvnsArbitrary, (dvns) => {
                    const sortedDvns = [...dvns].sort((a, b) => a.localeCompare(b))
                    const ulnConfigUnsorted: Uln302UlnConfig = {
                        confirmations: BigInt(100),
                        optionalDVNThreshold: 0,
                        optionalDVNs: dvns,
                        requiredDVNs: dvns,
                    }

                    const ulnConfigSorted: Uln302UlnConfig = {
                        ...ulnConfigUnsorted,
                        optionalDVNs: sortedDvns,
                        requiredDVNs: sortedDvns,
                    }

                    const ulnConfigEncodedUnsorted = ulnSdk.encodeUlnConfig(ulnConfigUnsorted)
                    const ulnConfigEncodedSorted = ulnSdk.encodeUlnConfig(ulnConfigSorted)
                    expect(ulnConfigEncodedSorted).toBe(ulnConfigEncodedUnsorted)
                }),
                { numRuns: 20 }
            )
        })


it('should sort requiredDVNs and optionalDVNs', async () => {
            await fc.assert(
                fc.asyncProperty(endpointArbitrary, dvnsArbitrary, async (eid, dvns) => {
                    const sortedDvns = [...dvns].sort((a, b) => a.localeCompare(b))
                    const ulnConfigUnsorted: Uln302UlnConfig = {
                        confirmations: BigInt(100),
                        optionalDVNThreshold: 0,
                        optionalDVNs: dvns,
                        requiredDVNs: dvns,
                    }

                    const ulnConfigSorted: Uln302UlnConfig = {
                        ...ulnConfigUnsorted,
                        optionalDVNs: sortedDvns,
                        requiredDVNs: sortedDvns,
                    }

                    // Let's check that both the sorted and the unsorted config produce the same transaction
                    const transactionUnsorted = await ulnSdk.setDefaultUlnConfig(eid, ulnConfigUnsorted)
                    const transactionsSorted = await ulnSdk.setDefaultUlnConfig(eid, ulnConfigSorted)
                    expect(transactionUnsorted).toEqual(transactionsSorted)

                    // And let's check that the encoding call is correct and the DVNs are sorted
                    expect(transactionsSorted.data).toBe(
                        ulnSdk.contract.contract.interface.encodeFunctionData('setDefaultUlnConfigs', [
                            [
                                {
                                    eid,
                                    config: {
                                        confirmations: BigInt(100),
                                        optionalDVNThreshold: 0,
                                        optionalDVNs: sortedDvns.map(addChecksum),
                                        requiredDVNs: sortedDvns.map(addChecksum),
                                        requiredDVNCount: sortedDvns.length,
                                        optionalDVNCount: sortedDvns.length,
                                    },
                                },
                            ],
                        ])
                    )
                }),
                { numRuns: 20 }
            )
        })