Integration (Typescript)
Interacting with the Oracle contract directly is a common use case, one of the possible methods to interact with this contract is illustrated below.
The following examples leverage Viem
, a Typescript library similar to ethers.js
that simplifies the process of interacting with the Oracle contract.
Attention: Follow the examples carefully. It is recommended that you first test and deploy your code on Testnet before using Pricing Sylo on Mainnet.
Initial configuration
The account used will need sufficient balance to deposit in SYLOs and pay the associated gas fees.
All values used in these examples are for Porcini, The Root Network testnet.
import { createWalletClient, createPublicClient, http } from 'viem';
import { rootPorcini } from 'viem/chains';
const account = privateKeyToAccount("0x123abc");
const syloTokenAddress = "0xCCcCCcCC00000C64000000000000000000000000";
const oracleAddress = "0xf459E82138096876C25cd5fbc54c487476640619";
const publicClient = createPublicClient({
chain: rootPorcini,
transport: http("https://porcini.rootnet.app"),
});
const walletClient = createWalletClient({
account,
chain: rootPorcini,
transport: http("https://porcini.rootnet.app"),
});
export default { walletClient, publicClient, syloTokenAddress, oracleAddress };
Typical User Flow
Step 1: Deposit SYLO tokens to the Oracle.
async function depositTokens() {
// First approve the Oracle to spend your SYLO tokens
const approvalHash = await walletClient.writeContract({
address: syloTokenAddress,
abi: ERC20_ABI,
functionName: "approve",
account,
args: [oracleAddress, parseUnits("100", 18)], // 100 SYLO tokens
});
// Wait for approval transaction to be mined
await publicClient.waitForTransactionReceipt({ hash: approvalHash });
// Deposit SYLO to the Oracle contract
const depositHash = await walletClient.writeContract({
address: oracleAddress,
abi: ORACLE_ABI,
functionName: "deposit",
account,
args: [parseUnits("100", 18), account.address],
});
// Wait for deposit transaction to be mined
return await publicClient.waitForTransactionReceipt({ hash: depositHash });
}
Step 2: Create a price data request for a token.
async function requestTokenPrice(tokenId: string) {
const hash = await walletClient.writeContract({
address: oracleAddress,
abi: ORACLE_ABI,
functionName: "createRequest",
account,
args: [tokenId],
});
// Wait for createRequest transaction to be mined
await publicClient.waitForTransactionReceipt({ hash });
const requestId = (await publicClient.readContract({
address: oracleAddress,
abi: ORACLE_ABI,
functionName: "requestId",
})) as string;
return requestId;
}
Below is a table of asset IDs for the Oracle contract on Porcini. These asset IDs are used to identify what token to retrieve price data for.
Asset Id | Token |
---|---|
1 | ROOT |
2 | XRP |
3172 | SYLO |
17508 | ASTO |
1124 | ETH |
2148 | USDC |
8292 | WBTC |
Step 3: Get the response data once itβs available.
async function getResponseData(requestId: string) {
</strong> // Check if request is processed
const isProcessed = await publicClient.readContract({
address: oracleAddress,
abi: ORACLE_ABI,
functionName: "isProcessed",
args: [requestId],
});
if (!isProcessed) {
console.log("Request not yet processed, try again later");
return null;
}
// Get response data
const response = (await publicClient.readContract({
address: oracleAddress,
abi: ORACLE_ABI,
functionName: "getResponse",
args: [requestId],
})) as { value: bigint; timestamp: string };
console.log(`Token price: ${formatUnits(response.value, 18)}`);
console.log(`Timestamp: ${new Date(Number(response.timestamp) * 1000)}`);
return response;
}
Complete Workflow
async function priceRequestWorkflow(tokenId: string) {
// Step 1
await depositTokens();
// Step 2
const requestId = await requestTokenPrice(tokenId);
console.log(`Request created with ID: ${requestId}`);
// Step 3
if (requestId) {
// Wait for daemon to emit responded event and get response data
console.log("waiting for responded event ...");
publicClient.watchEvent({
address: oracleAddress,
event: parseAbiItem("event Responded(uint256 indexed requestId)"),
onLogs: async (logs) => {
const requestId = logs[0].args.requestId;
if (requestId) {
await getResponseData(requestId.toString());
}
},
});
}
}
priceRequestWorkflow("1"); // Asset Id for ROOT
It is useful to note that retrieving the requestId
can be done in a few different ways. In this particular example, the Responded
event indicates that the Daemon has processed the request and that the token data is ready to be read.
Oracle ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "_responder",
"type": "address"
},
{
"internalType": "uint32[]",
"name": "_tokens",
"type": "uint32[]"
},
{
"internalType": "contract IERC20",
"name": "_syloToken",
"type": "address"
},
{
"internalType": "address",
"name": "_initialManager",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "AccessControlBadConfirmation",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "bytes32",
"name": "neededRole",
"type": "bytes32"
}
],
"name": "AccessControlUnauthorizedAccount",
"type": "error"
},
{
"inputs": [],
"name": "AlreadyFulfilled",
"type": "error"
},
{
"inputs": [],
"name": "InsufficientBalance",
"type": "error"
},
{
"inputs": [],
"name": "InvalidValue",
"type": "error"
},
{
"inputs": [],
"name": "NotAllowedToken",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"indexed": true,
"internalType": "address",
"name": "recipient",
"type": "address"
}
],
"name": "AdminWithdrawal",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "Deposited",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "requestId",
"type": "uint256"
},
{
"indexed": true,
"internalType": "string",
"name": "token",
"type": "string"
}
],
"name": "Requested",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "requestId",
"type": "uint256"
}
],
"name": "Responded",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "previousAdminRole",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "newAdminRole",
"type": "bytes32"
}
],
"name": "RoleAdminChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "RoleGranted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "RoleRevoked",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "string",
"name": "token",
"type": "string"
},
{
"indexed": false,
"internalType": "bool",
"name": "state",
"type": "bool"
}
],
"name": "TokenUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [],
"name": "UpdatedAmountPerRequest",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
}
],
"name": "WithdrawalForUser",
"type": "event"
},
{
"inputs": [],
"name": "DEFAULT_ADMIN_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MANAGER_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "RESPONDER_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint32",
"name": "_token",
"type": "uint32"
}
],
"name": "createRequest",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint32[]",
"name": "_tokens",
"type": "uint32[]"
}
],
"name": "createRequests",
"outputs": [
{
"internalType": "uint256[]",
"name": "",
"type": "uint256[]"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_value",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_requestId",
"type": "uint256"
}
],
"name": "createResponse",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
},
{
"internalType": "address",
"name": "_sender",
"type": "address"
}
],
"name": "deposit",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
},
{
"internalType": "address",
"name": "_recipient",
"type": "address"
}
],
"name": "depositForUser",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "deposits",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint32[]",
"name": "_tokens",
"type": "uint32[]"
}
],
"name": "getLatestData",
"outputs": [
{
"components": [
{
"internalType": "uint256",
"name": "timestamp",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "requestId",
"type": "uint256"
}
],
"internalType": "struct Oracle.Response[]",
"name": "",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bool",
"name": "_breakOnProcessed",
"type": "bool"
}
],
"name": "getPendingRequests",
"outputs": [
{
"internalType": "uint256[]",
"name": "",
"type": "uint256[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_address",
"type": "address"
}
],
"name": "getRemainingRequests",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_requestId",
"type": "uint256"
}
],
"name": "getResponse",
"outputs": [
{
"components": [
{
"internalType": "uint256",
"name": "timestamp",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "requestId",
"type": "uint256"
}
],
"internalType": "struct Oracle.Response",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
}
],
"name": "getRoleAdmin",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "grantRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "hasRole",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_requestId",
"type": "uint256"
}
],
"name": "isProcessed",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "pricePerRequest",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "callerConfirmation",
"type": "address"
}
],
"name": "renounceRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "requestId",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "requests",
"outputs": [
{
"internalType": "uint32",
"name": "tokenId",
"type": "uint32"
},
{
"internalType": "uint256",
"name": "timestamp",
"type": "uint256"
},
{
"internalType": "bool",
"name": "processed",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "responses",
"outputs": [
{
"internalType": "uint256",
"name": "timestamp",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "requestId",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "revokeRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "interfaceId",
"type": "bytes4"
}
],
"name": "supportsInterface",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "syloToken",
"outputs": [
{
"internalType": "contract IERC20",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "tokenData",
"outputs": [
{
"internalType": "uint256",
"name": "timestamp",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "requestId",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint32",
"name": "",
"type": "uint32"
}
],
"name": "tokenNames",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint32",
"name": "",
"type": "uint32"
}
],
"name": "tokens",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
}
],
"name": "updateAmountPerRequest",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint32",
"name": "_token",
"type": "uint32"
},
{
"internalType": "string",
"name": "_name",
"type": "string"
},
{
"internalType": "bool",
"name": "_state",
"type": "bool"
}
],
"name": "updateToken",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
},
{
"internalType": "address",
"name": "_from",
"type": "address"
},
{
"internalType": "address",
"name": "_recipient",
"type": "address"
}
],
"name": "withdrawForUser",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
},
{
"internalType": "address",
"name": "_recipient",
"type": "address"
}
],
"name": "withdrawFunds",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "withdrawable",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]
Was this page helpful?