Skip to content

Commit

Permalink
Merge pull request #16 from usherlabs/feature/notify
Browse files Browse the repository at this point in the history
Feature/notify
  • Loading branch information
rsoury authored Jan 27, 2025
2 parents 5236c57 + ec721e0 commit cc56668
Show file tree
Hide file tree
Showing 14 changed files with 318 additions and 81 deletions.
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,42 @@ yarn dev
# or
pnpm dev
```


## Supported APIs on Testnet and Mainnet for Rooch Network

### Twitter/X API
- User Endpoint: `https://api.x.com/2/users/` and `https://api.x.com/2/tweets/`
```bash
# Example: Get user followers count
rooch move run --function 0x0d6144b074dd19a9ff581abd5bf7815a39222c8b3ac68ce5938c9d9723544e08::example_caller::request_data \
--sender-account default \
--args 'string:https://api.x.com/2/users/by/username/elonmusk?user.fields=public_metrics' \
--args 'string:GET' \
--args 'string:{}' \
--args 'string:{}' \
--args 'string:.data.public_metrics.followers_count' \
--args 'address:<orchestrator_address>' \
--args 'u256:50000000'
```

### OpenAI API
- Chat Completions: `https://api.openai.com/v1/chat/completions`
```bash
# Example: Simple GPT request
rooch move run --function 0x0d6144b074dd19a9ff581abd5bf7815a39222c8b3ac68ce5938c9d9723544e08::example_caller::request_data \
--sender-account default \
--args 'string:https://api.openai.com/v1/chat/completions' \
--args 'string:POST' \
--args 'string:{}' \
--args 'string:{
"model": "gpt-4",
"messages": [{"role": "user", "content": "Say this is a test!"}],
"temperature": 0.7
}' \
--args 'string:.choices[].message.content' \
--args 'address:<orchestrator_address>' \
--args 'u256:50000000'
```

Note: Replace `<oracle_address>` and `<orchestrator_address>` with your actual deployed addresses.
36 changes: 18 additions & 18 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,24 @@ services:
volumes:
- postgres-db-data:/var/lib/postgresql/data

orchestrator:
build:
dockerfile: ./orch.dockerfile
context: .
image: orchestrator:move
container_name: verity-move-orchestrator
environment:
DATABASE_URL: ${DATABASE_URL}
networks:
- verify-network
depends_on:
postgres_db:
condition: service_healthy
command: >
sh -c "
npx prisma migrate deploy &&
pnpm run start
"
# orchestrator:
# build:
# dockerfile: ./orch.dockerfile
# context: .
# image: orchestrator:move
# container_name: verity-move-orchestrator
# environment:
# DATABASE_URL: ${DATABASE_URL}
# networks:
# - verify-network
# depends_on:
# postgres_db:
# condition: service_healthy
# command: >
# sh -c "
# npx prisma migrate deploy &&
# pnpm run start
# "

volumes:
postgres-db-data:
Expand Down
23 changes: 16 additions & 7 deletions docs/ROOCH.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,14 @@ Navigate to the `rooch` directory, build the contracts for development, publish
```bash
cd rooch
rooch move build --dev
rooch move publish --named-addresses verity_test_foreign_module=default,verity=default
rooch move publish --named-addresses verity=default --sender default
cd ..
```

###### Note:
- A sender account is required for deployment and contract updates.
- The account with the upgrade_Cap object can update/upgrade the contract by setting the --sender flag to their account with the upgrade_Cap.

#### Step 4: Install Node Dependencies

Install the necessary Node.js dependencies using npm, yarn, or pnpm. Ensure you are in the root project directory.
Expand Down Expand Up @@ -99,19 +103,19 @@ Additional steps for managing supported orchestrator URL
- To add URL

```bash
rooch move run --function <oracle_address>::registry::add_supported_url --sender-account <orchestrator_address> --args 'string:https://api.x.com/2/users/' --args 'u256:400000' --args 'u64:0' --args 'u256:0' --args 'u256:0'
rooch move run --function 0x330895328871633518adee400b6b14d4475fa240965ce7923b50ba42b0ab50b9::registry::add_supported_url --sender-account 0x694cbe655b126e9e6a997e86aaab39e538abf30a8c78669ce23a98740b47b65d --args 'string:https://api.openai.com/v1/chat/completions' --args 'u256:50000' --args 'u64:40' --args 'u256:4000' --args 'u256:5000'
```

- to remove URLs

```bash
rooch move run --function <oracle_address>::registry::remove_supported_url --sender-account <orchestrator_address> --args 'string:api.twitter.com/2/users/'
rooch move run --function 0x330895328871633518adee400b6b14d4475fa240965ce7923b50ba42b0ab50b9::registry::remove_supported_url --sender-account <orchestrator_address> --args 'string:https://api.twitter.com/2/users/'
```

