Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
57 changes: 57 additions & 0 deletions test/examples/program/GetPeople.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import '../../../contracts/GatewayFetchTarget.sol';
import '../../../contracts/GatewayFetcher.sol';
import '../../../contracts/GatewayRequest.sol';

/**
* @title Program-based Gateway Request Example
* @dev This example demonstrates a working program-based approach to gateway requests.
*/

contract GetPeople is GatewayFetchTarget {
using GatewayFetcher for GatewayRequest;

IGatewayVerifier immutable _verifier;
address immutable _target;

constructor(IGatewayVerifier verifier, address target) {
_verifier = verifier;
_target = target;
}

function getProgram(uint256 id) external view returns (string memory) {
GatewayRequest memory req = GatewayFetcher.newRequest(1);
req.setTarget(_target);
req.push(id);

// Program bytecode breakdown:
// 0x00 = PUSH_0 (push 0 for slot)
// 0x46 = SET_SLOT
// 0x48 = FOLLOW
// 0x3d = READ_BYTES (read name from slot 0)
// 0x28 = PUSH_BYTES, 0x0104 = parameters (push 4-byte string)
// 0x20697320 = " is " string
// 0x5b = CONCAT (name + " is ")
// 0x01 = PUSH_1 (push 1)
// 0x47 = ADD_SLOT (slot becomes 1)
// 0x3d = READ_BYTES (read age from slot 1)
// 0x5b = CONCAT (name + " is " + age)
// 0x00 = PUSH_0 (push 0 for output)
// 0x33 = SET_OUTPUT
bytes memory program = hex"0046483d280104206973205b0101473d5b0033";

// Use evalLoop(0, 1) instead of eval() to pick up the `id` value from the stack
req.push(program).evalLoop(0, 1);
fetch(_verifier, req, this.getCallback.selector);
}

function getCallback(
bytes[] memory values,
uint8 /*exitCode*/,
bytes memory /*carry*/
) external pure returns (string memory) {
return string(values[0]);
}
}
18 changes: 18 additions & 0 deletions test/examples/program/People.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

contract People {

struct Record {
string name;
string age;
}

mapping(uint256 id => Record) records;

constructor() {
records[1] = Record("Alice", "25");
records[2] = Record("Bob", "30");
records[3] = Record("Christopher Alexander Johnson-Williams", "42");
}
}
49 changes: 49 additions & 0 deletions test/examples/program/demo.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { serve } from '@namestone/ezccip/serve';
import { Foundry } from '@adraffy/blocksmith';
import { EthSelfRollup } from '../../../src/eth/EthSelfRollup.js';
import { Gateway } from '../../../src/gateway.js';
import { describe } from '../../bun-describe-fix.js';
import { afterAll, expect, test } from 'bun:test';
import { LATEST_BLOCK_TAG } from '../../../src/utils.js';

describe('local program', async () => {
const foundry = await Foundry.launch({
infoLog: false,
});
afterAll(foundry.shutdown);
const rollup = new EthSelfRollup(foundry.provider);
rollup.latestBlockTag = LATEST_BLOCK_TAG;
const gateway = new Gateway(rollup);
const ccip = await serve(gateway, { protocol: 'raw', log: false });
afterAll(ccip.shutdown);

// setup verifier
const GatewayVM = await foundry.deploy({ file: 'GatewayVM' });
const hooks = await foundry.deploy({ file: 'EthVerifierHooks' });
const verifier = await foundry.deploy({
file: 'SelfVerifier',
args: [[ccip.endpoint], rollup.defaultWindow, hooks],
libs: { GatewayVM },
});

// setup backend contract (L2) - data is set in constructor
const People = await foundry.deploy({ file: 'People' });

// setup frontend contract (L1)
const GetPeople = await foundry.deploy({
file: 'GetPeople',
args: [verifier, People],
});

test('get name and age (program version)', async () => {
expect(await GetPeople.getProgram(1, { enableCcipRead: true })).toEqual('Alice is 25');
});

test('get name and age (program version - Bob)', async () => {
expect(await GetPeople.getProgram(2, { enableCcipRead: true })).toEqual('Bob is 30');
});

test('get name and age (program version - long name)', async () => {
expect(await GetPeople.getProgram(3, { enableCcipRead: true })).toEqual('Christopher Alexander Johnson-Williams is 42');
});
});
Loading