Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
zapaz committed Nov 4, 2024
2 parents 1e31352 + ed07188 commit 8e6f3ba
Show file tree
Hide file tree
Showing 153 changed files with 2,607 additions and 1,960 deletions.
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@
{
"filePath": "svelte5/src/lib/onchain-ai/components/Events.svelte",
"group": "Default"
},
{
"filePath": "svelte5/src/lib/onchain-ai",
"group": "Default"
},
{
"filePath": "svelte5/src/routes/+page.svelte",
"group": "Default"
}
]
}
16 changes: 8 additions & 8 deletions chainlink/package.json
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
{
"author": "",
"dependencies": {
"author": "Kredeum",
"description": "OnChainAI Chainlink package",
"devDependencies": {
"@chainlink/functions-toolkit": "^0.3.2",
"@types/prompt-sync": "^4.2.3",
"@typescript-eslint/eslint-plugin": "^8.11.0",
"@typescript-eslint/parser": "^8.11.0",
"eslint": "^9.13.0",
"@typescript-eslint/eslint-plugin": "^8.12.2",
"@typescript-eslint/parser": "^8.12.2",
"eslint": "^9.14.0",
"ethers": "^5.7.2",
"prettier": "^3.3.3",
"prompt-sync": "^4.2.0",
"ts-node": "^10.9.2",
"typescript-eslint": "^8.11.0",
"typescript-eslint": "^8.12.2",
"utf-8-validate": "^5.0.10"
},
"description": "",
"keywords": [],
"license": "ISC",
"main": "index.js",
"name": "@onchain-ai/chainlink",
"scripts": {
"check": "prettier --check . && eslint **/*.ts",
"clean": "rm -rf node_modules .turbo",
"format": "prettier --write --list-different .",
"check": "prettier --check . && eslint **/*.ts",
"secrets": "ts-node scripts/upload-secrets.ts"
},
"version": "1.0.0"
Expand Down
14 changes: 7 additions & 7 deletions common/package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"author": "",
"description": "",
"dependencies": {
"@types/node": "^22.8.1",
"author": "Kredeum",
"description": "OnChainAI Common package",
"devDependencies": {
"@types/node": "^22.8.7",
"eslint-plugin-json": "^4.0.1",
"ts-node": "^10.9.2",
"typescript": "^5.6.3"
Expand All @@ -12,10 +12,10 @@
"main": "index.js",
"name": "@onchain-ai/common",
"scripts": {
"clean": "rm -rf node_modules .turbo",
"format": "prettier --write --list-different .",
"build": "ts-node script/mergeAbis.ts",
"check": "prettier --check . && eslint **/*.ts",
"build": "ts-node script/mergeAbis.ts"
"clean": "rm -rf node_modules .turbo",
"format": "prettier --write --list-different ."
},
"version": "1.0.1"
}
1 change: 1 addition & 0 deletions common/turbo.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"extends": ["//"],
"tasks": {
"build": {
"dependsOn": ["@onchain-ai/foundry#deploy"],
"inputs": ["lib/**", "../chainlink/config.json", "../foundry/addresses.json"],
"outputLogs": "new-only"
}
Expand Down
6 changes: 3 additions & 3 deletions foundry/addresses.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"11155420": {
"Counter": "0x8354Ef7b78012151c276f51F8d19147FF8C47288",
"OnChainAI": "0xd1ca741de2d2975822ADf4646Cf0A8AE3Df51c78",
"OnChainAIv1": "0x432beBA9B2Fc71180FF9ba3fA93E1Ae88beDF402",
"OnChainAIv1": "0x879ae6BC9a6173A14111FE204ec0E14DCB619e9E",
"chainName": "optimism-sepolia"
},
"31337": {
Expand All @@ -13,13 +13,13 @@
},
"8453": {
"OnChainAI": "0xd798E6E526d7893e4F7aCED9F56DF69643bCf1B6",
"OnChainAIv1": "0x1F4666E268Ec7F1Fc46C467A8CdAF6b01f88B935",
"OnChainAIv1": "0x5095f726C40D0AE7360c6307B7cE57620ae8594c",
"chainName": "base"
},
"84532": {
"Counter": "0x1bC96A82609F23419065FCEf120E16E2A6Bd3981",
"OnChainAI": "0xCB60F4a4e578CDDBe89e4a27B2126f54BaeF3500",
"OnChainAIv1": "0xBf196B3732880a51Eaa6Cfc38d82De1A61582B06",
"OnChainAIv1": "0xc308300b222bf2C6B0C81D8C1a64909D0a32b5Ec",
"chainName": "base-sepolia"
}
}
30 changes: 14 additions & 16 deletions foundry/package.json
Original file line number Diff line number Diff line change
@@ -1,34 +1,32 @@
{
"author": "",
"description": "",
"dependencies": {
"eslint-plugin-json": "^4.0.1"
"author": "Kredeum",
"description": "OnChainAI Foundry package",
"devDependencies": {
"eslint-plugin-json": "^4.0.1",
"solhint": "^5.0.3"
},
"keywords": [],
"license": "ISC",
"main": "index.js",
"name": "@onchain-ai/foundry",
"scripts": {
"all": "pnpm run clean && pnpm run format && pnpm run check && pnpm run build && pnpm run test && pnpm run deploy:anvil",
"clean": "rm -rf node_modules .turbo out broadcast cache",
"format": "forge fmt",
"check": "pnpx solhint src/**/*.sol",
"build": "forge compile",
"chain": "./anvil.sh",
"check": "pnpx solhint src/**/*.sol",
"clean": "rm -rf node_modules .turbo out broadcast cache",
"deploy:all": "forge script script/DeployAll.s.sol",
"deploy:deploy": "pnpm deploy:all --fork-url $CHAIN --account $ACCOUNT --broadcast",
"deploy:validate": "pnpm deploy:all --fork-url $CHAIN",
"deploy:testnet": "ACCOUNT=testnet-deployer pnpm deploy:deploy --verify && pnpm run deploy:validate",
"deploy:mainnet": "ACCOUNT=mainnet-deployer pnpm deploy:deploy --verify && pnpm run deploy:validate",
"deploy:anvil": "export CHAIN=anvil ACCOUNT=anvil-deployer && pnpm run chain && pnpm deploy:deploy --password '' && pnpm run deploy:validate",
"deploy:base": "CHAIN=base pnpm deploy:mainnet",
"deploy:optimism": "CHAIN=optimism pnpm deploy:mainnet",
"deploy:base-sepolia": "CHAIN=base-sepolia pnpm deploy:testnet",
"deploy:deploy": "pnpm deploy:all --fork-url $CHAIN --account $ACCOUNT --broadcast",
"deploy:mainnet": "ACCOUNT=mainnet-deployer pnpm deploy:deploy --verify && pnpm run deploy:validate",
"deploy:optimism": "CHAIN=optimism pnpm deploy:mainnet",
"deploy:optimism-sepolia": "CHAIN=optimism-sepolia pnpm deploy:testnet",
"deploy:testnet": "ACCOUNT=testnet-deployer pnpm deploy:deploy --verify && pnpm run deploy:validate",
"deploy:validate": "pnpm deploy:all --fork-url $CHAIN",
"format": "forge fmt",
"test": "forge test"
},
"version": "1.0.2",
"devDependencies": {
"solhint": "^5.0.3"
}
"version": "1.0.2"
}
104 changes: 87 additions & 17 deletions foundry/src/OnChainAIv1.sol
Original file line number Diff line number Diff line change
@@ -1,43 +1,85 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {FunctionsRequest} from "@chainlink/functions/v1_0_0/libraries/FunctionsRequest.sol";
import {FunctionsClient} from "@chainlink/functions/v1_0_0/FunctionsClient.sol";
import {ConfirmedOwner} from "@chainlink/shared/access/ConfirmedOwner.sol";
import {FunctionsRequest} from "@chainlink/functions/v1_0_0/libraries/FunctionsRequest.sol";

/// @title OnChainAIv1 Contract
/// @notice A smart contract that interacts with Chainlink Functions to process AI requests on-chain.
/// @dev Inherits from FunctionsClient and ConfirmedOwner contracts.
contract OnChainAIv1 is FunctionsClient, ConfirmedOwner {
using FunctionsRequest for FunctionsRequest.Request;

/// @notice Error thrown when there are no valid secrets available.
error NoValidSecrets();

/// @notice Error thrown when the user prompt is empty.
error NoEmptyPrompt();

/// @notice Error thrown when the withdrawal fails.
/// @param receiver The address of the receiver.
/// @param balance The balance attempted to withdraw.
error WithdrawFailed(address receiver, uint256 balance);

/// @notice Error thrown when the payment amount is incorrect.
/// @param expected The expected payment amount.
/// @param actual The actual payment amount received.
error PaymentRequired(uint256 expected, uint256 actual);

/// @notice Error thrown when an unexpected fulfillRequest occurs.
/// @param expected The expected request ID.
/// @param response The response data.
/// @param err The error message.
error UnexpectedFullfillRequest(bytes32 expected, string response, string err);

/// @notice Emitted when the JavaScript code is updated.
/// @param javascript The new JavaScript code.
event JavascriptLog(string javascript);

/// @notice Emitted when the price is updated.
/// @param price The new price.
event PriceLog(uint256 indexed price);

/// @notice Emitted when an interaction occurs (request sent or response received).
/// @param requestId The request ID.
/// @param sender The address of the sender.
/// @param isResponse True if this log is for a response, false for a request.
/// @param prompt The user prompt.
/// @param response The response data.
event InteractionLog(
bytes32 indexed requestId, address indexed sender, bool indexed isResponse, string prompt, string response
);

/// @notice Struct representing an interaction (request and response).
struct Interaction {
bytes32 requestId;
address sender;
string prompt;
string response;
}

mapping(address => bytes32) internal _lastRequestId;
mapping(bytes32 => Interaction) public interactions;
/// @notice lastInteraction mapping of each sender.
mapping(address => Interaction) public lastInteraction;
/// @notice interaction mapping of each requestId.
mapping(bytes32 => Interaction) internal _interactionRequests;

bytes32 internal _donId;
uint32 internal _gasLimit;
string internal _javascript;
uint64 internal _subscriptionId;
uint64 internal _donHostedSecretsVersion;

/// @notice The price required to send a request.
uint256 public price;

/// @notice Constructor to initialize the OnChainAIv1 contract.
/// @param router The address of the Chainlink Functions Router contract.
/// @param javascript_ The JavaScript code to be executed by the Chainlink Function.
/// @param subscriptionId_ The subscription ID for billing purposes.
/// @param gasLimit_ The gas limit for the Chainlink Function request.
/// @param donId_ The DON ID used for routing the request.
/// @param price_ The price required to send a request.
constructor(
address router,
string memory javascript_,
Expand All @@ -53,36 +95,53 @@ contract OnChainAIv1 is FunctionsClient, ConfirmedOwner {
setPrice(price_);
}

function lastInteraction(address sender) external view returns (Interaction memory) {
return interactions[_lastRequestId[sender]];
}

/// @notice Sets the JavaScript code to be used in the Chainlink Function request.
/// @dev Only the contract owner can call this function.
/// @param javascript_ The JavaScript code as a string.
function setJavascript(string memory javascript_) public onlyOwner {
_javascript = javascript_;
emit JavascriptLog(javascript_);
}

/// @notice Sets the subscription ID for billing purposes.
/// @dev Only the contract owner can call this function.
/// @param subscriptionId_ The subscription ID.
function setSubscriptionId(uint64 subscriptionId_) public onlyOwner {
_subscriptionId = subscriptionId_;
}

/// @notice Sets the gas limit for the Chainlink Function request.
/// @dev Only the contract owner can call this function.
/// @param gasLimit_ The gas limit in units of gas.
function setGasLimit(uint32 gasLimit_) public onlyOwner {
_gasLimit = gasLimit_;
}

/// @notice Sets the DON ID used for routing the request.
/// @dev Only the contract owner can call this function.
/// @param donId_ The DON ID.
function setDonID(bytes32 donId_) public onlyOwner {
_donId = donId_;
}

/// @notice Sets the price required to send a request.
/// @dev Only the contract owner can call this function.
/// @param price_ The new price in wei.
function setPrice(uint256 price_) public onlyOwner {
price = price_;
emit PriceLog(price_);
}

/// @notice Sets the version of the DON-hosted secrets.
/// @dev Only the contract owner can call this function.
/// @param donHostedSecretsVersion_ The version number of the DON-hosted secrets.
function setDonHostedSecretsVersion(uint64 donHostedSecretsVersion_) public onlyOwner {
_donHostedSecretsVersion = donHostedSecretsVersion_;
}

/// @notice Sends a Chainlink Function request with the user's prompt.
/// @param userPrompt The user's prompt to be processed.
/// @return requestId The ID of the Chainlink Function request.
function sendRequest(string memory userPrompt) external payable returns (bytes32 requestId) {
require(_donHostedSecretsVersion > 0, NoValidSecrets());
require(bytes(userPrompt).length > 0, NoEmptyPrompt());
Expand All @@ -98,28 +157,39 @@ contract OnChainAIv1 is FunctionsClient, ConfirmedOwner {

requestId = _sendRequest(req.encodeCBOR(), _subscriptionId, _gasLimit, _donId);

delete( interactions[_lastRequestId[msg.sender]]);
_lastRequestId[msg.sender] = requestId;
interactions[requestId] = Interaction(requestId, msg.sender, userPrompt, "");
Interaction memory interactionRequest = Interaction(requestId, msg.sender, userPrompt, "");
_interactionRequests[requestId] = interactionRequest;
lastInteraction[msg.sender] = interactionRequest;

emit InteractionLog(requestId, msg.sender, false, userPrompt, "");
}

/// @notice Callback function invoked when the Chainlink Function request is fulfilled.
/// @dev Overrides the fulfillRequest function from FunctionsClient.
/// @param requestId The ID of the request being fulfilled.
/// @param response The response data from the Chainlink Function.
/// @param err Any error messages from the Chainlink Function.
function fulfillRequest(bytes32 requestId, bytes memory response, bytes memory err) internal override {
Interaction memory interaction = interactions[requestId];

require(interaction.requestId == requestId, UnexpectedFullfillRequest(requestId, string(response), string(err)));

// concat response or/and error
Interaction memory interactionResponse = _interactionRequests[requestId];
require(
(requestId != 0) && (requestId == interactionResponse.requestId),
UnexpectedFullfillRequest(requestId, string(response), string(err))
);
delete _interactionRequests[requestId];

/// @dev Concatenate response and/or error
string memory responseError = (err.length == 0)
? (response.length == 0) ? "Empty response" : string(response)
: string.concat("Error: ", string(err), " | ", string(response));

interactions[requestId].response = responseError;
interactionResponse.response = responseError;
lastInteraction[interactionResponse.sender] = interactionResponse;

emit InteractionLog(requestId, interaction.sender, true, interaction.prompt, responseError);
emit InteractionLog(requestId, interactionResponse.sender, true, interactionResponse.prompt, responseError);
}

/// @notice Withdraws the contract's balance to the owner's address.
/// @dev Only the contract owner can call this function.
function withdraw() external onlyOwner {
uint256 bal = address(this).balance;
(bool success,) = payable(msg.sender).call{value: bal}("");
Expand Down
10 changes: 10 additions & 0 deletions foundry/turbo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": ["//"],
"tasks": {
"dev": {
"dependsOn": ["@onchain-ai/foundry#deploy", "@onchain-ai/common#build"],
"inputs": ["src/**"],
"outputLogs": "new-only"
}
}
}
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "onchain-ai",
"version": "1.0.1",
"description": "",
"description": "OnChainAI - AI for smartcontracts",
"main": "index.js",
"scripts": {
"all": "pnpm run clean && pnpm install && pnpm run chain && pnpm run deploy && turbo start",
Expand All @@ -13,12 +13,12 @@
"keywords": [],
"author": "",
"license": "ISC",
"packageManager": "pnpm@9.12.0",
"packageManager": "pnpm@9.12.3",
"engines": {
"node": "^20",
"pnpm": "^9"
},
"dependencies": {
"devDependencies": {
"turbo": "^2.2.3"
}
}
Loading

0 comments on commit 8e6f3ba

Please sign in to comment.