- To view supported URLS

```bash
rooch move view --function <oracle_address>::registry::get_supported_urls --args 'address:<orchestrator_address>'
rooch move view --function 0x330895328871633518adee400b6b14d4475fa240965ce7923b50ba42b0ab50b9::registry::get_supported_urls --args 'address:0x694cbe655b126e9e6a997e86aaab39e538abf30a8c78669ce23a98740b47b65d'
```


Expand All @@ -138,24 +142,29 @@ rooch move run --function <contractAddress>::example_caller::request_data --sen
Here's an example of requesting the Twitter Followers Count on a Local Rooch Node:

```bash
rooch move run --function 0x0d6144b074dd19a9ff581abd5bf7815a39222c8b3ac68ce5938c9d9723544e08::example_caller::request_data --sender-account default --args 'string:https://api.x.com/2/users/by/username/elonmusk?user.fields=public_metrics' --args 'string:GET' --args 'string:{}' --args 'string:{}' --args 'string:.data.public_metrics.followers_count' --args 'address:0x694cbe655b126e9e6a997e86aaab39e538abf30a8c78669ce23a98740b47b65d' --args 'u256:50000000'
rooch move run --function 0xf1290fb0e7e1de7e92e616209fb628970232e85c4c1a264858ff35092e1be231::example_caller::request_data --sender-account default --args 'string:https://api.x.com/2/users/by/username/elonmusk?user.fields=public_metrics' --args 'string:GET' --args 'string:{}' --args 'string:{}' --args 'string:.data.public_metrics.followers_count' --args 'address:0x694cbe655b126e9e6a997e86aaab39e538abf30a8c78669ce23a98740b47b65d' --args 'u256:50000'
```
or
```bash
rooch move run --function 0x0d6144b074dd19a9ff581abd5bf7815a39222c8b3ac68ce5938c9d9723544e08::example_caller::request_data --sender-account default --args 'string:https://api.openai.com/v1/chat/completions' --args 'string:POST' --args 'string:{}' --args 'string:{
rooch move run --function 0xf1290fb0e7e1de7e92e616209fb628970232e85c4c1a264858ff35092e1be231::example_caller::request_data --sender-account default --args 'string:https://api.openai.com/v1/chat/completions' --args 'string:POST' --args 'string:{}' --args 'string:{
"model": "gpt-4o-mini",
"messages": [{"role": "user", "content": "Say this is a test!"}],
"temperature": 0.7
}' --args 'string:.choices[].message.content' --args 'address:0x694cbe655b126e9e6a997e86aaab39e538abf30a8c78669ce23a98740b47b65d' --args 'u256:50000000'
```

To check the state of the response object on a local Rooch node, use the following command:

```bash
rooch state -a /object/0x7a01ddf194f8a1c19212d56f747294352bf2e5cf23e6e10e64937aa1955704b0
```


Additionally,
For notification calls you can allocated an portion form escrow for notification
```bash
rooch move run --function 0xf1290fb0e7e1de7e92e616209fb628970232e85c4c1a264858ff35092e1be231::oracles::update_notification_gas_allocation --sender-account default --args 'address:0x27e46e033da11c4d1f986081877e80cefb2b29dec1c559c97c3ccf12e910aba7' --args 'string:example_caller::receive_data' --args 'u256:90000'
```

#### Step 10: Manage Escrow balance

- To view balance
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
-- CreateTable
CREATE TABLE "Keeper" (
"id" TEXT NOT NULL,
"chain" TEXT NOT NULL DEFAULT 'ROOCH-testnet',
"module" TEXT NOT NULL,
"privateKey" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updateAt" TIMESTAMP(3) NOT NULL,

CONSTRAINT "Keeper_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE INDEX "Keeper_chain_module_idx" ON "Keeper"("chain", "module");
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
Warnings:
- A unique constraint covering the columns `[chain,module]` on the table `Keeper` will be added. If there are existing duplicate values, this will fail.
*/
-- DropIndex
DROP INDEX "Keeper_chain_module_idx";

-- CreateIndex
CREATE UNIQUE INDEX "Keeper_chain_module_key" ON "Keeper"("chain", "module");
13 changes: 13 additions & 0 deletions orchestrator/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,17 @@ model Events{
updateAt DateTime @updatedAt
@@index([eventHandleId, eventSeq,chain])
}

model Keeper{
id String @id @default(cuid())
chain String @default("ROOCH-testnet")
module String
privateKey String
createdAt DateTime @default(now())
updateAt DateTime @updatedAt
@@unique([chain, module])
}
42 changes: 34 additions & 8 deletions orchestrator/src/indexer/rooch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import env from "@/env";
import { instance as xTwitterInstance } from "@/integrations/xtwitter";
import { log } from "@/logger";
import type { IEvent, IRequestAdded, JsonRpcResponse, ProcessedRequestAdded, RoochNetwork } from "@/types";
import { decodeNotifyValue } from "@/util";
import { decodeNotifyValueFull } from "@/util";
import { Args, RoochClient, Secp256k1Keypair, Transaction, getRoochNodeUrl } from "@roochnetwork/rooch-sdk";
import axios from "axios";
import prismaClient from "../../prisma";
Expand Down Expand Up @@ -205,7 +205,7 @@ export default class RoochIndexer extends Indexer {
oracle: values.oracle,
pick: values.pick,
request_id: values.request_id,
notify: decodeNotifyValue(values.notify?.value?.vec?.at(0) ?? ""),
notify: decodeNotifyValueFull(values.notify?.value?.vec?.value?.at(0).at(0) ?? ""),
};
return data;
});
Expand Down Expand Up @@ -238,32 +238,58 @@ export default class RoochIndexer extends Indexer {
return null;
}

