From c565ed0f15952c6d96bc1dce49bd1621c5355719 Mon Sep 17 00:00:00 2001 From: Nico Arqueros <1622112+nicarq@users.noreply.github.com> Date: Thu, 22 Aug 2024 00:17:41 -0500 Subject: [PATCH] update to support actual mpc --- .../src/index.ts | 21 ++-- .../src/index.ts | 22 +++-- .../src/index.test.ts | 12 +-- .../src/index.ts | 20 +--- .../jest.config.ts | 7 ++ .../package.json | 4 + .../project.json | 30 ++++++ .../src/chrome-paths.d.ts | 3 + .../src/global.d.ts | 9 ++ .../src/index.test.ts | 7 ++ .../src/index.ts | 99 +++++++++++++++++++ .../tsconfig.app.json | 4 + .../tsconfig.json | 5 + .../tsconfig.spec.json | 15 +++ .../src/index.test.ts | 5 - .../src/index.ts | 91 ++++++++++++----- libs/shinkai-tools-runner/src/lib.test.rs | 8 +- 17 files changed, 275 insertions(+), 87 deletions(-) create mode 100644 apps/shinkai-tool-coinbase-get-transactions/jest.config.ts create mode 100644 apps/shinkai-tool-coinbase-get-transactions/package.json create mode 100644 apps/shinkai-tool-coinbase-get-transactions/project.json create mode 100644 apps/shinkai-tool-coinbase-get-transactions/src/chrome-paths.d.ts create mode 100644 apps/shinkai-tool-coinbase-get-transactions/src/global.d.ts create mode 100644 apps/shinkai-tool-coinbase-get-transactions/src/index.test.ts create mode 100644 apps/shinkai-tool-coinbase-get-transactions/src/index.ts create mode 100644 apps/shinkai-tool-coinbase-get-transactions/tsconfig.app.json create mode 100644 apps/shinkai-tool-coinbase-get-transactions/tsconfig.json create mode 100644 apps/shinkai-tool-coinbase-get-transactions/tsconfig.spec.json diff --git a/apps/shinkai-tool-coinbase-call-faucet/src/index.ts b/apps/shinkai-tool-coinbase-call-faucet/src/index.ts index cd3bf99..e3fbd3a 100644 --- a/apps/shinkai-tool-coinbase-call-faucet/src/index.ts +++ b/apps/shinkai-tool-coinbase-call-faucet/src/index.ts @@ -5,11 +5,9 @@ import { Coinbase, CoinbaseOptions } from '@coinbase/coinbase-sdk'; type Config = { name: string; privateKey: string; - walletId?: string; -}; -type Params = { - walletId?: string; + walletId: string; }; +type Params = {}; type Result = { data: string; }; @@ -32,9 +30,7 @@ export class Tool extends BaseTool { }, parameters: { type: 'object', - properties: { - walletId: { type: 'string', nullable: true }, - }, + properties: {}, required: [], }, result: { @@ -47,22 +43,17 @@ export class Tool extends BaseTool { }; async run(params: Params): Promise> { - // Coinbase wallet creation using constructor const coinbaseOptions: CoinbaseOptions = { apiKeyName: this.config.name, privateKey: this.config.privateKey, - useServerSigner: false, - debugging: false, - basePath: '', - maxNetworkRetries: 3, }; const coinbase = new Coinbase(coinbaseOptions); console.log(`Coinbase configured: `, coinbase); const user = await coinbase.getDefaultUser(); console.log(`User: `, user); - // Prioritize walletId from Params over Config - const walletId = params.walletId || this.config.walletId; + // Use walletId from Config only + const walletId = this.config.walletId; let wallet; if (walletId) { @@ -85,7 +76,7 @@ export class Tool extends BaseTool { return { data: { - data: `Faucet transaction completed successfully: ${faucetTransaction.toString()}`, + data: `Faucet transaction completed successfully: ${faucetTransaction.toString()} for wallet: ${wallet.getDefaultAddress()}`, }, }; } diff --git a/apps/shinkai-tool-coinbase-create-wallet/src/index.ts b/apps/shinkai-tool-coinbase-create-wallet/src/index.ts index 8c03d3b..5110d17 100644 --- a/apps/shinkai-tool-coinbase-create-wallet/src/index.ts +++ b/apps/shinkai-tool-coinbase-create-wallet/src/index.ts @@ -5,10 +5,13 @@ import { Coinbase, CoinbaseOptions } from '@coinbase/coinbase-sdk'; type Config = { name: string; privateKey: string; + useServerSigner?: boolean; }; type Params = {}; // Params type is now empty type Result = { walletId?: string; + seed?: string; + address?: string; }; export class Tool extends BaseTool { @@ -23,6 +26,7 @@ export class Tool extends BaseTool { properties: { name: { type: 'string' }, privateKey: { type: 'string' }, + useServerSigner: { type: 'boolean', default: false, nullable: true }, }, required: ['name', 'privateKey'], }, @@ -35,20 +39,18 @@ export class Tool extends BaseTool { type: 'object', properties: { walletId: { type: 'string', nullable: true }, + seed: { type: 'string', nullable: true }, + address: { type: 'string', nullable: true }, }, required: [], }, }; async run(params: Params): Promise> { - // Coinbase wallet creation using constructor const coinbaseOptions: CoinbaseOptions = { apiKeyName: this.config.name, privateKey: this.config.privateKey, - useServerSigner: false, - debugging: false, - basePath: '', - maxNetworkRetries: 3, + useServerSigner: this.config.useServerSigner ?? false, }; const coinbase = new Coinbase(coinbaseOptions); console.log(`Coinbase configured: `, coinbase); @@ -61,9 +63,17 @@ export class Tool extends BaseTool { }); console.log(`Wallet successfully created: `, wallet.toString()); + let exportedWallet; + if (!this.config.useServerSigner) { + exportedWallet = await wallet.export(); + } + + const address = await wallet.getDefaultAddress(); + return { data: { - walletId: wallet.getId(), + ...exportedWallet, + address: address?.getId(), }, }; } diff --git a/apps/shinkai-tool-coinbase-get-balance/src/index.test.ts b/apps/shinkai-tool-coinbase-get-balance/src/index.test.ts index ab8bf95..d65a954 100644 --- a/apps/shinkai-tool-coinbase-get-balance/src/index.test.ts +++ b/apps/shinkai-tool-coinbase-get-balance/src/index.test.ts @@ -1,13 +1,7 @@ import { Tool } from './index'; test('exists definition', async () => { -// const tool = new Tool({}); -// const definition = tool.getDefinition(); -// expect(definition).toBeInstanceOf(Object); + const tool = new Tool({ name: 'test', privateKey: 'test' }); + const definition = tool.getDefinition(); + expect(definition).toBeInstanceOf(Object); }); - -test('run definition', async () => { -// const tool = new Tool({}); -// const run_result = await tool.run({ walletId: '0d948159-3b3e-40f8-9001-741e64498fa9' }); -// console.log(run_result); -}, 25000); diff --git a/apps/shinkai-tool-coinbase-get-balance/src/index.ts b/apps/shinkai-tool-coinbase-get-balance/src/index.ts index 3f25c1a..7e7d4bc 100644 --- a/apps/shinkai-tool-coinbase-get-balance/src/index.ts +++ b/apps/shinkai-tool-coinbase-get-balance/src/index.ts @@ -18,7 +18,8 @@ export class Tool extends BaseTool { definition: ToolDefinition = { id: 'shinkai-tool-coinbase-get-balance', name: 'Shinkai: Coinbase Balance Getter', - description: 'Tool for getting the balance of a Coinbase wallet after restoring it', + description: + 'Tool for getting the balance of a Coinbase wallet after restoring it', author: 'Shinkai', keywords: ['coinbase', 'balance', 'shinkai'], configurations: { @@ -47,19 +48,12 @@ export class Tool extends BaseTool { }; async run(params: Params): Promise> { - // Coinbase wallet creation using constructor const coinbaseOptions: CoinbaseOptions = { apiKeyName: this.config.name, privateKey: this.config.privateKey, - useServerSigner: false, - debugging: false, - basePath: '', - maxNetworkRetries: 3, }; const coinbase = new Coinbase(coinbaseOptions); - console.log(`Coinbase configured: `, coinbase); const user = await coinbase.getDefaultUser(); - console.log(`User: `, user); // Prioritize walletId from Params over Config const walletId = params.walletId || this.config.walletId; @@ -81,16 +75,6 @@ export class Tool extends BaseTool { let balances = await wallet.listBalances(); console.log(`Balances: `, balances); - // If no balances, call the faucet and then list balances again - if (balances.size === 0) { - const faucetTransaction = await wallet.faucet(); - console.log(`Faucet transaction completed successfully: `, faucetTransaction.toString()); - - // Retrieve the list of balances again - balances = await wallet.listBalances(); - console.log(`Balances after faucet: `, balances); - } - return { data: { data: `Balances: ${balances.toString()}`, diff --git a/apps/shinkai-tool-coinbase-get-transactions/jest.config.ts b/apps/shinkai-tool-coinbase-get-transactions/jest.config.ts new file mode 100644 index 0000000..76978c7 --- /dev/null +++ b/apps/shinkai-tool-coinbase-get-transactions/jest.config.ts @@ -0,0 +1,7 @@ +/* eslint-disable */ +export default { + displayName: '@shinkai_protocol/shinkai-tool-coinbase-get-transactions', + preset: '../../jest.preset.js', + coverageDirectory: '../../coverage/apps/shinkai-tool-coinbase-get-transactions', + passWithNoTests: true, +}; diff --git a/apps/shinkai-tool-coinbase-get-transactions/package.json b/apps/shinkai-tool-coinbase-get-transactions/package.json new file mode 100644 index 0000000..b4950a4 --- /dev/null +++ b/apps/shinkai-tool-coinbase-get-transactions/package.json @@ -0,0 +1,4 @@ +{ + "name": "@shinkai_protocol/shinkai-tool-coinbase-get-transactions", + "type": "commonjs" +} diff --git a/apps/shinkai-tool-coinbase-get-transactions/project.json b/apps/shinkai-tool-coinbase-get-transactions/project.json new file mode 100644 index 0000000..fc099b6 --- /dev/null +++ b/apps/shinkai-tool-coinbase-get-transactions/project.json @@ -0,0 +1,30 @@ +{ + "name": "@shinkai_protocol/shinkai-tool-coinbase-get-transactions", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "apps/shinkai-tool-coinbase-get-transactions/src", + "projectType": "library", + "tags": ["tool"], + "targets": { + "build": { + "executor": "nx:run-commands", + "defaultConfiguration": "production", + "options": { + "command": "npx ts-node scripts/tool-bundler.ts --entry ./apps/shinkai-tool-coinbase-get-transactions/src/index.ts --outputFolder ./dist/apps/shinkai-tool-coinbase-get-transactions" + }, + "configurations": { + "development": {}, + "production": {} + } + }, + "lint": { + "executor": "@nx/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": [ + "apps/shinkai-tool-coinbase-get-transactions/**/*.ts", + "apps/shinkai-tool-coinbase-get-transactions/package.json" + ] + } + } + } +} diff --git a/apps/shinkai-tool-coinbase-get-transactions/src/chrome-paths.d.ts b/apps/shinkai-tool-coinbase-get-transactions/src/chrome-paths.d.ts new file mode 100644 index 0000000..9b369ed --- /dev/null +++ b/apps/shinkai-tool-coinbase-get-transactions/src/chrome-paths.d.ts @@ -0,0 +1,3 @@ +declare module 'chrome-paths' { + const chrome: string; +} diff --git a/apps/shinkai-tool-coinbase-get-transactions/src/global.d.ts b/apps/shinkai-tool-coinbase-get-transactions/src/global.d.ts new file mode 100644 index 0000000..af92505 --- /dev/null +++ b/apps/shinkai-tool-coinbase-get-transactions/src/global.d.ts @@ -0,0 +1,9 @@ +declare global { + interface Window { + viemClient: any; + viemAccount: any; + ethereum: any; + } +} + +export {}; diff --git a/apps/shinkai-tool-coinbase-get-transactions/src/index.test.ts b/apps/shinkai-tool-coinbase-get-transactions/src/index.test.ts new file mode 100644 index 0000000..bc5a47e --- /dev/null +++ b/apps/shinkai-tool-coinbase-get-transactions/src/index.test.ts @@ -0,0 +1,7 @@ +import { Tool } from './index'; + +test('exists definition', async () => { + // const tool = new Tool({ name: 'test', privateKey: 'test' }); + // const definition = tool.getDefinition(); + // expect(definition).toBeInstanceOf(Object); +}); diff --git a/apps/shinkai-tool-coinbase-get-transactions/src/index.ts b/apps/shinkai-tool-coinbase-get-transactions/src/index.ts new file mode 100644 index 0000000..76d3e61 --- /dev/null +++ b/apps/shinkai-tool-coinbase-get-transactions/src/index.ts @@ -0,0 +1,99 @@ +import { BaseTool, RunResult } from '@shinkai_protocol/shinkai-tools-builder'; +import { ToolDefinition } from 'libs/shinkai-tools-builder/src/tool-definition'; +import { Coinbase, CoinbaseOptions } from '@coinbase/coinbase-sdk'; + +type Config = { + name: string; + privateKey: string; + walletId: string; +}; +type Params = {}; +type Result = { tableCsv: string; rowsCount: number; columnsCount: number }; + +export class Tool extends BaseTool { + definition: ToolDefinition = { + id: 'shinkai-tool-coinbase-get-transactions', + name: 'Shinkai: Coinbase Transactions Getter', + description: + 'Tool for getting the transactions of a Coinbase wallet after restoring it', + author: 'Shinkai', + keywords: ['coinbase', 'balance', 'shinkai'], + configurations: { + type: 'object', + properties: { + name: { type: 'string' }, + privateKey: { type: 'string' }, + walletId: { type: 'string' }, + }, + required: ['name', 'privateKey', 'walletId'], + }, + parameters: { + type: 'object', + properties: { + walletId: { type: 'string', nullable: true }, + }, + required: [], + }, + result: { + type: 'object', + properties: { + tableCsv: { type: 'string' }, + rowsCount: { type: 'number' }, + columnsCount: { type: 'number' }, + }, + required: ['tableCsv', 'rowsCount', 'columnsCount'], + }, + }; + + async run(params: Params): Promise> { + const coinbaseOptions: CoinbaseOptions = { + apiKeyName: this.config.name, + privateKey: this.config.privateKey, + }; + const coinbase = new Coinbase(coinbaseOptions); + const user = await coinbase.getDefaultUser(); + + // Prioritize walletId from Params over Config + const walletId = this.config.walletId; + + let wallet = await user.getWallet(walletId); + console.log(`Wallet retrieved: `, wallet.toString()); + + // Retrieve the list of balances for the wallet + let address = await wallet.getDefaultAddress(); + let transactions = (await address?.listTransfers()) ?? []; + + // Convert transactions to CSV format + const headers = [ + 'transferId', + 'networkId', + 'fromAddressId', + 'destinationAddressId', + 'assetId', + 'amount', + 'transactionHash', + 'transactionLink', + 'status', + ]; + const rows = transactions.map((tx) => [ + tx.getId(), + tx.getNetworkId(), + tx.getFromAddressId(), + tx.getDestinationAddressId(), + tx.getAssetId(), + tx.getAmount().toString(), + tx.getTransactionHash(), + tx.getTransactionLink(), + tx.getStatus(), + ]); + const tableCsv = [headers, ...rows].map((row) => row.join(';')).join('\n'); + + return Promise.resolve({ + data: { + tableCsv, + rowsCount: transactions.length, + columnsCount: headers.length, + }, + }); + } +} diff --git a/apps/shinkai-tool-coinbase-get-transactions/tsconfig.app.json b/apps/shinkai-tool-coinbase-get-transactions/tsconfig.app.json new file mode 100644 index 0000000..b139ef3 --- /dev/null +++ b/apps/shinkai-tool-coinbase-get-transactions/tsconfig.app.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "include": ["./src/**/*.ts"] +} diff --git a/apps/shinkai-tool-coinbase-get-transactions/tsconfig.json b/apps/shinkai-tool-coinbase-get-transactions/tsconfig.json new file mode 100644 index 0000000..61cc7dc --- /dev/null +++ b/apps/shinkai-tool-coinbase-get-transactions/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": {}, + "include": ["./src/**/*.ts"] +} diff --git a/apps/shinkai-tool-coinbase-get-transactions/tsconfig.spec.json b/apps/shinkai-tool-coinbase-get-transactions/tsconfig.spec.json new file mode 100644 index 0000000..6cfffe7 --- /dev/null +++ b/apps/shinkai-tool-coinbase-get-transactions/tsconfig.spec.json @@ -0,0 +1,15 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"], + "lib": ["dom"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/apps/shinkai-tool-coinbase-send-tx/src/index.test.ts b/apps/shinkai-tool-coinbase-send-tx/src/index.test.ts index 5166581..f5e856c 100644 --- a/apps/shinkai-tool-coinbase-send-tx/src/index.test.ts +++ b/apps/shinkai-tool-coinbase-send-tx/src/index.test.ts @@ -6,8 +6,3 @@ test('exists definition', async () => { // expect(definition).toBeInstanceOf(Object); }); -test('run definition', async () => { - // const tool = new Tool({}); - // const run_result = await tool.run({ walletId: '0d948159-3b3e-40f8-9001-741e64498fa9' }); - // console.log(run_result); -}, 25000); diff --git a/apps/shinkai-tool-coinbase-send-tx/src/index.ts b/apps/shinkai-tool-coinbase-send-tx/src/index.ts index 938ed6d..6ed5cdd 100644 --- a/apps/shinkai-tool-coinbase-send-tx/src/index.ts +++ b/apps/shinkai-tool-coinbase-send-tx/src/index.ts @@ -5,10 +5,11 @@ import { Coinbase, CoinbaseOptions } from '@coinbase/coinbase-sdk'; type Config = { name: string; privateKey: string; - walletId?: string; + walletId: string; + seed?: string; + useServerSigner?: boolean; }; type Params = { - walletId?: string; recipient_address: string; assetId: string; amount: string; @@ -31,13 +32,14 @@ export class Tool extends BaseTool { name: { type: 'string' }, privateKey: { type: 'string' }, walletId: { type: 'string', nullable: true }, + seed: { type: 'string', nullable: true }, + useServerSigner: { type: 'boolean', default: false, nullable: true }, }, required: ['name', 'privateKey'], }, parameters: { type: 'object', properties: { - walletId: { type: 'string', nullable: true }, recipient_address: { type: 'string' }, assetId: { type: 'string' }, amount: { type: 'string' }, @@ -54,34 +56,58 @@ export class Tool extends BaseTool { }; async run(params: Params): Promise> { - // Coinbase wallet creation using constructor const coinbaseOptions: CoinbaseOptions = { apiKeyName: this.config.name, privateKey: this.config.privateKey, - useServerSigner: false, - debugging: false, - basePath: '', - maxNetworkRetries: 3, + useServerSigner: this.config.useServerSigner ?? false, + debugging: true, }; const coinbase = new Coinbase(coinbaseOptions); console.log(`Coinbase configured: `, coinbase); const user = await coinbase.getDefaultUser(); console.log(`User: `, user); - // Prioritize walletId from Params over Config - const walletId = params.walletId || this.config.walletId; + // Check if seed exists or useServerSigner is true, but not both + if (!this.config.seed && !this.config.useServerSigner) { + throw new Error( + 'Either seed must be provided or useServerSigner must be true', + ); + } + if (this.config.seed && this.config.useServerSigner) { + throw new Error( + 'Both seed and useServerSigner cannot be true at the same time', + ); + } + // Prioritize walletId from Params over Config + const walletId = this.config.walletId; let wallet; - if (walletId) { - // Retrieve existing Wallet using walletId + + if (this.config.useServerSigner) { + // Use getWallet if useServerSigner is true + if (!walletId) { + throw new Error( + 'walletId must be provided when useServerSigner is true', + ); + } wallet = await user.getWallet(walletId); - console.log(`Wallet retrieved: `, wallet.toString()); + console.log(`Wallet retrieved using server signer: `, wallet.toString()); } else { - // Create a new Wallet for the User - wallet = await user.createWallet({ - networkId: Coinbase.networks.BaseSepolia, - }); - console.log(`Wallet successfully created: `, wallet.toString()); + if (walletId) { + // Retrieve existing Wallet using walletId + wallet = await user.importWallet({ + walletId, + // it's not going to be empty but to quiet the type error + seed: this.config.seed || '', + }); + console.log(`Wallet retrieved: `, wallet.toString()); + } else { + // Create a new Wallet for the User + wallet = await user.createWallet({ + networkId: Coinbase.networks.BaseSepolia, + }); + console.log(`Wallet successfully created: `, wallet.toString()); + } } // Retrieve the list of balances for the wallet @@ -107,16 +133,27 @@ export class Tool extends BaseTool { throw new Error('Invalid amount provided'); } + // Convert assetId to have only the first letter capitalized + const formattedAssetId = params.assetId.toLowerCase(); + // Create and send the transfer - const transfer = await wallet.createTransfer({ - amount, - assetId: params.assetId, - destination: params.recipient_address, - timeoutSeconds: 60, - intervalSeconds: 5, - gasless: false, - }); - console.log(`Transfer completed successfully: `, transfer.toString()); + let transfer; + try { + transfer = await wallet.createTransfer({ + amount, + assetId: Coinbase.toAssetId(formattedAssetId), + destination: params.recipient_address, + }); + console.log(`Transfer successfully completed: `, transfer.toString()); + } catch (error) { + if (error instanceof Error) { + console.error('Error during transfer:', error); + throw new Error(`Transfer failed: ${error.message}`); + } else { + console.error('Unknown error during transfer:', error); + throw new Error('Transfer failed due to an unknown error'); + } + } return { data: { diff --git a/libs/shinkai-tools-runner/src/lib.test.rs b/libs/shinkai-tools-runner/src/lib.test.rs index a277b4d..60d3c2e 100644 --- a/libs/shinkai-tools-runner/src/lib.test.rs +++ b/libs/shinkai-tools-runner/src/lib.test.rs @@ -354,12 +354,7 @@ async fn shinkai_tool_defillama_lending_tvl_rankings() { tool_definition.code.clone().unwrap(), serde_json::Value::Null, ); - let run_result = tool - .run( - serde_json::json!({ "all": true }), - None, - ) - .await; + let run_result = tool.run(serde_json::json!({ "all": true }), None).await; assert!(run_result.is_ok()); assert_eq!(run_result.unwrap().data["rowsCount"], 405); } @@ -379,4 +374,3 @@ async fn shinkai_tool_aave_loan_requester() { .await; assert!(run_result.is_ok()); } -