From a80fb0f1e0fe1bc380f30c89ca80cb8d9f1e45b4 Mon Sep 17 00:00:00 2001 From: Arpit Singh Bhatia <84636859+The-x-35@users.noreply.github.com> Date: Thu, 26 Dec 2024 14:05:40 +0530 Subject: [PATCH 1/2] rebase final --- src/agent/index.ts | 5 ++ src/langchain/index.ts | 47 ++++++++++++ src/tools/index.ts | 2 + src/tools/rock_paper_scissor.ts | 126 ++++++++++++++++++++++++++++++++ 4 files changed, 180 insertions(+) create mode 100644 src/tools/rock_paper_scissor.ts diff --git a/src/agent/index.ts b/src/agent/index.ts index 56f66f4..6cfbfb2 100644 --- a/src/agent/index.ts +++ b/src/agent/index.ts @@ -35,6 +35,7 @@ import { getOwnedAllDomains, resolveAllDomains, create_gibwork_task, + rock_paper_scissor, } from "../tools"; import { CollectionDeployment, @@ -337,4 +338,8 @@ export class SolanaAgentKit { payer ? new PublicKey(payer) : undefined, ); } + + async rockPaperScissors(amount: number, choice: "rock" | "paper" | "scissors") { + return rock_paper_scissor(this, amount, choice); + } } diff --git a/src/langchain/index.ts b/src/langchain/index.ts index f28b000..11413a4 100644 --- a/src/langchain/index.ts +++ b/src/langchain/index.ts @@ -1229,6 +1229,52 @@ export class SolanaCreateGibworkTask extends Tool { } } +export class SolanaRockPaperScissorsTool extends Tool { + name = "rock_paper_scissors_blink"; + description = `Play rock paper scissors to win the SEND coin. + Inputs(convert the input to a json string): + choice: string, either "rock", "paper", or "scissors" (required) + amount: number, amount of SOL to play the game with, either 0.1, 0.01, or 0.005 SOL (required)`; + + constructor(private solanaKit: SolanaAgentKit) { + super(); + } + + private validateInput(input: any): void { + if (input.choice !== undefined) { + throw new Error('choice is required.'); + } + if ( + input.amount !== undefined && + (typeof input.spaceKB !== "number" || input.spaceKB <= 0) + ) { + throw new Error("amount must be a positive number when provided"); + } + } + + protected async _call(input: string): Promise { + try { + const parsedInput = toJSON(input); + this.validateInput(parsedInput); + const result = await this.solanaKit.rockPaperScissors( + Number(parsedInput['"amount"']), + parsedInput['"choice"'].replace(/^"|"$/g, '') as "rock" | "paper" | "scissors" + ); + + return JSON.stringify({ + status: "success", + message: result, + }); + } catch (error: any) { + return JSON.stringify({ + status: "error", + message: error.message, + code: error.code || "UNKNOWN_ERROR", + }); + } + } +} + export function createSolanaTools(solanaKit: SolanaAgentKit) { return [ new SolanaBalanceTool(solanaKit), @@ -1263,5 +1309,6 @@ export function createSolanaTools(solanaKit: SolanaAgentKit) { new SolanaGetMainDomain(solanaKit), new SolanaResolveAllDomainsTool(solanaKit), new SolanaCreateGibworkTask(solanaKit), + new SolanaRockPaperScissorsTool(solanaKit), ]; } diff --git a/src/tools/index.ts b/src/tools/index.ts index 9a18cf4..10e9ff7 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -37,3 +37,5 @@ export * from "./openbook_create_market"; export * from "./pyth_fetch_price"; export * from "./create_gibwork_task"; + +export * from "./rock_paper_scissor"; \ No newline at end of file diff --git a/src/tools/rock_paper_scissor.ts b/src/tools/rock_paper_scissor.ts new file mode 100644 index 0000000..b5f1c0a --- /dev/null +++ b/src/tools/rock_paper_scissor.ts @@ -0,0 +1,126 @@ +import { sendAndConfirmTransaction, Transaction } from "@solana/web3.js"; +import { SolanaAgentKit } from "../agent"; + +export async function rock_paper_scissor( + agent: SolanaAgentKit, + amount: number, + choice: "rock" | "paper" | "scissors", +) { + try { + const res = await fetch( + `https://rps.sendarcade.fun/api/actions/bot?amount=${amount}&choice=${choice}`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + account: agent.wallet.publicKey.toBase58(), + }), + }, + ); + + const data = await res.json(); + if (data.transaction) { + const txn = Transaction.from(Buffer.from(data.transaction, "base64")); + txn.sign(agent.wallet); + txn.recentBlockhash = ( + await agent.connection.getLatestBlockhash() + ).blockhash; + const sig = await sendAndConfirmTransaction( + agent.connection, + txn, + [agent.wallet], + { commitment: 'confirmed' } + ); + let href = data.links?.next?.href; + return await outcome(agent, sig, href); + } else { + return "failed"; + } + } catch (error: any) { + console.error(error); + throw new Error(`RPS game failed: ${error.message}`); + } +} +async function outcome(agent: SolanaAgentKit, sig: string, href: string): Promise { + try { + const res = await fetch( + "https://rps.sendarcade.fun" + href, // href = /api/actions/outcome?id=... + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + account: agent.wallet.publicKey.toBase58(), + signature: sig, + }), + }, + ); + + const data: any = await res.json(); + const title = data.title; + if (title.startsWith("You lost")) { + return title; + } + let next_href = data.links?.actions?.[0]?.href; + return title + "\n" + await won(agent, next_href) + } catch (error: any) { + console.error(error); + throw new Error(`RPS outcome failed: ${error.message}`); + } +} +async function won(agent: SolanaAgentKit, href: string): Promise { + try { + const res = await fetch( + "https://rps.sendarcade.fun" + href, // href = /api/actions/won?id=... + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + account: agent.wallet.publicKey.toBase58(), + }), + }, + ); + + const data: any = await res.json(); + if (data.transaction) { + const txn = Transaction.from(Buffer.from(data.transaction, "base64")); + txn.partialSign(agent.wallet); + await agent.connection.sendRawTransaction(txn.serialize(),{ preflightCommitment: 'confirmed' }); } + else { + return "Failed to claim prize."; + } + let next_href = data.links?.next?.href; + return await postWin(agent, next_href); + } catch (error: any) { + console.error(error); + throw new Error(`RPS outcome failed: ${error.message}`); + } +} +async function postWin(agent: SolanaAgentKit, href: string): Promise { + try { + const res = await fetch( + "https://rps.sendarcade.fun" + href, // href = /api/actions/postwin?id=... + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + account: agent.wallet.publicKey.toBase58(), + }), + }, + ); + + const data: any = await res.json(); + const title = data.title; + return "Prize claimed Successfully" + "\n" + title; + } catch (error: any) { + console.error(error); + throw new Error(`RPS outcome failed: ${error.message}`); + } +} \ No newline at end of file From 6f687187e6d12771c7c83d003b589071bd56f3ad Mon Sep 17 00:00:00 2001 From: aryan Date: Sat, 28 Dec 2024 00:54:50 +0530 Subject: [PATCH 2/2] fix: lint --- src/agent/index.ts | 5 +- src/langchain/index.ts | 18 ++- src/tools/index.ts | 2 +- src/tools/rock_paper_scissor.ts | 224 ++++++++++++++++---------------- 4 files changed, 131 insertions(+), 118 deletions(-) diff --git a/src/agent/index.ts b/src/agent/index.ts index 6cfbfb2..f930e40 100644 --- a/src/agent/index.ts +++ b/src/agent/index.ts @@ -339,7 +339,10 @@ export class SolanaAgentKit { ); } - async rockPaperScissors(amount: number, choice: "rock" | "paper" | "scissors") { + async rockPaperScissors( + amount: number, + choice: "rock" | "paper" | "scissors", + ) { return rock_paper_scissor(this, amount, choice); } } diff --git a/src/langchain/index.ts b/src/langchain/index.ts index 11413a4..dfefd57 100644 --- a/src/langchain/index.ts +++ b/src/langchain/index.ts @@ -1230,11 +1230,12 @@ export class SolanaCreateGibworkTask extends Tool { } export class SolanaRockPaperScissorsTool extends Tool { - name = "rock_paper_scissors_blink"; - description = `Play rock paper scissors to win the SEND coin. - Inputs(convert the input to a json string): + name = "rock_paper_scissors"; + description = `Play rock paper scissors to win SEND coins. + + Inputs (input is a JSON string): choice: string, either "rock", "paper", or "scissors" (required) - amount: number, amount of SOL to play the game with, either 0.1, 0.01, or 0.005 SOL (required)`; + amount: number, amount of SOL to play with - must be 0.1, 0.01, or 0.005 SOL (required)`; constructor(private solanaKit: SolanaAgentKit) { super(); @@ -1242,7 +1243,7 @@ export class SolanaRockPaperScissorsTool extends Tool { private validateInput(input: any): void { if (input.choice !== undefined) { - throw new Error('choice is required.'); + throw new Error("choice is required."); } if ( input.amount !== undefined && @@ -1258,9 +1259,12 @@ export class SolanaRockPaperScissorsTool extends Tool { this.validateInput(parsedInput); const result = await this.solanaKit.rockPaperScissors( Number(parsedInput['"amount"']), - parsedInput['"choice"'].replace(/^"|"$/g, '') as "rock" | "paper" | "scissors" + parsedInput['"choice"'].replace(/^"|"$/g, "") as + | "rock" + | "paper" + | "scissors", ); - + return JSON.stringify({ status: "success", message: result, diff --git a/src/tools/index.ts b/src/tools/index.ts index 10e9ff7..48662af 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -38,4 +38,4 @@ export * from "./pyth_fetch_price"; export * from "./create_gibwork_task"; -export * from "./rock_paper_scissor"; \ No newline at end of file +export * from "./rock_paper_scissor"; diff --git a/src/tools/rock_paper_scissor.ts b/src/tools/rock_paper_scissor.ts index b5f1c0a..8a0603e 100644 --- a/src/tools/rock_paper_scissor.ts +++ b/src/tools/rock_paper_scissor.ts @@ -2,125 +2,131 @@ import { sendAndConfirmTransaction, Transaction } from "@solana/web3.js"; import { SolanaAgentKit } from "../agent"; export async function rock_paper_scissor( - agent: SolanaAgentKit, - amount: number, - choice: "rock" | "paper" | "scissors", + agent: SolanaAgentKit, + amount: number, + choice: "rock" | "paper" | "scissors", ) { - try { - const res = await fetch( - `https://rps.sendarcade.fun/api/actions/bot?amount=${amount}&choice=${choice}`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - account: agent.wallet.publicKey.toBase58(), - }), - }, - ); + try { + const res = await fetch( + `https://rps.sendarcade.fun/api/actions/bot?amount=${amount}&choice=${choice}`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + account: agent.wallet.publicKey.toBase58(), + }), + }, + ); - const data = await res.json(); - if (data.transaction) { - const txn = Transaction.from(Buffer.from(data.transaction, "base64")); - txn.sign(agent.wallet); - txn.recentBlockhash = ( - await agent.connection.getLatestBlockhash() - ).blockhash; - const sig = await sendAndConfirmTransaction( - agent.connection, - txn, - [agent.wallet], - { commitment: 'confirmed' } - ); - let href = data.links?.next?.href; - return await outcome(agent, sig, href); - } else { - return "failed"; - } - } catch (error: any) { - console.error(error); - throw new Error(`RPS game failed: ${error.message}`); + const data = await res.json(); + if (data.transaction) { + const txn = Transaction.from(Buffer.from(data.transaction, "base64")); + txn.sign(agent.wallet); + txn.recentBlockhash = ( + await agent.connection.getLatestBlockhash() + ).blockhash; + const sig = await sendAndConfirmTransaction( + agent.connection, + txn, + [agent.wallet], + { commitment: "confirmed" }, + ); + const href = data.links?.next?.href; + return await outcome(agent, sig, href); + } else { + return "failed"; } + } catch (error: any) { + console.error(error); + throw new Error(`RPS game failed: ${error.message}`); + } } -async function outcome(agent: SolanaAgentKit, sig: string, href: string): Promise { - try { - const res = await fetch( - "https://rps.sendarcade.fun" + href, // href = /api/actions/outcome?id=... - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - account: agent.wallet.publicKey.toBase58(), - signature: sig, - }), - }, - ); +async function outcome( + agent: SolanaAgentKit, + sig: string, + href: string, +): Promise { + try { + const res = await fetch( + "https://rps.sendarcade.fun" + href, // href = /api/actions/outcome?id=... + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + account: agent.wallet.publicKey.toBase58(), + signature: sig, + }), + }, + ); - const data: any = await res.json(); - const title = data.title; - if (title.startsWith("You lost")) { - return title; - } - let next_href = data.links?.actions?.[0]?.href; - return title + "\n" + await won(agent, next_href) - } catch (error: any) { - console.error(error); - throw new Error(`RPS outcome failed: ${error.message}`); + const data: any = await res.json(); + const title = data.title; + if (title.startsWith("You lost")) { + return title; } + const next_href = data.links?.actions?.[0]?.href; + return title + "\n" + (await won(agent, next_href)); + } catch (error: any) { + console.error(error); + throw new Error(`RPS outcome failed: ${error.message}`); + } } async function won(agent: SolanaAgentKit, href: string): Promise { - try { - const res = await fetch( - "https://rps.sendarcade.fun" + href, // href = /api/actions/won?id=... - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - account: agent.wallet.publicKey.toBase58(), - }), - }, - ); + try { + const res = await fetch( + "https://rps.sendarcade.fun" + href, // href = /api/actions/won?id=... + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + account: agent.wallet.publicKey.toBase58(), + }), + }, + ); - const data: any = await res.json(); - if (data.transaction) { - const txn = Transaction.from(Buffer.from(data.transaction, "base64")); - txn.partialSign(agent.wallet); - await agent.connection.sendRawTransaction(txn.serialize(),{ preflightCommitment: 'confirmed' }); } - else { - return "Failed to claim prize."; - } - let next_href = data.links?.next?.href; - return await postWin(agent, next_href); - } catch (error: any) { - console.error(error); - throw new Error(`RPS outcome failed: ${error.message}`); + const data: any = await res.json(); + if (data.transaction) { + const txn = Transaction.from(Buffer.from(data.transaction, "base64")); + txn.partialSign(agent.wallet); + await agent.connection.sendRawTransaction(txn.serialize(), { + preflightCommitment: "confirmed", + }); + } else { + return "Failed to claim prize."; } + const next_href = data.links?.next?.href; + return await postWin(agent, next_href); + } catch (error: any) { + console.error(error); + throw new Error(`RPS outcome failed: ${error.message}`); + } } async function postWin(agent: SolanaAgentKit, href: string): Promise { - try { - const res = await fetch( - "https://rps.sendarcade.fun" + href, // href = /api/actions/postwin?id=... - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - account: agent.wallet.publicKey.toBase58(), - }), - }, - ); + try { + const res = await fetch( + "https://rps.sendarcade.fun" + href, // href = /api/actions/postwin?id=... + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + account: agent.wallet.publicKey.toBase58(), + }), + }, + ); - const data: any = await res.json(); - const title = data.title; - return "Prize claimed Successfully" + "\n" + title; - } catch (error: any) { - console.error(error); - throw new Error(`RPS outcome failed: ${error.message}`); - } -} \ No newline at end of file + const data: any = await res.json(); + const title = data.title; + return "Prize claimed Successfully" + "\n" + title; + } catch (error: any) { + console.error(error); + throw new Error(`RPS outcome failed: ${error.message}`); + } +}