Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions abi/Child.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
1 change: 1 addition & 0 deletions abi/Child.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const ChildAbi = [] as const
85 changes: 85 additions & 0 deletions abi/ReturnDataTester.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
[
{
"inputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "callStuff",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "createChildContract",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "doStuff",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [],
"name": "getCapturedReturnDataSize",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "otherField",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "returndatasize",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]
85 changes: 85 additions & 0 deletions abi/ReturnDataTester.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
export const ReturnDataTesterAbi = [
{
'inputs': [],
'stateMutability': 'nonpayable',
'type': 'constructor',
},
{
'inputs': [],
'name': 'callStuff',
'outputs': [
{
'internalType': 'uint256',
'name': '',
'type': 'uint256',
},
],
'stateMutability': 'nonpayable',
'type': 'function',
},
{
'inputs': [],
'name': 'createChildContract',
'outputs': [
{
'internalType': 'uint256',
'name': '',
'type': 'uint256',
},
],
'stateMutability': 'nonpayable',
'type': 'function',
},
{
'inputs': [],
'name': 'doStuff',
'outputs': [
{
'internalType': 'uint256',
'name': '',
'type': 'uint256',
},
],
'stateMutability': 'pure',
'type': 'function',
},
{
'inputs': [],
'name': 'getCapturedReturnDataSize',
'outputs': [
{
'internalType': 'uint256',
'name': '',
'type': 'uint256',
},
],
'stateMutability': 'view',
'type': 'function',
},
{
'inputs': [],
'name': 'otherField',
'outputs': [
{
'internalType': 'uint256',
'name': '',
'type': 'uint256',
},
],
'stateMutability': 'view',
'type': 'function',
},
{
'inputs': [],
'name': 'returndatasize',
'outputs': [
{
'internalType': 'uint256',
'name': '',
'type': 'uint256',
},
],
'stateMutability': 'view',
'type': 'function',
},
] as const
25 changes: 25 additions & 0 deletions contracts/ReturnDataTester.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Child contract with dummy state passed through constructor
contract Child {
}

// Parent contract that creates a child and captures return data
contract ReturnDataTester {
uint public returndatasize;

function createChildContract() external {
new Child();
uint size;
assembly {
size := returndatasize()
}
returndatasize = size;
}

// Read-only function to return the captured return data size
function getCapturedReturnDataSize() external view returns (uint) {
return returndatasize;
}
}
Binary file added evm/Child.bin
Binary file not shown.
Binary file added evm/ReturnDataTester.bin
Binary file not shown.
Binary file added pvm/Child.polkavm
Binary file not shown.
Binary file added pvm/ReturnDataTester.polkavm
Binary file not shown.
100 changes: 76 additions & 24 deletions src/others.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { expect } from '@std/expect'
import { decodeEventLog, encodeFunctionData, parseEther } from 'viem'
import { ErrorsAbi } from '../abi/Errors.ts'
import { EventExampleAbi } from '../abi/EventExample.ts'
import { ReturnDataTesterAbi } from '../abi/ReturnDataTester.ts'

// Initialize test environment
const env = await getEnv()
Expand All @@ -31,6 +32,15 @@ const getEventExampleAddr = memoizedDeploy(
}),
)

const getReturnDataTesterAddr = memoizedDeploy(
env,
() =>
env.serverWallet.deployContract({
abi: ReturnDataTesterAbi,
bytecode: getByteCode('ReturnDataTester', env.evm),
}),
)

