dria-oracle-sdk
Version:
An on-chain LLM Oracle SDK for Dria
1,186 lines (1,178 loc) • 32.9 kB
JavaScript
'use strict';
var viem = require('viem');
var Irys = require('@irys/sdk');
var TaskStatus = /* @__PURE__ */ ((TaskStatus2) => {
TaskStatus2[TaskStatus2["None"] = 0] = "None";
TaskStatus2[TaskStatus2["PendingGeneration"] = 1] = "PendingGeneration";
TaskStatus2[TaskStatus2["PendingValidation"] = 2] = "PendingValidation";
TaskStatus2[TaskStatus2["Completed"] = 3] = "Completed";
return TaskStatus2;
})(TaskStatus || {});
async function stringToContractBytesWithStorage(input, storage) {
const inputBytes = viem.stringToBytes(input);
if (storage && inputBytes.length > storage.bytesLimit) {
const key = await storage.put(Buffer.from(inputBytes));
return `0x${Buffer.from(JSON.stringify(key)).toString("hex")}`;
} else {
return `0x${Buffer.from(inputBytes).toString("hex")}`;
}
}
async function contractBytesToStringWithStorage(input, storage) {
const inputStr = viem.bytesToString(Buffer.from(input.slice(2), "hex"));
if (storage) {
const key = storage.isKey(inputStr);
if (key == null) {
return inputStr;
}
const data = await storage.get(key);
if (data == null) {
return null;
}
return data.toString();
} else {
return inputStr;
}
}
function stringToBytes32(input) {
return viem.toHex(input, { size: 32 });
}
function bytes32ToString(input) {
return viem.fromHex(input, { size: 32, to: "string" });
}
var coordinatorAbi = [
{ type: "constructor", inputs: [], stateMutability: "nonpayable" },
{
type: "function",
name: "UPGRADE_INTERFACE_VERSION",
inputs: [],
outputs: [{ name: "", type: "string", internalType: "string" }],
stateMutability: "view"
},
{
type: "function",
name: "feeToken",
inputs: [],
outputs: [{ name: "", type: "address", internalType: "contract ERC20" }],
stateMutability: "view"
},
{
type: "function",
name: "generationDeviationFactor",
inputs: [],
outputs: [{ name: "", type: "uint64", internalType: "uint64" }],
stateMutability: "view"
},
{
type: "function",
name: "generationFee",
inputs: [],
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
stateMutability: "view"
},
{
type: "function",
name: "getBestResponse",
inputs: [{ name: "taskId", type: "uint256", internalType: "uint256" }],
outputs: [
{
name: "",
type: "tuple",
internalType: "struct LLMOracleTask.TaskResponse",
components: [
{
name: "responder",
type: "address",
internalType: "address"
},
{ name: "nonce", type: "uint256", internalType: "uint256" },
{ name: "score", type: "uint256", internalType: "uint256" },
{ name: "output", type: "bytes", internalType: "bytes" },
{ name: "metadata", type: "bytes", internalType: "bytes" }
]
}
],
stateMutability: "view"
},
{
type: "function",
name: "getFee",
inputs: [
{
name: "parameters",
type: "tuple",
internalType: "struct LLMOracleTaskParameters",
components: [
{ name: "difficulty", type: "uint8", internalType: "uint8" },
{
name: "numGenerations",
type: "uint40",
internalType: "uint40"
},
{
name: "numValidations",
type: "uint40",
internalType: "uint40"
}
]
}
],
outputs: [
{ name: "totalFee", type: "uint256", internalType: "uint256" },
{
name: "generatorFee",
type: "uint256",
internalType: "uint256"
},
{ name: "validatorFee", type: "uint256", internalType: "uint256" }
],
stateMutability: "view"
},
{
type: "function",
name: "getResponses",
inputs: [{ name: "taskId", type: "uint256", internalType: "uint256" }],
outputs: [
{
name: "",
type: "tuple[]",
internalType: "struct LLMOracleTask.TaskResponse[]",
components: [
{
name: "responder",
type: "address",
internalType: "address"
},
{ name: "nonce", type: "uint256", internalType: "uint256" },
{ name: "score", type: "uint256", internalType: "uint256" },
{ name: "output", type: "bytes", internalType: "bytes" },
{ name: "metadata", type: "bytes", internalType: "bytes" }
]
}
],
stateMutability: "view"
},
{
type: "function",
name: "getValidations",
inputs: [{ name: "taskId", type: "uint256", internalType: "uint256" }],
outputs: [
{
name: "",
type: "tuple[]",
internalType: "struct LLMOracleTask.TaskValidation[]",
components: [
{
name: "validator",
type: "address",
internalType: "address"
},
{ name: "nonce", type: "uint256", internalType: "uint256" },
{
name: "scores",
type: "uint256[]",
internalType: "uint256[]"
},
{ name: "metadata", type: "bytes", internalType: "bytes" }
]
}
],
stateMutability: "view"
},
{
type: "function",
name: "initialize",
inputs: [
{
name: "_oracleRegistry",
type: "address",
internalType: "address"
},
{ name: "_feeToken", type: "address", internalType: "address" },
{
name: "_platformFee",
type: "uint256",
internalType: "uint256"
},
{
name: "_generationFee",
type: "uint256",
internalType: "uint256"
},
{
name: "_validationFee",
type: "uint256",
internalType: "uint256"
},
{ name: "_minScore", type: "uint256", internalType: "uint256" },
{ name: "_maxScore", type: "uint256", internalType: "uint256" }
],
outputs: [],
stateMutability: "nonpayable"
},
{
type: "function",
name: "maxScore",
inputs: [],
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
stateMutability: "view"
},
{
type: "function",
name: "minScore",
inputs: [],
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
stateMutability: "view"
},
{
type: "function",
name: "nextTaskId",
inputs: [],
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
stateMutability: "view"
},
{
type: "function",
name: "owner",
inputs: [],
outputs: [{ name: "", type: "address", internalType: "address" }],
stateMutability: "view"
},
{
type: "function",
name: "platformFee",
inputs: [],
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
stateMutability: "view"
},
{
type: "function",
name: "platformFeeBalance",
inputs: [],
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
stateMutability: "view"
},
{
type: "function",
name: "proxiableUUID",
inputs: [],
outputs: [{ name: "", type: "bytes32", internalType: "bytes32" }],
stateMutability: "view"
},
{
type: "function",
name: "registry",
inputs: [],
outputs: [
{
name: "",
type: "address",
internalType: "contract LLMOracleRegistry"
}
],
stateMutability: "view"
},
{
type: "function",
name: "renounceOwnership",
inputs: [],
outputs: [],
stateMutability: "nonpayable"
},
{
type: "function",
name: "request",
inputs: [
{ name: "protocol", type: "bytes32", internalType: "bytes32" },
{ name: "input", type: "bytes", internalType: "bytes" },
{ name: "models", type: "bytes", internalType: "bytes" },
{
name: "parameters",
type: "tuple",
internalType: "struct LLMOracleTaskParameters",
components: [
{ name: "difficulty", type: "uint8", internalType: "uint8" },
{
name: "numGenerations",
type: "uint40",
internalType: "uint40"
},
{
name: "numValidations",
type: "uint40",
internalType: "uint40"
}
]
}
],
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
stateMutability: "nonpayable"
},
{
type: "function",
name: "requests",
inputs: [{ name: "taskId", type: "uint256", internalType: "uint256" }],
outputs: [
{ name: "requester", type: "address", internalType: "address" },
{ name: "protocol", type: "bytes32", internalType: "bytes32" },
{
name: "parameters",
type: "tuple",
internalType: "struct LLMOracleTaskParameters",
components: [
{ name: "difficulty", type: "uint8", internalType: "uint8" },
{
name: "numGenerations",
type: "uint40",
internalType: "uint40"
},
{
name: "numValidations",
type: "uint40",
internalType: "uint40"
}
]
},
{
name: "status",
type: "uint8",
internalType: "enum LLMOracleTask.TaskStatus"
},
{
name: "generatorFee",
type: "uint256",
internalType: "uint256"
},
{
name: "validatorFee",
type: "uint256",
internalType: "uint256"
},
{ name: "platformFee", type: "uint256", internalType: "uint256" },
{ name: "input", type: "bytes", internalType: "bytes" },
{ name: "models", type: "bytes", internalType: "bytes" }
],
stateMutability: "view"
},
{
type: "function",
name: "respond",
inputs: [
{ name: "taskId", type: "uint256", internalType: "uint256" },
{ name: "nonce", type: "uint256", internalType: "uint256" },
{ name: "output", type: "bytes", internalType: "bytes" },
{ name: "metadata", type: "bytes", internalType: "bytes" }
],
outputs: [],
stateMutability: "nonpayable"
},
{
type: "function",
name: "responses",
inputs: [
{ name: "taskId", type: "uint256", internalType: "uint256" },
{ name: "", type: "uint256", internalType: "uint256" }
],
outputs: [
{ name: "responder", type: "address", internalType: "address" },
{ name: "nonce", type: "uint256", internalType: "uint256" },
{ name: "score", type: "uint256", internalType: "uint256" },
{ name: "output", type: "bytes", internalType: "bytes" },
{ name: "metadata", type: "bytes", internalType: "bytes" }
],
stateMutability: "view"
},
{
type: "function",
name: "setFees",
inputs: [
{
name: "_platformFee",
type: "uint256",
internalType: "uint256"
},
{
name: "_generationFee",
type: "uint256",
internalType: "uint256"
},
{
name: "_validationFee",
type: "uint256",
internalType: "uint256"
}
],
outputs: [],
stateMutability: "nonpayable"
},
{
type: "function",
name: "setGenerationDeviationFactor",
inputs: [
{
name: "_generationDeviationFactor",
type: "uint64",
internalType: "uint64"
}
],
outputs: [],
stateMutability: "nonpayable"
},
{
type: "function",
name: "setParameters",
inputs: [
{
name: "minimums",
type: "tuple",
internalType: "struct LLMOracleTaskParameters",
components: [
{ name: "difficulty", type: "uint8", internalType: "uint8" },
{
name: "numGenerations",
type: "uint40",
internalType: "uint40"
},
{
name: "numValidations",
type: "uint40",
internalType: "uint40"
}
]
},
{
name: "maximums",
type: "tuple",
internalType: "struct LLMOracleTaskParameters",
components: [
{ name: "difficulty", type: "uint8", internalType: "uint8" },
{
name: "numGenerations",
type: "uint40",
internalType: "uint40"
},
{
name: "numValidations",
type: "uint40",
internalType: "uint40"
}
]
}
],
outputs: [],
stateMutability: "nonpayable"
},
{
type: "function",
name: "transferOwnership",
inputs: [{ name: "newOwner", type: "address", internalType: "address" }],
outputs: [],
stateMutability: "nonpayable"
},
{
type: "function",
name: "upgradeToAndCall",
inputs: [
{
name: "newImplementation",
type: "address",
internalType: "address"
},
{ name: "data", type: "bytes", internalType: "bytes" }
],
outputs: [],
stateMutability: "payable"
},
{
type: "function",
name: "validate",
inputs: [
{ name: "taskId", type: "uint256", internalType: "uint256" },
{ name: "nonce", type: "uint256", internalType: "uint256" },
{ name: "scores", type: "uint256[]", internalType: "uint256[]" },
{ name: "metadata", type: "bytes", internalType: "bytes" }
],
outputs: [],
stateMutability: "nonpayable"
},
{
type: "function",
name: "validationFee",
inputs: [],
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
stateMutability: "view"
},
{
type: "function",
name: "validations",
inputs: [
{ name: "taskId", type: "uint256", internalType: "uint256" },
{ name: "", type: "uint256", internalType: "uint256" }
],
outputs: [
{ name: "validator", type: "address", internalType: "address" },
{ name: "nonce", type: "uint256", internalType: "uint256" },
{ name: "metadata", type: "bytes", internalType: "bytes" }
],
stateMutability: "view"
},
{
type: "function",
name: "withdrawPlatformFees",
inputs: [],
outputs: [],
stateMutability: "nonpayable"
},
{
type: "event",
name: "Initialized",
inputs: [
{
name: "version",
type: "uint64",
indexed: false,
internalType: "uint64"
}
],
anonymous: false
},
{
type: "event",
name: "OwnershipTransferred",
inputs: [
{
name: "previousOwner",
type: "address",
indexed: true,
internalType: "address"
},
{
name: "newOwner",
type: "address",
indexed: true,
internalType: "address"
}
],
anonymous: false
},
{
type: "event",
name: "Request",
inputs: [
{
name: "taskId",
type: "uint256",
indexed: true,
internalType: "uint256"
},
{
name: "requester",
type: "address",
indexed: true,
internalType: "address"
},
{
name: "protocol",
type: "bytes32",
indexed: true,
internalType: "bytes32"
}
],
anonymous: false
},
{
type: "event",
name: "Response",
inputs: [
{
name: "taskId",
type: "uint256",
indexed: true,
internalType: "uint256"
},
{
name: "responder",
type: "address",
indexed: true,
internalType: "address"
}
],
anonymous: false
},
{
type: "event",
name: "StatusUpdate",
inputs: [
{
name: "taskId",
type: "uint256",
indexed: true,
internalType: "uint256"
},
{
name: "protocol",
type: "bytes32",
indexed: true,
internalType: "bytes32"
},
{
name: "statusBefore",
type: "uint8",
indexed: false,
internalType: "enum LLMOracleTask.TaskStatus"
},
{
name: "statusAfter",
type: "uint8",
indexed: false,
internalType: "enum LLMOracleTask.TaskStatus"
}
],
anonymous: false
},
{
type: "event",
name: "Upgraded",
inputs: [
{
name: "implementation",
type: "address",
indexed: true,
internalType: "address"
}
],
anonymous: false
},
{
type: "event",
name: "Validation",
inputs: [
{
name: "taskId",
type: "uint256",
indexed: true,
internalType: "uint256"
},
{
name: "validator",
type: "address",
indexed: true,
internalType: "address"
}
],
anonymous: false
},
{
type: "error",
name: "AddressEmptyCode",
inputs: [{ name: "target", type: "address", internalType: "address" }]
},
{
type: "error",
name: "AlreadyResponded",
inputs: [
{ name: "taskId", type: "uint256", internalType: "uint256" },
{ name: "oracle", type: "address", internalType: "address" }
]
},
{ type: "error", name: "ComputeError", inputs: [] },
{
type: "error",
name: "ERC1967InvalidImplementation",
inputs: [
{
name: "implementation",
type: "address",
internalType: "address"
}
]
},
{ type: "error", name: "ERC1967NonPayable", inputs: [] },
{ type: "error", name: "FailedCall", inputs: [] },
{
type: "error",
name: "InsufficientFees",
inputs: [
{ name: "have", type: "uint256", internalType: "uint256" },
{ name: "want", type: "uint256", internalType: "uint256" }
]
},
{ type: "error", name: "InvalidInitialization", inputs: [] },
{ type: "error", name: "InvalidInput", inputs: [] },
{
type: "error",
name: "InvalidNonce",
inputs: [
{ name: "taskId", type: "uint256", internalType: "uint256" },
{ name: "nonce", type: "uint256", internalType: "uint256" }
]
},
{
type: "error",
name: "InvalidParameterRange",
inputs: [
{ name: "have", type: "uint256", internalType: "uint256" },
{ name: "min", type: "uint256", internalType: "uint256" },
{ name: "max", type: "uint256", internalType: "uint256" }
]
},
{
type: "error",
name: "InvalidTaskStatus",
inputs: [
{ name: "taskId", type: "uint256", internalType: "uint256" },
{
name: "have",
type: "uint8",
internalType: "enum LLMOracleTask.TaskStatus"
},
{
name: "want",
type: "uint8",
internalType: "enum LLMOracleTask.TaskStatus"
}
]
},
{
type: "error",
name: "InvalidValidation",
inputs: [
{ name: "taskId", type: "uint256", internalType: "uint256" },
{ name: "validator", type: "address", internalType: "address" }
]
},
{ type: "error", name: "NotInitializing", inputs: [] },
{
type: "error",
name: "NotRegistered",
inputs: [{ name: "oracle", type: "address", internalType: "address" }]
},
{
type: "error",
name: "NotWhitelisted",
inputs: [{ name: "validator", type: "address", internalType: "address" }]
},
{
type: "error",
name: "OwnableInvalidOwner",
inputs: [{ name: "owner", type: "address", internalType: "address" }]
},
{
type: "error",
name: "OwnableUnauthorizedAccount",
inputs: [{ name: "account", type: "address", internalType: "address" }]
},
{ type: "error", name: "UUPSUnauthorizedCallContext", inputs: [] },
{
type: "error",
name: "UUPSUnsupportedProxiableUUID",
inputs: [{ name: "slot", type: "bytes32", internalType: "bytes32" }]
}
];
class Oracle {
constructor(client, storage) {
this.client = client;
this.storage = storage;
// defaults
this.taskParameters = { difficulty: 2, numGenerations: 2, numValidations: 2 };
this.protocol = "dria-oracle-sdk/0.0.x";
}
/**
* Initialize the oracle client by setting up contract instances.
* @param coordinatorAddress coordinator contract address
* @returns initialized oracle client
*/
async init(coordinatorAddress) {
this.coordinator = this.Coordinator(coordinatorAddress);
const tokenAddr = await this.coordinator.read.feeToken();
this.token = this.Token(tokenAddr);
return this;
}
/**
* Change the underlying default task parameters.
* @param opts new default task parameters
*/
withParameters(opts) {
this.taskParameters = {
...this.taskParameters,
...opts
};
return this;
}
/**
* Change the underlying default protocol.
*
* The protocol is a string that should fit a `bytes32` type in Solidity. It is used
* to identify the source of the request, and can be used within event filters.
*
* It should have to format `name/version`, e.g. `dria-oracle-sdk/0.x.x`.
* @param protocol protocol name
*/
withProtocol(protocol) {
if (protocol.split("/").length !== 2) {
throw new Error("Invalid protocol format.");
}
if (Buffer.from(protocol).length > 32) {
throw new Error("Protocol string is too long.");
}
this.protocol = protocol;
return this;
}
/** Returns a new instance of the LLM coordinator contract.
* @warning This is an internal method, and making it `private` will break
* the type export due to the size of ABI-inferred types.
*/
Coordinator(address) {
return viem.getContract({
address,
abi: coordinatorAbi,
client: this.client
});
}
/** Returns a new instance of an ERC20 token contract.
* @warning This is an internal method, and making it `private` will break
* the type export due to the size of ABI-inferred types.
*/
Token(address) {
return viem.getContract({
address,
abi: viem.erc20Abi,
client: this.client
});
}
async request(input, models = "*", opts = {}) {
if (this.coordinator === void 0) {
throw new Error("SDK not initialized.");
}
const taskParameters = { ...this.taskParameters, ...opts.taskParameters };
if (taskParameters.numGenerations === 0) {
throw new Error("Number of generations cant be 0.");
}
const modelsString = Array.isArray(models) ? models.join(",") : models;
if (typeof input !== "string") {
if (!await this.isCompleted(input.history_id)) {
throw new Error("Chat history task is not completed.");
}
input = JSON.stringify(input);
}
const inputBytes = await stringToContractBytesWithStorage(input, this.storage);
const modelBytes = await stringToContractBytesWithStorage(modelsString, void 0);
const protocol = opts.protocol ?? this.protocol;
const protocolBytes = stringToBytes32(protocol);
const txHash = await this.coordinator.write.request([protocolBytes, inputBytes, modelBytes, taskParameters], {
chain: this.client.wallet.chain,
account: this.client.wallet.account
});
return { txHash, protocol, input, models, taskParameters };
}
/**
* Waits until the request transaction is mined and returns the task id.
* @param txHash transaction hash for the request (see `request`)
* @returns taskId
*/
async waitRequest(txHash) {
const receipt = await this.client.public.waitForTransactionReceipt({ hash: txHash });
const logs = viem.parseEventLogs({
abi: viem.parseAbi(["event Request(uint256 indexed taskId, address indexed requester, bytes32 indexed protocol)"]),
logs: receipt.logs,
eventName: "Request"
});
if (logs.length === 0) {
throw new Error(`Request event not found in logs: ${JSON.stringify(logs)}`);
}
const taskId = logs[0].args.taskId;
return taskId;
}
/**
* Alias for `getBestResponse` followed by `processResponse`.
* @param taskId task id
* @param kind task kind, e.g. `chat` for conversational models
* @returns processed task response
*/
async read(taskId) {
const response = await this.getBestResponse(taskId);
return this.processResponse(response);
}
/**
* Returns a boolean indicating if the task is completed.
* @param taskId task id
* @returns true if the task is completed, or `taskId` is 0
*/
async isCompleted(taskId) {
if (BigInt(taskId) === 0n) {
return true;
}
if (this.coordinator === void 0) {
throw new Error("SDK not initialized.");
}
const requestRaw = await this.coordinator.read.requests([BigInt(taskId)]);
return requestRaw[3] === TaskStatus.Completed;
}
/**
* Returns the task request for a given task id.
* @param taskId task id
* @returns task request
*/
async getRequest(taskId) {
if (this.coordinator === void 0) {
throw new Error("SDK not initialized.");
}
const request = await this.coordinator.read.requests([BigInt(taskId)]);
return {
requester: request[0],
protocol: bytes32ToString(request[1]),
parameters: request[2],
status: request[3],
generatorFee: request[4],
validatorFee: request[5],
platformFee: request[6],
input: await contractBytesToStringWithStorage(request[7], this.storage) ?? "",
models: bytes32ToString(request[8])
};
}
/**
* Returns the highest scored response of a task.
* Will throw an error if the task is not completed yet!
* @param taskId task id
* @returns task response with the highest score
*/
async getBestResponse(taskId) {
if (this.coordinator === void 0) {
throw new Error("SDK not initialized.");
}
return await this.coordinator.read.getBestResponse([BigInt(taskId)]);
}
/**
* Returns the validations of all generation responses for a task.
* @param taskId task id
* @returns array of task validations
*/
async getValidations(taskId) {
if (this.coordinator === void 0) {
throw new Error("SDK not initialized.");
}
return this.coordinator.read.getValidations([BigInt(taskId)]);
}
/**
* Returns the generation responses for a task.
* @param taskId task id
* @returns array of task responses
*/
async getResponses(taskId) {
if (this.coordinator === void 0) {
throw new Error("SDK not initialized.");
}
return await this.coordinator.read.getResponses([BigInt(taskId)]);
}
/**
* Process the `output` and `metadata` of a task, with respect to the given storage.
* @param response existing response object
* @returns response object with processed `output` and `metadata`
*/
async processResponse(response) {
const output = await contractBytesToStringWithStorage(response.output, this.storage);
const metadata = await contractBytesToStringWithStorage(response.metadata, this.storage);
return {
...response,
output,
metadata
};
}
/**
* Process the `metadata` of a task, with respect to the given storage.
* @param response existing validation object
* @returns validation object with processed `metadata`
*/
async processValidation(validation) {
const metadata = await contractBytesToStringWithStorage(validation.metadata, this.storage);
if (!metadata) {
throw new Error("Validation metadata not found.");
}
try {
return {
...validation,
// here we assume the type like this, because validators are trusted
metadata: JSON.parse(metadata)
};
} catch (err) {
console.error("Error parsing metadata:", err);
throw err;
}
}
/** Shorthand to parse a string input to a chat history response. */
toChatHistory(input) {
return JSON.parse(input);
}
/**
* Fetches the task events from the coordinator contract and returns its args.
* A returned task event has the taskId, protocol, statusBefore, and statusAfter.
* For a completed task, we are looking for the statusAfter to be `Completed` which is `3`.
*
* @param opts options for fetching tasks
* - `protocol`: protocol name
* - `from`: block to start from
* - `to`: block to end at
* - `status`: task status to filter by
* @returns array of task events
*/
async getTaskEvents(opts) {
if (this.coordinator === void 0) {
throw new Error("SDK not initialized.");
}
const protocol = opts.protocol ? stringToBytes32(opts.protocol) : void 0;
const fromBlock = opts.from ?? "earliest";
const toBlock = opts.to ?? "latest";
const events = await this.coordinator.getEvents.StatusUpdate({ protocol }, { fromBlock, toBlock });
const taskEvents = events.map((event) => event.args);
if (opts.status) {
return taskEvents.filter((e) => e.statusAfter === opts.status);
} else {
return taskEvents;
}
}
/**
* Waits for a task to be completed, i.e. it should have all the required
* generations and validations be done.
* @param taskId task id
*/
async wait(taskId) {
if (this.coordinator === void 0) {
throw new Error("SDK not initialized.");
}
if (await this.isCompleted(taskId)) {
return;
}
return new Promise((resolve, reject) => {
const unwatch = this.coordinator.watchEvent.StatusUpdate(
{
taskId: BigInt(taskId),
protocol: void 0
},
{
onLogs: (logs) => {
const status = logs[0].args.statusAfter;
if (status === TaskStatus.Completed) {
unwatch();
resolve();
}
}
// onError: (err) => reject(err), // TODO: should we handle any stuff here?
}
);
});
}
/** Returns the allowance of the client for the coordinator.
* @returns allowance amount
*/
async allowance() {
if (this.token === void 0) {
throw new Error("SDK not initialized.");
}
return this.token.read.allowance([this.client.wallet.account.address, this.coordinator.address]);
}
/**
* Approves the coordinator to spend the client's tokens.
* @param amount amount to approve, defaults to max uint256 (infinite)
* @returns transaction hash
*/
async approve(amount) {
if (this.token === void 0) {
throw new Error("SDK not initialized.");
}
amount = amount ?? viem.maxUint256;
return this.token.write.approve([this.coordinator.address, amount], {
chain: this.client.wallet.chain,
account: this.client.wallet.account
});
}
}
class ArweaveStorage {
constructor() {
/** Byte threshold, beyond which data is uploaded to Arweave. */
this.bytesLimit = Number.MAX_SAFE_INTEGER;
/** Base URL of the gateway. */
this.baseUrl = "https://gateway.irys.xyz";
}
/**
* Initializes the Arweave storage with the given key.
* @param key Arweave wallet object.
* @param bytesLimit Number of bytes such that smaller data are not uploaded, default is 1024 bytes.
*/
init(key, bytesLimit = 1024) {
const network = "mainnet";
const token = "arweave";
this.irys = new Irys({
network,
// "mainnet" or "devnet"
token,
// Token used for payment and signing
key
// Arweave wallet
});
this.bytesLimit = bytesLimit;
}
/** Return an `ArweaveKey` object if `key` is a stringified object of the form `{ arweave: string }`.
*
* @example // a valid key
* { arweave: "Zg6CZYfxXCWYnCuKEpnZCYfy7ghit1_v4-BCe53iWuA" }
*/
isKey(key) {
try {
const obj = JSON.parse(key);
if (obj.arweave && typeof obj.arweave === "string") {
return { arweave: obj.arweave };
}
} catch {
}
return null;
}
async get(key) {
const url = `${this.baseUrl}/${key.arweave}`;
const res = await fetch(url);
if (!res.ok) {
if (res.status === 404) {
return null;
} else {
throw new Error(`Failed to fetch data: ${await res.text()}`);
}
} else {
return Buffer.from(await res.arrayBuffer());
}
}
/**
* Uploads the given value to Arweave and returns the key.
*
* _Requires `init` to have been called._
*
* @param value Value to upload.
* @returns Key to access the value.
*/
async put(value) {
if (!this.irys) {
throw new Error("Arweave client not initialized");
}
const receipt = await this.irys.upload(value);
return { arweave: receipt.id };
}
/**
* Returns the balance of the Arweave wallet.
*
* _Requires `init` to have been called._
*
* @returns Balance in `bigint`.
*/
async balance() {
if (!this.irys) {
throw new Error("Arweave client not initialized");
}
const balance = await this.irys.getBalance(this.irys.address);
return BigInt(`0x${balance.toString(16)}`);
}
describe() {
return "Arweave";
}
}
exports.ArweaveStorage = ArweaveStorage;
exports.Oracle = Oracle;
exports.TaskStatus = TaskStatus;
exports.contractBytesToStringWithStorage = contractBytesToStringWithStorage;
exports.stringToContractBytesWithStorage = stringToContractBytesWithStorage;