Skip to main content

Naptha Agents with Oyster Serverless

Serverless function

const user = {
'public_key': '9a8cb98fa9a913ede98ccf4468b0262f80c3131eb6d4d9d1d478b9bb94ee48d80073fb8a2ce92d059a6ac797264cbbd54790849dd41b1e3d3f599654d8fe4ce9',
'id': 'user:9a8cb98fa9a913ede98ccf4468b0262f80c3131eb6d4d9d1d478b9bb94ee48d80073fb8a2ce92d059a6ac797264cbbd54790849dd41b1e3d3f599654d8fe4ce9'
}

const NODE_URL = "http://node.naptha.ai:7001";

addEventListener('fetch', event => {
event.respondWith(handle(event.request));
});

async function handle(request) {
try {
const data = await request.json();

const task_data = {
...data,
"consumer_id": user.id,
"worker_nodes": []
};

const response = await fetch(`${NODE_URL}/CreateTask`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(task_data)
});

if(!response.ok) {
throw new Error(`Error creating the task`);
}

const task_details = await response.json();

let final_response = "Error while checking task";

let task_completed = false;

while(!task_completed) {
const response = await fetch(`${NODE_URL}/CheckTask`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(task_details)
});

const task_status = await response.json();

if(task_status.status == "completed") {
final_response = JSON.stringify(task_status.results);
break;
}

if(task_status.status == "error") {
final_response = "Error while executing task";
break;
}

await sleep(3000);
}

return new Response(final_response);

} catch(err) {
console.log(err);
return new Response('Please provide a valid JSON input');
}
}

function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

Smart Contract

// SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

contract App {
using SafeERC20 for IERC20;

address public relayAddress;

/// @notice refers to USDC token
IERC20 public token;
bytes32 public codehash;

constructor(bytes32 _codehash, address _relayAddress, address _token) {
codehash = _codehash;
relayAddress = _relayAddress;
token = IERC20(_token);
token.approve(relayAddress, 100000000 ether);
}

event CalledBack(
uint256 indexed jobId,
address jobOwner,
bytes32 codehash,
bytes codeInputs,
bytes outputs,
uint8 errorCode
);

function relayJob(
bytes memory _codeInputs,
uint256 _userTimeout,
uint256 _maxGasPrice
) external payable returns (bool) {
(bool success, ) = relayAddress.call{value: msg.value}(
abi.encodeWithSignature(
"relayJob(uint8,bytes32,bytes,uint256,uint256,address,address,uint256)",
1, // _env
codehash,
_codeInputs,
_userTimeout,
_maxGasPrice,
msg.sender, // _refundAccount,
address(this), // callback contract
50000 // _callbackGasLimit
)
);
return success;
}

function oysterResultCall(
uint256 _jobId,
address _jobOwner,
bytes32 _codehash,
bytes calldata _codeInputs,
bytes calldata _output,
uint8 _errorCode
) public {
require(msg.sender == relayAddress, "Invalid caller");
emit CalledBack(_jobId, _jobOwner, _codehash, _codeInputs, _output, _errorCode);
}

receive() external payable {}
}

Deployment Script

import { ethers } from "hardhat";

async function main() {

let codeHash = "0x0000000000000000000000000000000000000000000000000000000000000000";
let relayAddress = "0xf3E2fFf7887D8CD53379cBd75d2F90bdd4799C02";
let usdcToken = "0x3F595cC7999648533B0B3ac3a71c08Ef3A206de0";
const app = await ethers.deployContract(
"App",
[
codeHash,
relayAddress,
usdcToken
]
);
await app.waitForDeployment();
console.log("App Contract is deployed at ", app.target);
}

main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});

Sample Inputs

Create a job by sending a transaction to call the relayJob method of the User contract with some Ether to pay for response tx (0.001 ETH should be sufficient) with the following arguments.

_codeInputs : 0x7b226d6f64756c655f6e616d65223a2268656c6c6f5f776f726c64222c226d6f64756c655f706172616d73223a7b22706172616d31223a224d61726c696e222c22706172616d32223a226e6170746861227d7d
_userTimeout : 299999
_maxGasPrice : 2000000000

_codeInputs are hex representation of the following json

{"module_name":"hello_world","module_params":{"param1":"Marlin","param2":"naptha"}}