Deno.test('eth_call with insufficient funds', opts, async () => {
try {
await env.emptyWallet.simulateContract({
Expand All @@ -44,18 +54,14 @@ Deno.test('eth_call with insufficient funds', opts, async () => {
} catch (_) {
const lastJsonRpcError = jsonRpcErrors.pop()
expect(lastJsonRpcError?.code).toBe(-32000)
expect(lastJsonRpcError?.message).toContain(
'insufficient funds',
)
expect(lastJsonRpcError?.message).toContain('insufficient funds')
expect(lastJsonRpcError?.data).toBeUndefined()
}
})

Deno.test('eth_call transfer with insufficient funds', opts, async () => {
const value = parseEther('10')
const balance = await env.emptyWallet.getBalance(
env.emptyWallet.account,
)
const balance = await env.emptyWallet.getBalance(env.emptyWallet.account)
if (balance >= value) {
throw new Error('Balance should be less than 10')
}
Expand All @@ -68,9 +74,7 @@ Deno.test('eth_call transfer with insufficient funds', opts, async () => {
} catch (_) {
const lastJsonRpcError = jsonRpcErrors.pop()
expect(lastJsonRpcError?.code).toBe(-32000)
expect(lastJsonRpcError?.message).toContain(
'insufficient funds',
)
expect(lastJsonRpcError?.message).toContain('insufficient funds')
expect(lastJsonRpcError?.data).toBeUndefined()
}
})
Expand All @@ -88,9 +92,7 @@ Deno.test('eth_estimate with insufficient funds', opts, async () => {
} catch (_err) {
const lastJsonRpcError = jsonRpcErrors.pop()
expect(lastJsonRpcError?.code).toBe(-32000)
expect(lastJsonRpcError?.message).toContain(
'insufficient funds',
)
expect(lastJsonRpcError?.message).toContain('insufficient funds')
expect(lastJsonRpcError?.data).toBeUndefined()
}
})
Expand All @@ -111,9 +113,7 @@ Deno.test(
} catch (_err) {
const lastJsonRpcError = jsonRpcErrors.pop()
expect(lastJsonRpcError?.code).toBe(-32000)
expect(lastJsonRpcError?.message).toContain(
'insufficient funds',
)
expect(lastJsonRpcError?.message).toContain('insufficient funds')
expect(lastJsonRpcError?.data).toBeUndefined()
}
},
Expand Down Expand Up @@ -168,18 +168,14 @@ Deno.test(
} catch (_err) {
const lastJsonRpcError = jsonRpcErrors.pop()
expect(lastJsonRpcError?.code).toBe(-32000)
expect(lastJsonRpcError?.message).toContain(
'insufficient funds',
)
expect(lastJsonRpcError?.message).toContain('insufficient funds')
expect(lastJsonRpcError?.data).toBeUndefined()
}
},
)

Deno.test('eth_estimate with no gas specified', opts, async () => {
const balance = await env.serverWallet.getBalance(
env.emptyWallet.account,
)
const balance = await env.serverWallet.getBalance(env.emptyWallet.account)
expect(balance).toBe(0n)

const data = encodeFunctionData({
Expand Down Expand Up @@ -209,9 +205,7 @@ Deno.test('logs', opts, async () => {
})

const hash = await env.serverWallet.writeContract(request)
const receipt = await env.serverWallet.waitForTransactionReceipt(
hash,
)
const receipt = await env.serverWallet.waitForTransactionReceipt(hash)
const logs = await env.serverWallet.getLogs({
address,
blockHash: receipt.blockHash,
Expand Down Expand Up @@ -239,3 +233,61 @@ Deno.test('logs', opts, async () => {
},
})
})

Deno.test('returndata_works', opts, async () => {
if (!env.evm) {
console.warn(
"Skip this test on PVM, as it doesn't support instantiating a child contract whose code is not yet on-chain.",
)
return
}
Comment thread
marian-radu marked this conversation as resolved.
Outdated

// 1. deploy ReturnDataTester contract and get its address
const address = await getReturnDataTesterAddr()

// 2. call createChildContract to create a child contract
const { request } = await env.serverWallet.simulateContract({
address,
abi: ReturnDataTesterAbi,
functionName: 'createChildContract',
})
const hash = await env.serverWallet.writeContract(request)
const receipt = await env.serverWallet.waitForTransactionReceipt(hash)
expect(receipt.status).toEqual('success')

// 3. call getCapturedReturnDataSize to get the recorded return data size
const dataSize = await env.emptyWallet.readContract({
address: address,
abi: ReturnDataTesterAbi,
functionName: 'getCapturedReturnDataSize',
args: [],
})

expect(dataSize).toBe(0n)
})

Deno.test('eth_call_deployment_returns_bytecode', opts, async () => {
const result = await env.serverWallet.call({
data: getByteCode('Errors', env.evm),
})

expect(typeof result).toBe('object')
if (env.evm) {
expect(result).not.toBeNull()
expect('data' in result).toBe(true)
expect(typeof result.data).toBe('string')
const data = result['data']
if (typeof data !== 'string') {
throw new Error(
`expected result.data to be string, got ${typeof data}`,
)
}

// hex string; '0xDDDD...'
expect(data.startsWith('0x')).toBe(true)
expect(data.length).toBeGreaterThan(2)
} else {
//TODO: Is fix required for PVM ?
expect(result).toEqual({})
Comment thread
pgherveou marked this conversation as resolved.
Outdated
}
})
Loading