const keeper_key = await prismaClient.keeper.upsert({
where: {
chain_module: {
module: data.notify ?? "",
chain: this.chainId,
},
},
create: {
module: data.notify ?? "",
chain: this.chainId,
privateKey: Secp256k1Keypair.generate().getSecretKey(),
},
update: {},
});

const tx = new Transaction();
tx.callFunction({
target: `${this.oracleAddress}::oracles::fulfil_request`,
args: [Args.objectId(data.request_id), Args.u16(status), Args.string(result)],
args: [
Args.objectId(data.request_id),
Args.u16(status),
Args.string(result),
Args.address(Secp256k1Keypair.fromSecretKey(keeper_key.privateKey).getRoochAddress().toHexAddress()),
],
});

const receipt = await client.signAndExecuteTransaction({
transaction: tx,
signer: this.keyPair,
});

console.log({
keeper_key,
address: Secp256k1Keypair.fromSecretKey(keeper_key.privateKey).getRoochAddress().toHexAddress(),
target: data.notify ?? "",
oracleAddress: this.oracleAddress,
});
try {
if ((data.notify?.length ?? 0) > 66) {
const tx = new Transaction();
tx.callFunction({
target: data.notify ?? "",
maxGas: 10_000,
args: [],
});

const receipt = await client.signAndExecuteTransaction({
const notification_receipt = await client.signAndExecuteTransaction({
transaction: tx,
signer: this.keyPair,
signer: Secp256k1Keypair.fromSecretKey(keeper_key.privateKey),
});
log.info({ notification_receipt });
}
} catch (err) {
log.error(err);
log.error({ request_id: data.request_id, err: err });
}
return receipt;
}
Expand Down
1 change: 1 addition & 0 deletions orchestrator/src/integrations/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export abstract class BasicBearerAPIHandler {

const token = this.getAccessToken();
let request: AxiosResponse<any, any>;

if (isValidJson(data.params.headers) && isValidJson(data.params.body)) {
// TODO: Replace direct requests via axios with requests via VerityClient TS module
request = await axios({
Expand Down
3 changes: 2 additions & 1 deletion orchestrator/src/integrations/openAI.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import env from "@/env";
import { log } from "@/logger";
import Joi from "joi";
import { BasicBearerAPIHandler } from "./base";

Expand All @@ -19,8 +20,8 @@ export default class OpenAIIntegration extends BasicBearerAPIHandler {
const { error, value } = chatSchema.validate(JSON.parse(payload), {
allowUnknown: true,
});
console.log({ value, error });
if (error) {
log.error({ value, error });
return false;
} else {
if (value.model === "gpt-4o") {
Expand Down
2 changes: 1 addition & 1 deletion orchestrator/src/integrations/xtwitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default class TwitterIntegration extends BasicBearerAPIHandler {
}

export const instance = new TwitterIntegration(
env.integrations.openAIToken,
env.integrations.xBearerToken,
["api.x.com", "api.twitter.com"],
["/2/tweets", "/2/users/"],
60 * 1000,
Expand Down
2 changes: 1 addition & 1 deletion orchestrator/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ interface NotifyValue {
value: VecValue;
}
interface VecValue {
vec: string[];
vec: { value: Array<Array<string>> } | any;
}

export interface IRequestAdded {
Expand Down
4 changes: 4 additions & 0 deletions orchestrator/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ export function isValidJson(jsonString: string): boolean {
export function decodeNotifyValue(hex: string): string {
return `${hex.slice(0, 66)}${Buffer.from(hex.slice(66), "hex").toString()}`;
}

export function decodeNotifyValueFull(hex: string): string {
return `0x${Buffer.from(hex.slice(2, hex.length), "hex").toString()}`;
}
Loading

0 comments on commit cc56668

Please sign in to comment.