From 4657b17aac838d5185a2c180b2906dd068a9657b Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Thu, 5 Sep 2024 12:11:18 -0400 Subject: [PATCH 01/21] add kitchen sink: quorum provisioning --- examples/kitchen-sink/.env.local.example | 4 ++ examples/kitchen-sink/README.md | 3 ++ examples/kitchen-sink/httpClient.ts | 0 examples/kitchen-sink/package.json | 17 +++++++++ examples/kitchen-sink/sdkServerClient.ts | 48 ++++++++++++++++++++++++ examples/kitchen-sink/tsconfig.json | 8 ++++ pnpm-lock.yaml | 15 ++++++++ 7 files changed, 95 insertions(+) create mode 100644 examples/kitchen-sink/.env.local.example create mode 100644 examples/kitchen-sink/README.md create mode 100644 examples/kitchen-sink/httpClient.ts create mode 100644 examples/kitchen-sink/package.json create mode 100644 examples/kitchen-sink/sdkServerClient.ts create mode 100644 examples/kitchen-sink/tsconfig.json diff --git a/examples/kitchen-sink/.env.local.example b/examples/kitchen-sink/.env.local.example new file mode 100644 index 000000000..4e5e7ba16 --- /dev/null +++ b/examples/kitchen-sink/.env.local.example @@ -0,0 +1,4 @@ +API_PUBLIC_KEY="" +API_PRIVATE_KEY="" +BASE_URL="https://api.turnkey.com" +ORGANIZATION_ID="" diff --git a/examples/kitchen-sink/README.md b/examples/kitchen-sink/README.md new file mode 100644 index 000000000..c8c5555a0 --- /dev/null +++ b/examples/kitchen-sink/README.md @@ -0,0 +1,3 @@ +# Kitchen Sink + +A playground to make various Turnkey requests. diff --git a/examples/kitchen-sink/httpClient.ts b/examples/kitchen-sink/httpClient.ts new file mode 100644 index 000000000..e69de29bb diff --git a/examples/kitchen-sink/package.json b/examples/kitchen-sink/package.json new file mode 100644 index 000000000..cd6358e37 --- /dev/null +++ b/examples/kitchen-sink/package.json @@ -0,0 +1,17 @@ +{ + "name": "@turnkey/kitchen-sink", + "version": "0.1.0", + "private": true, + "scripts": { + "start-sdk-server": "tsx sdkServerClient.ts", + "start-http": "tsx httpClient.ts", + "clean": "rimraf ./dist ./.cache", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@turnkey/http": "workspace:*", + "@turnkey/api-key-stamper": "workspace:*", + "@turnkey/sdk-server": "workspace:*", + "dotenv": "^16.0.3" + } +} diff --git a/examples/kitchen-sink/sdkServerClient.ts b/examples/kitchen-sink/sdkServerClient.ts new file mode 100644 index 000000000..7b09a7f66 --- /dev/null +++ b/examples/kitchen-sink/sdkServerClient.ts @@ -0,0 +1,48 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { Turnkey as TurnkeyServerSDK } from "@turnkey/sdk-server"; + +async function main() { + // Initialize a Turnkey client + const turnkeyClient = new TurnkeyServerSDK({ + apiBaseUrl: process.env.BASE_URL!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + apiPublicKey: process.env.API_PUBLIC_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); + + const usersResponse = await turnkeyClient.apiClient().getUsers(); + const whoamiResponse = await turnkeyClient.apiClient().getWhoami(); + const orgConfigsResponse = await turnkeyClient + .apiClient() + .getOrganizationConfigs({ + organizationId: process.env.ORGANIZATION_ID!, + }); + + await turnkeyClient.apiClient().updateRootQuorum({ + threshold: 1, + userIds: [orgConfigsResponse.configs.quorum?.userIds[0]!], // retain the first root user, which would be the passkey user + }); + + const updatedOrgConfigsResponse = await turnkeyClient + .apiClient() + .getOrganizationConfigs({ + organizationId: process.env.ORGANIZATION_ID!, + }); + + console.log({ + users: usersResponse.users, + whoami: whoamiResponse, + rootQuorum: orgConfigsResponse.configs.quorum, + updatedRootQuorum: updatedOrgConfigsResponse.configs.quorum, + }); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/tsconfig.json b/examples/kitchen-sink/tsconfig.json new file mode 100644 index 000000000..6d4b83714 --- /dev/null +++ b/examples/kitchen-sink/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "noEmit": true, + "tsBuildInfoFile": "./.cache/.tsbuildinfo" + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.json"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 72808a367..096b1190f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -321,6 +321,21 @@ importers: specifier: ^1.4.8 version: 1.4.8 + examples/kitchen-sink: + dependencies: + '@turnkey/api-key-stamper': + specifier: workspace:* + version: link:../../packages/api-key-stamper + '@turnkey/http': + specifier: workspace:* + version: link:../../packages/http + '@turnkey/sdk-server': + specifier: workspace:* + version: link:../../packages/sdk-server + dotenv: + specifier: ^16.0.3 + version: 16.0.3 + examples/otp-auth: dependencies: '@turnkey/api-key-stamper': From 7db6f62974fe1404a7b46c0babe53abbf6250b55 Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Thu, 3 Oct 2024 18:16:00 -0400 Subject: [PATCH 02/21] round 1: add utilities --- examples/kitchen-sink/httpClient.ts | 0 examples/kitchen-sink/package.json | 2 + .../src/http/createEthereumPrivateKey.ts | 64 +++++++++++++++++++ .../src/http/createEthereumWallet.ts | 60 +++++++++++++++++ .../kitchen-sink/src/http/createPolicy.ts | 52 +++++++++++++++ .../src/http/createPrivateKeyTag.ts | 44 +++++++++++++ .../kitchen-sink/src/http/createUserTag.ts | 55 ++++++++++++++++ .../sdk-server/createEthereumPrivateKey.ts | 44 +++++++++++++ .../src/sdk-server/createEthereumWallet.ts | 46 +++++++++++++ .../src/sdk-server/updateRootQuorum.ts | 48 ++++++++++++++ examples/kitchen-sink/src/utils.ts | 10 +++ pnpm-lock.yaml | 6 ++ 12 files changed, 431 insertions(+) delete mode 100644 examples/kitchen-sink/httpClient.ts create mode 100644 examples/kitchen-sink/src/http/createEthereumPrivateKey.ts create mode 100644 examples/kitchen-sink/src/http/createEthereumWallet.ts create mode 100644 examples/kitchen-sink/src/http/createPolicy.ts create mode 100644 examples/kitchen-sink/src/http/createPrivateKeyTag.ts create mode 100644 examples/kitchen-sink/src/http/createUserTag.ts create mode 100644 examples/kitchen-sink/src/sdk-server/createEthereumPrivateKey.ts create mode 100644 examples/kitchen-sink/src/sdk-server/createEthereumWallet.ts create mode 100644 examples/kitchen-sink/src/sdk-server/updateRootQuorum.ts create mode 100644 examples/kitchen-sink/src/utils.ts diff --git a/examples/kitchen-sink/httpClient.ts b/examples/kitchen-sink/httpClient.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/examples/kitchen-sink/package.json b/examples/kitchen-sink/package.json index cd6358e37..426676203 100644 --- a/examples/kitchen-sink/package.json +++ b/examples/kitchen-sink/package.json @@ -12,6 +12,8 @@ "@turnkey/http": "workspace:*", "@turnkey/api-key-stamper": "workspace:*", "@turnkey/sdk-server": "workspace:*", + "@turnkey/sdk-react": "workspace:*", + "@turnkey/sdk-browser": "workspace:*", "dotenv": "^16.0.3" } } diff --git a/examples/kitchen-sink/src/http/createEthereumPrivateKey.ts b/examples/kitchen-sink/src/http/createEthereumPrivateKey.ts new file mode 100644 index 000000000..9e956c9f8 --- /dev/null +++ b/examples/kitchen-sink/src/http/createEthereumPrivateKey.ts @@ -0,0 +1,64 @@ +import { TurnkeyClient } from "@turnkey/http"; +import { createActivityPoller } from "@turnkey/http"; +import { ApiKeyStamper } from "@turnkey/api-key-stamper"; +import * as crypto from "crypto"; +import { refineNonNull } from "../utils"; + +export async function createNewEthereumPrivateKey() { + const turnkeyClient = new TurnkeyClient( + { baseUrl: process.env.BASE_URL! }, + new ApiKeyStamper({ + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + }) + ); + + console.log( + "`process.env.PRIVATE_KEY_ID` not found; creating a new Ethereum private key on Turnkey...\n" + ); + + const activityPoller = createActivityPoller({ + client: turnkeyClient, + requestFn: turnkeyClient.createPrivateKeys, + }); + + const privateKeyName = `ETH Key ${crypto.randomBytes(2).toString("hex")}`; + + try { + const activity = await activityPoller({ + type: "ACTIVITY_TYPE_CREATE_PRIVATE_KEYS_V2", + organizationId: process.env.ORGANIZATION_ID!, + parameters: { + privateKeys: [ + { + privateKeyName, + curve: "CURVE_SECP256K1", + addressFormats: ["ADDRESS_FORMAT_ETHEREUM"], + privateKeyTags: [], + }, + ], + }, + timestampMs: String(Date.now()), // millisecond timestamp + }); + + const privateKeys = refineNonNull( + activity.result.createPrivateKeysResultV2?.privateKeys + ); + const privateKeyId = refineNonNull(privateKeys?.[0]?.privateKeyId); + const address = refineNonNull(privateKeys?.[0]?.addresses?.[0]?.address); + + // Success! + console.log( + [ + `New Ethereum private key created!`, + `- Name: ${privateKeyName}`, + `- Private key ID: ${privateKeyId}`, + `- Address: ${address}`, + ``, + "Now you can take the private key ID, put it in `.env.local`, then re-run the script.", + ].join("\n") + ); + } catch (err: any) { + throw new Error("Failed to create a new Ethereum private key: " + err); + } +} diff --git a/examples/kitchen-sink/src/http/createEthereumWallet.ts b/examples/kitchen-sink/src/http/createEthereumWallet.ts new file mode 100644 index 000000000..873ed2a0e --- /dev/null +++ b/examples/kitchen-sink/src/http/createEthereumWallet.ts @@ -0,0 +1,60 @@ +import { TurnkeyClient, createActivityPoller } from "@turnkey/http"; +import { ApiKeyStamper } from "@turnkey/api-key-stamper"; +import * as crypto from "crypto"; +import { refineNonNull } from "../utils"; + +export async function createNewWallet() { + console.log("creating a new wallet on Turnkey...\n"); + + const walletName = `ETH Wallet ${crypto.randomBytes(2).toString("hex")}`; + + try { + const turnkeyClient = new TurnkeyClient( + { baseUrl: process.env.BASE_URL! }, + new ApiKeyStamper({ + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + }) + ); + + const activityPoller = createActivityPoller({ + client: turnkeyClient, + requestFn: turnkeyClient.createWallet, + }); + + const completedActivity = await activityPoller({ + type: "ACTIVITY_TYPE_CREATE_WALLET", + timestampMs: String(Date.now()), + organizationId: process.env.ORGANIZATION_ID!, + parameters: { + walletName, + accounts: [ + { + curve: "CURVE_SECP256K1", + pathFormat: "PATH_FORMAT_BIP32", + path: "m/44'/60'/0'/0/0", + addressFormat: "ADDRESS_FORMAT_ETHEREUM", + }, + ], + }, + }); + + const wallet = refineNonNull(completedActivity.result.createWalletResult); + const walletId = refineNonNull(wallet.walletId); + const address = refineNonNull(wallet.addresses[0]); + + // Success! + console.log( + [ + `New Ethereum wallet created!`, + `- Name: ${walletName}`, + `- Wallet ID: ${walletId}`, + `- Address: ${address}`, + ``, + "Now you can take the address, put it in `.env.local` (`SIGN_WITH=
`), then re-run the script.", + ].join("\n") + ); + } catch (err: any) { + throw new Error("Failed to create a new Ethereum private key: " + err); + } +} diff --git a/examples/kitchen-sink/src/http/createPolicy.ts b/examples/kitchen-sink/src/http/createPolicy.ts new file mode 100644 index 000000000..28fb886a0 --- /dev/null +++ b/examples/kitchen-sink/src/http/createPolicy.ts @@ -0,0 +1,52 @@ +import type { TurnkeyClient } from "@turnkey/http"; +import { createActivityPoller } from "@turnkey/http"; +import { refineNonNull } from "../utils"; + +export default async function createPolicy( + turnkeyClient: TurnkeyClient, + policyName: string, + effect: "EFFECT_ALLOW" | "EFFECT_DENY", + consensus: string, + condition: string +): Promise { + const activityPoller = createActivityPoller({ + client: turnkeyClient, + requestFn: turnkeyClient.createPolicy, + }); + + try { + const activity = await activityPoller({ + type: "ACTIVITY_TYPE_CREATE_POLICY_V3", + organizationId: process.env.ORGANIZATION_ID!, + parameters: { + policyName, + condition, + consensus, + effect, + notes: "", + }, + timestampMs: String(Date.now()), // millisecond timestamp + }); + + const policyId = refineNonNull( + activity.result.createPolicyResult?.policyId + ); + + // Success! + console.log( + [ + `New policy created!`, + `- Name: ${policyName}`, + `- Policy ID: ${policyId}`, + `- Effect: ${effect}`, + `- Consensus: ${consensus}`, + `- Condition: ${condition}`, + ``, + ].join("\n") + ); + + return policyId; + } catch (err: any) { + throw new Error("Failed to create a new Ethereum private key: " + err); + } +} diff --git a/examples/kitchen-sink/src/http/createPrivateKeyTag.ts b/examples/kitchen-sink/src/http/createPrivateKeyTag.ts new file mode 100644 index 000000000..3798f48e6 --- /dev/null +++ b/examples/kitchen-sink/src/http/createPrivateKeyTag.ts @@ -0,0 +1,44 @@ +import type { TurnkeyClient } from "@turnkey/http"; +import { createActivityPoller } from "@turnkey/http"; +import { refineNonNull } from "../utils"; + +export default async function createPrivateKeyTag( + turnkeyClient: TurnkeyClient, + privateKeyTagName: string, + privateKeyIds: string[] +): Promise { + const activityPoller = createActivityPoller({ + client: turnkeyClient, + requestFn: turnkeyClient.createPrivateKeyTag, + }); + + try { + const activity = await activityPoller({ + type: "ACTIVITY_TYPE_CREATE_PRIVATE_KEY_TAG", + organizationId: process.env.ORGANIZATION_ID!, + parameters: { + privateKeyTagName, + privateKeyIds, + }, + timestampMs: String(Date.now()), // millisecond timestamp + }); + + const privateKeyTagId = refineNonNull( + activity.result.createPrivateKeyTagResult?.privateKeyTagId + ); + + // Success! + console.log( + [ + `New private key tag created!`, + `- Name: ${privateKeyTagName}`, + `- Private key tag ID: ${privateKeyTagId}`, + ``, + ].join("\n") + ); + + return privateKeyTagId; + } catch (err: any) { + throw new Error("Failed to create a new Ethereum private key: " + err); + } +} diff --git a/examples/kitchen-sink/src/http/createUserTag.ts b/examples/kitchen-sink/src/http/createUserTag.ts new file mode 100644 index 000000000..4ec9d5052 --- /dev/null +++ b/examples/kitchen-sink/src/http/createUserTag.ts @@ -0,0 +1,55 @@ +import { createActivityPoller, type TurnkeyClient } from "@turnkey/http"; +import { refineNonNull } from "../utils"; + +export default async function createUser( + turnkeyClient: TurnkeyClient, + userName: string, + userTags: string[], + apiKeyName: string, + publicKey: string +): Promise { + const activityPoller = createActivityPoller({ + client: turnkeyClient, + requestFn: turnkeyClient.createApiOnlyUsers, + }); + + try { + const activity = await activityPoller({ + type: "ACTIVITY_TYPE_CREATE_API_ONLY_USERS", + organizationId: process.env.ORGANIZATION_ID!, + parameters: { + apiOnlyUsers: [ + { + userName, + userTags, + apiKeys: [ + { + apiKeyName, + publicKey, + }, + ], + }, + ], + }, + timestampMs: String(Date.now()), // millisecond timestamp + }); + + const userId = refineNonNull( + activity.result.createApiOnlyUsersResult?.userIds?.[0] + ); + + // Success! + console.log( + [ + `New user created!`, + `- Name: ${userName}`, + `- User ID: ${userId}`, + ``, + ].join("\n") + ); + + return userId; + } catch (err: any) { + throw new Error("Failed to create a new Ethereum private key: " + err); + } +} diff --git a/examples/kitchen-sink/src/sdk-server/createEthereumPrivateKey.ts b/examples/kitchen-sink/src/sdk-server/createEthereumPrivateKey.ts new file mode 100644 index 000000000..25a2f848e --- /dev/null +++ b/examples/kitchen-sink/src/sdk-server/createEthereumPrivateKey.ts @@ -0,0 +1,44 @@ +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; +import * as crypto from "crypto"; +import { refineNonNull } from "../utils"; + +export async function createNewEthereumPrivateKey() { + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); + + const privateKeyName = `ETH Key ${crypto.randomBytes(2).toString("hex")}`; + + try { + const { privateKeys } = await turnkeyClient.apiClient().createPrivateKeys({ + privateKeys: [ + { + privateKeyName, + curve: "CURVE_SECP256K1", + addressFormats: ["ADDRESS_FORMAT_ETHEREUM"], + privateKeyTags: [], + }, + ], + }); + + const privateKeyId = refineNonNull(privateKeys?.[0]?.privateKeyId); + const address = refineNonNull(privateKeys?.[0]?.addresses?.[0]?.address); + + // Success! + console.log( + [ + `New Ethereum private key created!`, + `- Name: ${privateKeyName}`, + `- Private key ID: ${privateKeyId}`, + `- Address: ${address}`, + ``, + "Now you can take the private key ID, put it in `.env.local`, then re-run the script.", + ].join("\n") + ); + } catch (err: any) { + throw new Error("Failed to create a new Ethereum private key: " + err); + } +} diff --git a/examples/kitchen-sink/src/sdk-server/createEthereumWallet.ts b/examples/kitchen-sink/src/sdk-server/createEthereumWallet.ts new file mode 100644 index 000000000..34bfbcd73 --- /dev/null +++ b/examples/kitchen-sink/src/sdk-server/createEthereumWallet.ts @@ -0,0 +1,46 @@ +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; +import * as crypto from "crypto"; +import { refineNonNull } from "../utils"; + +export async function createNewEthereumWallet() { + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); + + const walletName = `ETH Wallet ${crypto.randomBytes(2).toString("hex")}`; + + try { + const { walletId, addresses } = await turnkeyClient + .apiClient() + .createWallet({ + walletName, + accounts: [ + { + curve: "CURVE_SECP256K1", + pathFormat: "PATH_FORMAT_BIP32", + path: "m/44'/60'/0'/0/0", + addressFormat: "ADDRESS_FORMAT_ETHEREUM", + }, + ], + }); + + const address = refineNonNull(addresses[0]); + + // Success! + console.log( + [ + `New Ethereum wallet created!`, + `- Name: ${walletName}`, + `- Wallet ID: ${walletId}`, + `- Address: ${address}`, + ``, + "Now you can take the address, put it in `.env.local`, then re-run the script.", + ].join("\n") + ); + } catch (err: any) { + throw new Error("Failed to create a new Ethereum wallet: " + err); + } +} diff --git a/examples/kitchen-sink/src/sdk-server/updateRootQuorum.ts b/examples/kitchen-sink/src/sdk-server/updateRootQuorum.ts new file mode 100644 index 000000000..7b09a7f66 --- /dev/null +++ b/examples/kitchen-sink/src/sdk-server/updateRootQuorum.ts @@ -0,0 +1,48 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { Turnkey as TurnkeyServerSDK } from "@turnkey/sdk-server"; + +async function main() { + // Initialize a Turnkey client + const turnkeyClient = new TurnkeyServerSDK({ + apiBaseUrl: process.env.BASE_URL!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + apiPublicKey: process.env.API_PUBLIC_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); + + const usersResponse = await turnkeyClient.apiClient().getUsers(); + const whoamiResponse = await turnkeyClient.apiClient().getWhoami(); + const orgConfigsResponse = await turnkeyClient + .apiClient() + .getOrganizationConfigs({ + organizationId: process.env.ORGANIZATION_ID!, + }); + + await turnkeyClient.apiClient().updateRootQuorum({ + threshold: 1, + userIds: [orgConfigsResponse.configs.quorum?.userIds[0]!], // retain the first root user, which would be the passkey user + }); + + const updatedOrgConfigsResponse = await turnkeyClient + .apiClient() + .getOrganizationConfigs({ + organizationId: process.env.ORGANIZATION_ID!, + }); + + console.log({ + users: usersResponse.users, + whoami: whoamiResponse, + rootQuorum: orgConfigsResponse.configs.quorum, + updatedRootQuorum: updatedOrgConfigsResponse.configs.quorum, + }); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/utils.ts b/examples/kitchen-sink/src/utils.ts new file mode 100644 index 000000000..d26b4fd42 --- /dev/null +++ b/examples/kitchen-sink/src/utils.ts @@ -0,0 +1,10 @@ +export function refineNonNull( + input: T | null | undefined, + errorMessage?: string +): T { + if (input == null) { + throw new Error(errorMessage ?? `Unexpected ${JSON.stringify(input)}`); + } + + return input; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 096b1190f..cbad3e0d0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -329,6 +329,12 @@ importers: '@turnkey/http': specifier: workspace:* version: link:../../packages/http + '@turnkey/sdk-browser': + specifier: workspace:* + version: link:../../packages/sdk-browser + '@turnkey/sdk-react': + specifier: workspace:* + version: link:../../packages/sdk-react '@turnkey/sdk-server': specifier: workspace:* version: link:../../packages/sdk-server From 15f800b9dd2cf4553b5f53c5b081c9b4855fd51e Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Sun, 6 Oct 2024 23:17:31 -0400 Subject: [PATCH 03/21] update deployer example --- examples/deployer/package.json | 3 +- .../src/createNewEthereumPrivateKey.ts | 83 ------------------- examples/deployer/src/createNewWallet.ts | 56 ++++--------- examples/deployer/src/index.ts | 20 ++--- pnpm-lock.yaml | 6 +- 5 files changed, 27 insertions(+), 141 deletions(-) delete mode 100644 examples/deployer/src/createNewEthereumPrivateKey.ts diff --git a/examples/deployer/package.json b/examples/deployer/package.json index 44642c9e5..5d323eb25 100644 --- a/examples/deployer/package.json +++ b/examples/deployer/package.json @@ -9,9 +9,8 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@turnkey/api-key-stamper": "workspace:^", + "@turnkey/sdk-server": "workspace:*", "@turnkey/ethers": "workspace:*", - "@turnkey/http": "workspace:*", "dotenv": "^16.0.3", "ethers": "^6.10.0", "solc": "0.8.13" diff --git a/examples/deployer/src/createNewEthereumPrivateKey.ts b/examples/deployer/src/createNewEthereumPrivateKey.ts deleted file mode 100644 index 5bad3828c..000000000 --- a/examples/deployer/src/createNewEthereumPrivateKey.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { TurnkeyClient } from "@turnkey/http"; -import { createActivityPoller } from "@turnkey/http"; -import { ApiKeyStamper } from "@turnkey/api-key-stamper"; -import { TurnkeyActivityError } from "@turnkey/ethers"; -import * as crypto from "crypto"; - -export async function createNewEthereumPrivateKey() { - const turnkeyClient = new TurnkeyClient( - { baseUrl: process.env.BASE_URL! }, - new ApiKeyStamper({ - apiPublicKey: process.env.API_PUBLIC_KEY!, - apiPrivateKey: process.env.API_PRIVATE_KEY!, - }) - ); - - console.log( - "`process.env.PRIVATE_KEY_ID` not found; creating a new Ethereum private key on Turnkey...\n" - ); - - const activityPoller = createActivityPoller({ - client: turnkeyClient, - requestFn: turnkeyClient.createPrivateKeys, - }); - - const privateKeyName = `ETH Key ${crypto.randomBytes(2).toString("hex")}`; - - try { - const activity = await activityPoller({ - type: "ACTIVITY_TYPE_CREATE_PRIVATE_KEYS_V2", - organizationId: process.env.ORGANIZATION_ID!, - parameters: { - privateKeys: [ - { - privateKeyName, - curve: "CURVE_SECP256K1", - addressFormats: ["ADDRESS_FORMAT_ETHEREUM"], - privateKeyTags: [], - }, - ], - }, - timestampMs: String(Date.now()), // millisecond timestamp - }); - - const privateKeys = refineNonNull( - activity.result.createPrivateKeysResultV2?.privateKeys - ); - const privateKeyId = refineNonNull(privateKeys?.[0]?.privateKeyId); - const address = refineNonNull(privateKeys?.[0]?.addresses?.[0]?.address); - - // Success! - console.log( - [ - `New Ethereum private key created!`, - `- Name: ${privateKeyName}`, - `- Private key ID: ${privateKeyId}`, - `- Address: ${address}`, - ``, - "Now you can take the private key ID, put it in `.env.local`, then re-run the script.", - ].join("\n") - ); - } catch (error) { - // If needed, you can read from `TurnkeyActivityError` to find out why the activity didn't succeed - if (error instanceof TurnkeyActivityError) { - throw error; - } - - throw new TurnkeyActivityError({ - message: "Failed to create a new Ethereum private key", - cause: error as Error, - }); - } -} - -export function refineNonNull( - input: T | null | undefined, - errorMessage?: string -): T { - if (input == null) { - throw new Error(errorMessage ?? `Unexpected ${JSON.stringify(input)}`); - } - - return input; -} diff --git a/examples/deployer/src/createNewWallet.ts b/examples/deployer/src/createNewWallet.ts index 12ffd7327..ef31988d9 100644 --- a/examples/deployer/src/createNewWallet.ts +++ b/examples/deployer/src/createNewWallet.ts @@ -1,36 +1,21 @@ -import { - TurnkeyClient, - createActivityPoller, - TurnkeyActivityError, -} from "@turnkey/http"; -import { ApiKeyStamper } from "@turnkey/api-key-stamper"; +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; import * as crypto from "crypto"; import { refineNonNull } from "./util"; export async function createNewWallet() { - console.log("creating a new wallet on Turnkey...\n"); + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); const walletName = `ETH Wallet ${crypto.randomBytes(2).toString("hex")}`; try { - const turnkeyClient = new TurnkeyClient( - { baseUrl: process.env.BASE_URL! }, - new ApiKeyStamper({ - apiPublicKey: process.env.API_PUBLIC_KEY!, - apiPrivateKey: process.env.API_PRIVATE_KEY!, - }) - ); - - const activityPoller = createActivityPoller({ - client: turnkeyClient, - requestFn: turnkeyClient.createWallet, - }); - - const completedActivity = await activityPoller({ - type: "ACTIVITY_TYPE_CREATE_WALLET", - timestampMs: String(Date.now()), - organizationId: process.env.ORGANIZATION_ID!, - parameters: { + const { walletId, addresses } = await turnkeyClient + .apiClient() + .createWallet({ walletName, accounts: [ { @@ -40,12 +25,9 @@ export async function createNewWallet() { addressFormat: "ADDRESS_FORMAT_ETHEREUM", }, ], - }, - }); + }); - const wallet = refineNonNull(completedActivity.result.createWalletResult); - const walletId = refineNonNull(wallet.walletId); - const address = refineNonNull(wallet.addresses[0]); + const address = refineNonNull(addresses[0]); // Success! console.log( @@ -55,18 +37,10 @@ export async function createNewWallet() { `- Wallet ID: ${walletId}`, `- Address: ${address}`, ``, - "Now you can take the address, put it in `.env.local` (`SIGN_WITH=
`), then re-run the script.", + "Now you can take the address, put it in `.env.local`, then re-run the script.", ].join("\n") ); - } catch (error) { - // If needed, you can read from `TurnkeyActivityError` to find out why the activity didn't succeed - if (error instanceof TurnkeyActivityError) { - throw error; - } - - throw new TurnkeyActivityError({ - message: "Failed to create a new Ethereum wallet", - cause: error as Error, - }); + } catch (err: any) { + throw new Error("Failed to create a new Ethereum wallet: " + err); } } diff --git a/examples/deployer/src/index.ts b/examples/deployer/src/index.ts index 52f00f69b..cbf9a65ab 100644 --- a/examples/deployer/src/index.ts +++ b/examples/deployer/src/index.ts @@ -6,8 +6,7 @@ dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); import { TurnkeySigner } from "@turnkey/ethers"; import { ethers } from "ethers"; -import { TurnkeyClient } from "@turnkey/http"; -import { ApiKeyStamper } from "@turnkey/api-key-stamper"; +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; import { createNewWallet } from "./createNewWallet"; import compile from "./compile"; import { print } from "./util"; @@ -19,19 +18,16 @@ async function main() { return; } - const turnkeyClient = new TurnkeyClient( - { - baseUrl: process.env.BASE_URL!, - }, - new ApiKeyStamper({ - apiPublicKey: process.env.API_PUBLIC_KEY!, - apiPrivateKey: process.env.API_PRIVATE_KEY!, - }) - ); + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); // Initialize a Turnkey Signer const turnkeySigner = new TurnkeySigner({ - client: turnkeyClient, + client: turnkeyClient.apiClient(), organizationId: process.env.ORGANIZATION_ID!, signWith: process.env.SIGN_WITH!, }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cbad3e0d0..e3c114400 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -63,15 +63,15 @@ importers: examples/deployer: dependencies: - '@turnkey/api-key-stamper': - specifier: workspace:^ - version: link:../../packages/api-key-stamper '@turnkey/ethers': specifier: workspace:* version: link:../../packages/ethers '@turnkey/http': specifier: workspace:* version: link:../../packages/http + '@turnkey/sdk-server': + specifier: workspace:* + version: link:../../packages/sdk-server dotenv: specifier: ^16.0.3 version: 16.0.3 From fe22a613e02c436452f0fa6312bc4280d8ff819c Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Wed, 16 Oct 2024 10:04:58 -0400 Subject: [PATCH 04/21] update gnosis example --- examples/with-gnosis/package.json | 3 +- .../src/createNewEthereumPrivateKey.ts | 49 +++++---------- examples/with-gnosis/src/createNewWallet.ts | 59 +++++-------------- 3 files changed, 33 insertions(+), 78 deletions(-) diff --git a/examples/with-gnosis/package.json b/examples/with-gnosis/package.json index 7c6769437..e27e1b2fe 100644 --- a/examples/with-gnosis/package.json +++ b/examples/with-gnosis/package.json @@ -10,9 +10,8 @@ "@safe-global/protocol-kit": "^3.0.1", "@safe-global/safe-core-sdk-types": "^4.0.1", "@safe-global/safe-ethers-lib": "^1.9.2", - "@turnkey/api-key-stamper": "workspace:^", + "@turnkey/sdk-server": "workspace:*", "@turnkey/ethers": "workspace:*", - "@turnkey/http": "workspace:*", "dotenv": "^16.0.3", "ethers": "^6.10.0" }, diff --git a/examples/with-gnosis/src/createNewEthereumPrivateKey.ts b/examples/with-gnosis/src/createNewEthereumPrivateKey.ts index 691223590..c4a819f26 100644 --- a/examples/with-gnosis/src/createNewEthereumPrivateKey.ts +++ b/examples/with-gnosis/src/createNewEthereumPrivateKey.ts @@ -1,50 +1,33 @@ -import { TurnkeyClient } from "@turnkey/http"; -import { createActivityPoller } from "@turnkey/http"; -import { ApiKeyStamper } from "@turnkey/api-key-stamper"; +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; import { TurnkeyActivityError } from "@turnkey/ethers"; import * as crypto from "crypto"; import { refineNonNull } from "./util"; export async function createNewEthereumPrivateKey() { - const turnkeyClient = new TurnkeyClient( - { baseUrl: process.env.BASE_URL! }, - new ApiKeyStamper({ - apiPublicKey: process.env.API_PUBLIC_KEY!, - apiPrivateKey: process.env.API_PRIVATE_KEY!, - }) - ); + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); console.log( "`process.env.PRIVATE_KEY_ID_{INDEX}` not found; creating a new Ethereum private key on Turnkey...\n" ); - - const activityPoller = createActivityPoller({ - client: turnkeyClient, - requestFn: turnkeyClient.createPrivateKeys, - }); - const privateKeyName = `ETH Key ${crypto.randomBytes(2).toString("hex")}`; try { - const activity = await activityPoller({ - type: "ACTIVITY_TYPE_CREATE_PRIVATE_KEYS_V2", - organizationId: process.env.ORGANIZATION_ID!, - parameters: { - privateKeys: [ - { - privateKeyName, - curve: "CURVE_SECP256K1", - addressFormats: ["ADDRESS_FORMAT_ETHEREUM"], - privateKeyTags: [], - }, - ], - }, - timestampMs: String(Date.now()), // millisecond timestamp + const { privateKeys } = await turnkeyClient.apiClient().createPrivateKeys({ + privateKeys: [ + { + privateKeyName, + curve: "CURVE_SECP256K1", + addressFormats: ["ADDRESS_FORMAT_ETHEREUM"], + privateKeyTags: [], + }, + ], }); - const privateKeys = refineNonNull( - activity.result.createPrivateKeysResultV2?.privateKeys - ); const privateKeyId = refineNonNull(privateKeys?.[0]?.privateKeyId); const address = refineNonNull(privateKeys?.[0]?.addresses?.[0]?.address); diff --git a/examples/with-gnosis/src/createNewWallet.ts b/examples/with-gnosis/src/createNewWallet.ts index e81dae2a3..a61d83177 100644 --- a/examples/with-gnosis/src/createNewWallet.ts +++ b/examples/with-gnosis/src/createNewWallet.ts @@ -1,36 +1,24 @@ import { - TurnkeyClient, - createActivityPoller, + Turnkey as TurnkeySDKServer, TurnkeyActivityError, -} from "@turnkey/http"; -import { ApiKeyStamper } from "@turnkey/api-key-stamper"; +} from "@turnkey/sdk-server"; import * as crypto from "crypto"; import { refineNonNull } from "./util"; -export async function createNewWallet() { - console.log("creating a new wallet on Turnkey...\n"); +export async function createNewEthereumWallet() { + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); const walletName = `ETH Wallet ${crypto.randomBytes(2).toString("hex")}`; try { - const turnkeyClient = new TurnkeyClient( - { baseUrl: process.env.BASE_URL! }, - new ApiKeyStamper({ - apiPublicKey: process.env.API_PUBLIC_KEY!, - apiPrivateKey: process.env.API_PRIVATE_KEY!, - }) - ); - - const activityPoller = createActivityPoller({ - client: turnkeyClient, - requestFn: turnkeyClient.createWallet, - }); - - const completedActivity = await activityPoller({ - type: "ACTIVITY_TYPE_CREATE_WALLET", - timestampMs: String(Date.now()), - organizationId: process.env.ORGANIZATION_ID!, - parameters: { + const { walletId, addresses } = await turnkeyClient + .apiClient() + .createWallet({ walletName, accounts: [ { @@ -39,25 +27,10 @@ export async function createNewWallet() { path: "m/44'/60'/0'/0/0", addressFormat: "ADDRESS_FORMAT_ETHEREUM", }, - { - curve: "CURVE_SECP256K1", - pathFormat: "PATH_FORMAT_BIP32", - path: "m/44'/60'/1'/0/0", - addressFormat: "ADDRESS_FORMAT_ETHEREUM", - }, - { - curve: "CURVE_SECP256K1", - pathFormat: "PATH_FORMAT_BIP32", - path: "m/44'/60'/2'/0/0", - addressFormat: "ADDRESS_FORMAT_ETHEREUM", - }, ], - }, - }); + }); - const wallet = refineNonNull(completedActivity.result.createWalletResult); - const walletId = refineNonNull(wallet.walletId); - const addresses = refineNonNull(wallet.addresses); + const address = refineNonNull(addresses[0]); // Success! console.log( @@ -65,9 +38,9 @@ export async function createNewWallet() { `New Ethereum wallet created!`, `- Name: ${walletName}`, `- Wallet ID: ${walletId}`, - `- Address: ${addresses}`, + `- Address: ${address}`, ``, - "Now you can take the addresses, put them in `.env.local`, then re-run the script.", + "Now you can take the address, put it in `.env.local`, then re-run the script.", ].join("\n") ); } catch (error) { From aacf496a79269174f14bfdfcc6a3831957a938e2 Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Wed, 16 Oct 2024 10:05:21 -0400 Subject: [PATCH 05/21] update ethers example --- examples/with-ethers/src/createNewWallet.ts | 52 ++++++--------------- 1 file changed, 15 insertions(+), 37 deletions(-) diff --git a/examples/with-ethers/src/createNewWallet.ts b/examples/with-ethers/src/createNewWallet.ts index 12ffd7327..a2c3b4c5b 100644 --- a/examples/with-ethers/src/createNewWallet.ts +++ b/examples/with-ethers/src/createNewWallet.ts @@ -1,9 +1,5 @@ -import { - TurnkeyClient, - createActivityPoller, - TurnkeyActivityError, -} from "@turnkey/http"; -import { ApiKeyStamper } from "@turnkey/api-key-stamper"; +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; + import * as crypto from "crypto"; import { refineNonNull } from "./util"; @@ -13,24 +9,16 @@ export async function createNewWallet() { const walletName = `ETH Wallet ${crypto.randomBytes(2).toString("hex")}`; try { - const turnkeyClient = new TurnkeyClient( - { baseUrl: process.env.BASE_URL! }, - new ApiKeyStamper({ - apiPublicKey: process.env.API_PUBLIC_KEY!, - apiPrivateKey: process.env.API_PRIVATE_KEY!, - }) - ); - - const activityPoller = createActivityPoller({ - client: turnkeyClient, - requestFn: turnkeyClient.createWallet, + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, }); - const completedActivity = await activityPoller({ - type: "ACTIVITY_TYPE_CREATE_WALLET", - timestampMs: String(Date.now()), - organizationId: process.env.ORGANIZATION_ID!, - parameters: { + const { walletId, addresses } = await turnkeyClient + .apiClient() + .createWallet({ walletName, accounts: [ { @@ -40,33 +28,23 @@ export async function createNewWallet() { addressFormat: "ADDRESS_FORMAT_ETHEREUM", }, ], - }, - }); + }); - const wallet = refineNonNull(completedActivity.result.createWalletResult); - const walletId = refineNonNull(wallet.walletId); - const address = refineNonNull(wallet.addresses[0]); + const newWalletId = refineNonNull(walletId); + const address = refineNonNull(addresses[0]); // Success! console.log( [ `New Ethereum wallet created!`, `- Name: ${walletName}`, - `- Wallet ID: ${walletId}`, + `- Wallet ID: ${newWalletId}`, `- Address: ${address}`, ``, "Now you can take the address, put it in `.env.local` (`SIGN_WITH=
`), then re-run the script.", ].join("\n") ); } catch (error) { - // If needed, you can read from `TurnkeyActivityError` to find out why the activity didn't succeed - if (error instanceof TurnkeyActivityError) { - throw error; - } - - throw new TurnkeyActivityError({ - message: "Failed to create a new Ethereum wallet", - cause: error as Error, - }); + throw new Error("Failed to create a new Ethereum wallet: " + error); } } From 1f9c2785094ba3ea375a573ade5428d483823d03 Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Wed, 16 Oct 2024 10:05:28 -0400 Subject: [PATCH 06/21] update viem example --- examples/with-viem/src/createNewWallet.ts | 52 +++++++---------------- 1 file changed, 15 insertions(+), 37 deletions(-) diff --git a/examples/with-viem/src/createNewWallet.ts b/examples/with-viem/src/createNewWallet.ts index 12ffd7327..a2c3b4c5b 100644 --- a/examples/with-viem/src/createNewWallet.ts +++ b/examples/with-viem/src/createNewWallet.ts @@ -1,9 +1,5 @@ -import { - TurnkeyClient, - createActivityPoller, - TurnkeyActivityError, -} from "@turnkey/http"; -import { ApiKeyStamper } from "@turnkey/api-key-stamper"; +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; + import * as crypto from "crypto"; import { refineNonNull } from "./util"; @@ -13,24 +9,16 @@ export async function createNewWallet() { const walletName = `ETH Wallet ${crypto.randomBytes(2).toString("hex")}`; try { - const turnkeyClient = new TurnkeyClient( - { baseUrl: process.env.BASE_URL! }, - new ApiKeyStamper({ - apiPublicKey: process.env.API_PUBLIC_KEY!, - apiPrivateKey: process.env.API_PRIVATE_KEY!, - }) - ); - - const activityPoller = createActivityPoller({ - client: turnkeyClient, - requestFn: turnkeyClient.createWallet, + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, }); - const completedActivity = await activityPoller({ - type: "ACTIVITY_TYPE_CREATE_WALLET", - timestampMs: String(Date.now()), - organizationId: process.env.ORGANIZATION_ID!, - parameters: { + const { walletId, addresses } = await turnkeyClient + .apiClient() + .createWallet({ walletName, accounts: [ { @@ -40,33 +28,23 @@ export async function createNewWallet() { addressFormat: "ADDRESS_FORMAT_ETHEREUM", }, ], - }, - }); + }); - const wallet = refineNonNull(completedActivity.result.createWalletResult); - const walletId = refineNonNull(wallet.walletId); - const address = refineNonNull(wallet.addresses[0]); + const newWalletId = refineNonNull(walletId); + const address = refineNonNull(addresses[0]); // Success! console.log( [ `New Ethereum wallet created!`, `- Name: ${walletName}`, - `- Wallet ID: ${walletId}`, + `- Wallet ID: ${newWalletId}`, `- Address: ${address}`, ``, "Now you can take the address, put it in `.env.local` (`SIGN_WITH=
`), then re-run the script.", ].join("\n") ); } catch (error) { - // If needed, you can read from `TurnkeyActivityError` to find out why the activity didn't succeed - if (error instanceof TurnkeyActivityError) { - throw error; - } - - throw new TurnkeyActivityError({ - message: "Failed to create a new Ethereum wallet", - cause: error as Error, - }); + throw new Error("Failed to create a new Ethereum wallet: " + error); } } From b15d45ff66b2a8f8f57021be2b78edd9ece9c61b Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Wed, 16 Oct 2024 10:05:34 -0400 Subject: [PATCH 07/21] update solana example --- examples/with-solana/src/utils/createSolanaWallet.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/with-solana/src/utils/createSolanaWallet.ts b/examples/with-solana/src/utils/createSolanaWallet.ts index 6d9d382cd..acd6d936b 100644 --- a/examples/with-solana/src/utils/createSolanaWallet.ts +++ b/examples/with-solana/src/utils/createSolanaWallet.ts @@ -1,5 +1,7 @@ -import { TurnkeyActivityError } from "@turnkey/http"; -import type { TurnkeyApiClient } from "@turnkey/sdk-server"; +import { + type TurnkeyApiClient, + TurnkeyActivityError, +} from "@turnkey/sdk-server"; import * as crypto from "crypto"; export async function createNewSolanaWallet(client: TurnkeyApiClient) { From 155cd696db76cf2a7112c3404ff04d5fd9a42470 Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Wed, 16 Oct 2024 11:07:16 -0400 Subject: [PATCH 08/21] update kitchen sink README --- examples/kitchen-sink/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/kitchen-sink/README.md b/examples/kitchen-sink/README.md index c8c5555a0..f1dea8e35 100644 --- a/examples/kitchen-sink/README.md +++ b/examples/kitchen-sink/README.md @@ -1,3 +1,7 @@ # Kitchen Sink -A playground to make various Turnkey requests. +A playground and example bank for making Turnkey requests in various ways: + +- `src/http`: create Turnkey requests in the most primitive way, using `@turnkey/http` and a stamper (e.g. `@turnkey/api-key-stamper`) +- `src/sdk-server`: create Turnkey requests using `@turnkey/sdk-server`, which abstracts away some of the internals in the above method +- 🚧 WIP `src/sdk-browser`: create Turnkey requests using `@turnkey/sdk-browser`, which also abstracts away some of the internals from the `@turnkey/http` approach. Note that `@turnkey/sdk-browser` has an interface identical to `@turnkey/sdk-server` From 164e167c16c8c602aa4598189bad056f146c7402 Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Wed, 16 Oct 2024 11:07:32 -0400 Subject: [PATCH 09/21] update requests via http update http nits. to squash --- .../src/http/createEthereumPrivateKey.ts | 85 +++++++------- .../src/http/createEthereumWallet.ts | 107 ++++++++++-------- .../kitchen-sink/src/http/createPolicy.ts | 101 ++++++++++------- .../src/http/createPrivateKeyTag.ts | 86 ++++++++------ .../src/http/createSolanaPrivateKey.ts | 70 ++++++++++++ .../src/http/createSolanaWallet.ts | 69 +++++++++++ examples/kitchen-sink/src/http/createUser.ts | 70 ++++++++++++ .../kitchen-sink/src/http/createUserTag.ts | 98 ++++++++-------- .../src/http/setOrganizationFeature.ts | 44 +++++++ .../kitchen-sink/src/http/signRawPayload.ts | 47 ++++++++ .../kitchen-sink/src/http/signTransaction.ts | 45 ++++++++ .../kitchen-sink/src/http/updateRootQuorum.ts | 60 ++++++++++ .../sdk-server/createEthereumPrivateKey.ts | 69 ++++++----- .../src/sdk-server/createEthereumWallet.ts | 72 ++++++------ 14 files changed, 741 insertions(+), 282 deletions(-) create mode 100644 examples/kitchen-sink/src/http/createSolanaPrivateKey.ts create mode 100644 examples/kitchen-sink/src/http/createSolanaWallet.ts create mode 100644 examples/kitchen-sink/src/http/createUser.ts create mode 100644 examples/kitchen-sink/src/http/setOrganizationFeature.ts create mode 100644 examples/kitchen-sink/src/http/signRawPayload.ts create mode 100644 examples/kitchen-sink/src/http/signTransaction.ts create mode 100644 examples/kitchen-sink/src/http/updateRootQuorum.ts diff --git a/examples/kitchen-sink/src/http/createEthereumPrivateKey.ts b/examples/kitchen-sink/src/http/createEthereumPrivateKey.ts index 9e956c9f8..b60e3153b 100644 --- a/examples/kitchen-sink/src/http/createEthereumPrivateKey.ts +++ b/examples/kitchen-sink/src/http/createEthereumPrivateKey.ts @@ -1,10 +1,18 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + import { TurnkeyClient } from "@turnkey/http"; import { createActivityPoller } from "@turnkey/http"; import { ApiKeyStamper } from "@turnkey/api-key-stamper"; import * as crypto from "crypto"; import { refineNonNull } from "../utils"; -export async function createNewEthereumPrivateKey() { +async function main() { + console.log("creating a new private key on Turnkey...\n"); + const turnkeyClient = new TurnkeyClient( { baseUrl: process.env.BASE_URL! }, new ApiKeyStamper({ @@ -13,10 +21,6 @@ export async function createNewEthereumPrivateKey() { }) ); - console.log( - "`process.env.PRIVATE_KEY_ID` not found; creating a new Ethereum private key on Turnkey...\n" - ); - const activityPoller = createActivityPoller({ client: turnkeyClient, requestFn: turnkeyClient.createPrivateKeys, @@ -24,41 +28,42 @@ export async function createNewEthereumPrivateKey() { const privateKeyName = `ETH Key ${crypto.randomBytes(2).toString("hex")}`; - try { - const activity = await activityPoller({ - type: "ACTIVITY_TYPE_CREATE_PRIVATE_KEYS_V2", - organizationId: process.env.ORGANIZATION_ID!, - parameters: { - privateKeys: [ - { - privateKeyName, - curve: "CURVE_SECP256K1", - addressFormats: ["ADDRESS_FORMAT_ETHEREUM"], - privateKeyTags: [], - }, - ], - }, - timestampMs: String(Date.now()), // millisecond timestamp - }); + const activity = await activityPoller({ + type: "ACTIVITY_TYPE_CREATE_PRIVATE_KEYS_V2", + organizationId: process.env.ORGANIZATION_ID!, + parameters: { + privateKeys: [ + { + privateKeyName, + curve: "CURVE_SECP256K1", + addressFormats: ["ADDRESS_FORMAT_ETHEREUM"], + privateKeyTags: [], + }, + ], + }, + timestampMs: String(Date.now()), // millisecond timestamp + }); - const privateKeys = refineNonNull( - activity.result.createPrivateKeysResultV2?.privateKeys - ); - const privateKeyId = refineNonNull(privateKeys?.[0]?.privateKeyId); - const address = refineNonNull(privateKeys?.[0]?.addresses?.[0]?.address); + const privateKeys = refineNonNull( + activity.result.createPrivateKeysResultV2?.privateKeys + ); + const privateKeyId = refineNonNull(privateKeys?.[0]?.privateKeyId); + const address = refineNonNull(privateKeys?.[0]?.addresses?.[0]?.address); - // Success! - console.log( - [ - `New Ethereum private key created!`, - `- Name: ${privateKeyName}`, - `- Private key ID: ${privateKeyId}`, - `- Address: ${address}`, - ``, - "Now you can take the private key ID, put it in `.env.local`, then re-run the script.", - ].join("\n") - ); - } catch (err: any) { - throw new Error("Failed to create a new Ethereum private key: " + err); - } + // Success! + console.log( + [ + `New Ethereum private key created!`, + `- Name: ${privateKeyName}`, + `- Private key ID: ${privateKeyId}`, + `- Address: ${address}`, + ``, + "Now you can take the private key ID, put it in `.env.local`, then re-run the script.", + ].join("\n") + ); } + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/http/createEthereumWallet.ts b/examples/kitchen-sink/src/http/createEthereumWallet.ts index 873ed2a0e..bd3df8bf0 100644 --- a/examples/kitchen-sink/src/http/createEthereumWallet.ts +++ b/examples/kitchen-sink/src/http/createEthereumWallet.ts @@ -1,60 +1,67 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + import { TurnkeyClient, createActivityPoller } from "@turnkey/http"; import { ApiKeyStamper } from "@turnkey/api-key-stamper"; import * as crypto from "crypto"; import { refineNonNull } from "../utils"; -export async function createNewWallet() { +async function main() { console.log("creating a new wallet on Turnkey...\n"); const walletName = `ETH Wallet ${crypto.randomBytes(2).toString("hex")}`; - try { - const turnkeyClient = new TurnkeyClient( - { baseUrl: process.env.BASE_URL! }, - new ApiKeyStamper({ - apiPublicKey: process.env.API_PUBLIC_KEY!, - apiPrivateKey: process.env.API_PRIVATE_KEY!, - }) - ); - - const activityPoller = createActivityPoller({ - client: turnkeyClient, - requestFn: turnkeyClient.createWallet, - }); - - const completedActivity = await activityPoller({ - type: "ACTIVITY_TYPE_CREATE_WALLET", - timestampMs: String(Date.now()), - organizationId: process.env.ORGANIZATION_ID!, - parameters: { - walletName, - accounts: [ - { - curve: "CURVE_SECP256K1", - pathFormat: "PATH_FORMAT_BIP32", - path: "m/44'/60'/0'/0/0", - addressFormat: "ADDRESS_FORMAT_ETHEREUM", - }, - ], - }, - }); - - const wallet = refineNonNull(completedActivity.result.createWalletResult); - const walletId = refineNonNull(wallet.walletId); - const address = refineNonNull(wallet.addresses[0]); - - // Success! - console.log( - [ - `New Ethereum wallet created!`, - `- Name: ${walletName}`, - `- Wallet ID: ${walletId}`, - `- Address: ${address}`, - ``, - "Now you can take the address, put it in `.env.local` (`SIGN_WITH=
`), then re-run the script.", - ].join("\n") - ); - } catch (err: any) { - throw new Error("Failed to create a new Ethereum private key: " + err); - } + const turnkeyClient = new TurnkeyClient( + { baseUrl: process.env.BASE_URL! }, + new ApiKeyStamper({ + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + }) + ); + + const activityPoller = createActivityPoller({ + client: turnkeyClient, + requestFn: turnkeyClient.createWallet, + }); + + const completedActivity = await activityPoller({ + type: "ACTIVITY_TYPE_CREATE_WALLET", + timestampMs: String(Date.now()), + organizationId: process.env.ORGANIZATION_ID!, + parameters: { + walletName, + accounts: [ + { + curve: "CURVE_SECP256K1", + pathFormat: "PATH_FORMAT_BIP32", + path: "m/44'/60'/0'/0/0", + addressFormat: "ADDRESS_FORMAT_ETHEREUM", + }, + ], + }, + }); + + const wallet = refineNonNull(completedActivity.result.createWalletResult); + const walletId = refineNonNull(wallet.walletId); + const address = refineNonNull(wallet.addresses[0]); + + // Success! + console.log( + [ + `New Ethereum wallet created!`, + `- Name: ${walletName}`, + `- Wallet ID: ${walletId}`, + `- Address: ${address}`, + ``, + "Now you can take the address, put it in `.env.local` (`SIGN_WITH=
`), then re-run the script.", + ].join("\n") + ); } + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/http/createPolicy.ts b/examples/kitchen-sink/src/http/createPolicy.ts index 28fb886a0..a3db3257b 100644 --- a/examples/kitchen-sink/src/http/createPolicy.ts +++ b/examples/kitchen-sink/src/http/createPolicy.ts @@ -1,52 +1,65 @@ -import type { TurnkeyClient } from "@turnkey/http"; -import { createActivityPoller } from "@turnkey/http"; +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { TurnkeyClient, createActivityPoller } from "@turnkey/http"; +import { ApiKeyStamper } from "@turnkey/api-key-stamper"; + import { refineNonNull } from "../utils"; -export default async function createPolicy( - turnkeyClient: TurnkeyClient, - policyName: string, - effect: "EFFECT_ALLOW" | "EFFECT_DENY", - consensus: string, - condition: string -): Promise { +async function main() { + // Initialize a Turnkey client + const turnkeyClient = new TurnkeyClient( + { baseUrl: process.env.BASE_URL! }, + new ApiKeyStamper({ + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + }) + ); + const activityPoller = createActivityPoller({ client: turnkeyClient, requestFn: turnkeyClient.createPolicy, }); - try { - const activity = await activityPoller({ - type: "ACTIVITY_TYPE_CREATE_POLICY_V3", - organizationId: process.env.ORGANIZATION_ID!, - parameters: { - policyName, - condition, - consensus, - effect, - notes: "", - }, - timestampMs: String(Date.now()), // millisecond timestamp - }); - - const policyId = refineNonNull( - activity.result.createPolicyResult?.policyId - ); - - // Success! - console.log( - [ - `New policy created!`, - `- Name: ${policyName}`, - `- Policy ID: ${policyId}`, - `- Effect: ${effect}`, - `- Consensus: ${consensus}`, - `- Condition: ${condition}`, - ``, - ].join("\n") - ); - - return policyId; - } catch (err: any) { - throw new Error("Failed to create a new Ethereum private key: " + err); - } + const policyName = " { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/http/createPrivateKeyTag.ts b/examples/kitchen-sink/src/http/createPrivateKeyTag.ts index 3798f48e6..5087d303f 100644 --- a/examples/kitchen-sink/src/http/createPrivateKeyTag.ts +++ b/examples/kitchen-sink/src/http/createPrivateKeyTag.ts @@ -1,44 +1,58 @@ -import type { TurnkeyClient } from "@turnkey/http"; -import { createActivityPoller } from "@turnkey/http"; +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { TurnkeyClient, createActivityPoller } from "@turnkey/http"; +import { ApiKeyStamper } from "@turnkey/api-key-stamper"; + import { refineNonNull } from "../utils"; -export default async function createPrivateKeyTag( - turnkeyClient: TurnkeyClient, - privateKeyTagName: string, - privateKeyIds: string[] -): Promise { +async function main() { + // Initialize a Turnkey client + const turnkeyClient = new TurnkeyClient( + { baseUrl: process.env.BASE_URL! }, + new ApiKeyStamper({ + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + }) + ); + const activityPoller = createActivityPoller({ client: turnkeyClient, requestFn: turnkeyClient.createPrivateKeyTag, }); - try { - const activity = await activityPoller({ - type: "ACTIVITY_TYPE_CREATE_PRIVATE_KEY_TAG", - organizationId: process.env.ORGANIZATION_ID!, - parameters: { - privateKeyTagName, - privateKeyIds, - }, - timestampMs: String(Date.now()), // millisecond timestamp - }); - - const privateKeyTagId = refineNonNull( - activity.result.createPrivateKeyTagResult?.privateKeyTagId - ); - - // Success! - console.log( - [ - `New private key tag created!`, - `- Name: ${privateKeyTagName}`, - `- Private key tag ID: ${privateKeyTagId}`, - ``, - ].join("\n") - ); - - return privateKeyTagId; - } catch (err: any) { - throw new Error("Failed to create a new Ethereum private key: " + err); - } + const privateKeyTagName = ""; + const privateKeyIds = [""]; + + const activity = await activityPoller({ + type: "ACTIVITY_TYPE_CREATE_PRIVATE_KEY_TAG", + organizationId: process.env.ORGANIZATION_ID!, + parameters: { + privateKeyTagName, + privateKeyIds, + }, + timestampMs: String(Date.now()), // millisecond timestamp + }); + + const privateKeyTagId = refineNonNull( + activity.result.createPrivateKeyTagResult?.privateKeyTagId + ); + + // Success! + console.log( + [ + `New private key tag created!`, + `- Name: ${privateKeyTagName}`, + `- Private key tag ID: ${privateKeyTagId}`, + ``, + ].join("\n") + ); } + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/http/createSolanaPrivateKey.ts b/examples/kitchen-sink/src/http/createSolanaPrivateKey.ts new file mode 100644 index 000000000..ad8bc0f2e --- /dev/null +++ b/examples/kitchen-sink/src/http/createSolanaPrivateKey.ts @@ -0,0 +1,70 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { TurnkeyClient, createActivityPoller } from "@turnkey/http"; +import { ApiKeyStamper } from "@turnkey/api-key-stamper"; + +import * as crypto from "crypto"; + +import { refineNonNull } from "../utils"; + +async function main() { + const turnkeyClient = new TurnkeyClient( + { baseUrl: process.env.BASE_URL! }, + new ApiKeyStamper({ + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + }) + ); + + console.log("creating a new Solana private key on Turnkey..."); + + const activityPoller = createActivityPoller({ + client: turnkeyClient, + requestFn: turnkeyClient.createPrivateKeys, + }); + + const privateKeyName = `SOL Key ${crypto.randomBytes(2).toString("hex")}`; + + const activity = await activityPoller({ + type: "ACTIVITY_TYPE_CREATE_PRIVATE_KEYS_V2", + organizationId: process.env.ORGANIZATION_ID!, + parameters: { + privateKeys: [ + { + privateKeyName, + curve: "CURVE_ED25519", + addressFormats: ["ADDRESS_FORMAT_SOLANA"], + privateKeyTags: [], + }, + ], + }, + timestampMs: String(Date.now()), // millisecond timestamp + }); + + const privateKeys = refineNonNull( + activity.result.createPrivateKeysResultV2?.privateKeys + ); + const privateKeyId = refineNonNull(privateKeys?.[0]?.privateKeyId); + const address = refineNonNull(privateKeys?.[0]?.addresses?.[0]?.address); + + // Success! + console.log( + [ + `New Solana private key created!`, + `- Name: ${privateKeyName}`, + `- Private key ID: ${privateKeyId}`, + `- Address: ${address}`, + ``, + "Now you can take the private key ID, put it in `.env.local`, then re-run the script.", + ].join("\n") + ); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/http/createSolanaWallet.ts b/examples/kitchen-sink/src/http/createSolanaWallet.ts new file mode 100644 index 000000000..45dcd26b4 --- /dev/null +++ b/examples/kitchen-sink/src/http/createSolanaWallet.ts @@ -0,0 +1,69 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; +import * as crypto from "crypto"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { TurnkeyClient, createActivityPoller } from "@turnkey/http"; +import { ApiKeyStamper } from "@turnkey/api-key-stamper"; + +import { refineNonNull } from "../utils"; + +async function main() { + console.log("creating a new wallet on Turnkey...\n"); + + const walletName = `SOL Wallet ${crypto.randomBytes(2).toString("hex")}`; + + const turnkeyClient = new TurnkeyClient( + { baseUrl: process.env.BASE_URL! }, + new ApiKeyStamper({ + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + }) + ); + + const activityPoller = createActivityPoller({ + client: turnkeyClient, + requestFn: turnkeyClient.createWallet, + }); + + const completedActivity = await activityPoller({ + type: "ACTIVITY_TYPE_CREATE_WALLET", + timestampMs: String(Date.now()), + organizationId: process.env.ORGANIZATION_ID!, + parameters: { + walletName, + accounts: [ + { + pathFormat: "PATH_FORMAT_BIP32", + // https://github.com/satoshilabs/slips/blob/master/slip-0044.md + path: "m/44'/501'/0'/0'", + curve: "CURVE_ED25519", + addressFormat: "ADDRESS_FORMAT_SOLANA", + }, + ], + }, + }); + + const wallet = refineNonNull(completedActivity.result.createWalletResult); + const walletId = refineNonNull(wallet.walletId); + const address = refineNonNull(wallet.addresses[0]); + + // Success! + console.log( + [ + `New SOL wallet created!`, + `- Name: ${walletName}`, + `- Wallet ID: ${walletId}`, + `- Address: ${address}`, + ``, + "Now you can take the address, put it in `.env.local` (`SIGN_WITH=
`), then re-run the script.", + ].join("\n") + ); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/http/createUser.ts b/examples/kitchen-sink/src/http/createUser.ts new file mode 100644 index 000000000..522c7b9a0 --- /dev/null +++ b/examples/kitchen-sink/src/http/createUser.ts @@ -0,0 +1,70 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { TurnkeyClient, createActivityPoller } from "@turnkey/http"; +import { ApiKeyStamper } from "@turnkey/api-key-stamper"; + +import { refineNonNull } from "../utils"; + +async function main() { + // Initialize a Turnkey client + const turnkeyClient = new TurnkeyClient( + { baseUrl: process.env.BASE_URL! }, + new ApiKeyStamper({ + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + }) + ); + + const activityPoller = createActivityPoller({ + client: turnkeyClient, + requestFn: turnkeyClient.createApiOnlyUsers, + }); + + const userName = ""; + const userTags = [""]; + const apiKeyName = ""; + const publicKey = ""; + + const activity = await activityPoller({ + type: "ACTIVITY_TYPE_CREATE_API_ONLY_USERS", + organizationId: process.env.ORGANIZATION_ID!, + parameters: { + apiOnlyUsers: [ + { + userName, + userTags, + apiKeys: [ + { + apiKeyName, + publicKey, + }, + ], + }, + ], + }, + timestampMs: String(Date.now()), // millisecond timestamp + }); + + const userId = refineNonNull( + activity.result.createApiOnlyUsersResult?.userIds?.[0] + ); + + // Success! + console.log( + [ + `New user created!`, + `- Name: ${userName}`, + `- User ID: ${userId}`, + ``, + ].join("\n") + ); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/http/createUserTag.ts b/examples/kitchen-sink/src/http/createUserTag.ts index 4ec9d5052..9f6691d8e 100644 --- a/examples/kitchen-sink/src/http/createUserTag.ts +++ b/examples/kitchen-sink/src/http/createUserTag.ts @@ -1,55 +1,57 @@ -import { createActivityPoller, type TurnkeyClient } from "@turnkey/http"; +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { TurnkeyClient, createActivityPoller } from "@turnkey/http"; +import { ApiKeyStamper } from "@turnkey/api-key-stamper"; + import { refineNonNull } from "../utils"; -export default async function createUser( - turnkeyClient: TurnkeyClient, - userName: string, - userTags: string[], - apiKeyName: string, - publicKey: string -): Promise { +async function main() { + // Initialize a Turnkey client + const turnkeyClient = new TurnkeyClient( + { baseUrl: process.env.BASE_URL! }, + new ApiKeyStamper({ + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + }) + ); + const activityPoller = createActivityPoller({ client: turnkeyClient, - requestFn: turnkeyClient.createApiOnlyUsers, + requestFn: turnkeyClient.createUserTag, }); - try { - const activity = await activityPoller({ - type: "ACTIVITY_TYPE_CREATE_API_ONLY_USERS", - organizationId: process.env.ORGANIZATION_ID!, - parameters: { - apiOnlyUsers: [ - { - userName, - userTags, - apiKeys: [ - { - apiKeyName, - publicKey, - }, - ], - }, - ], - }, - timestampMs: String(Date.now()), // millisecond timestamp - }); - - const userId = refineNonNull( - activity.result.createApiOnlyUsersResult?.userIds?.[0] - ); - - // Success! - console.log( - [ - `New user created!`, - `- Name: ${userName}`, - `- User ID: ${userId}`, - ``, - ].join("\n") - ); - - return userId; - } catch (err: any) { - throw new Error("Failed to create a new Ethereum private key: " + err); - } + const userTagName = ""; + + const activity = await activityPoller({ + type: "ACTIVITY_TYPE_CREATE_USER_TAG", + organizationId: process.env.ORGANIZATION_ID!, + parameters: { + userTagName, + userIds: [], // relevant user IDs + }, + timestampMs: String(Date.now()), // millisecond timestamp + }); + + const userTagId = refineNonNull( + activity.result.createUserTagResult?.userTagId + ); + + // Success! + console.log( + [ + `New user tag created!`, + `- Name: ${userTagName}`, + `- User tag ID: ${userTagId}`, + ``, + ].join("\n") + ); } + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/http/setOrganizationFeature.ts b/examples/kitchen-sink/src/http/setOrganizationFeature.ts new file mode 100644 index 000000000..132f8767f --- /dev/null +++ b/examples/kitchen-sink/src/http/setOrganizationFeature.ts @@ -0,0 +1,44 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { TurnkeyClient, createActivityPoller } from "@turnkey/http"; +import { ApiKeyStamper } from "@turnkey/api-key-stamper"; + +async function main() { + // Initialize a Turnkey client + const turnkeyClient = new TurnkeyClient( + { baseUrl: process.env.BASE_URL! }, + new ApiKeyStamper({ + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + }) + ); + + const activityPoller = createActivityPoller({ + client: turnkeyClient, + requestFn: turnkeyClient.setOrganizationFeature, + }); + + const activityResponse = await activityPoller({ + type: "ACTIVITY_TYPE_SET_ORGANIZATION_FEATURE", + timestampMs: String(Date.now()), + organizationId: process.env.ORGANIZATION_ID!, + parameters: { + name: "FEATURE_NAME_EMAIL_AUTH", + value: "", + }, + }); + + console.log( + "Successfully set organization feature. Updated features:", + activityResponse.result.setOrganizationFeatureResult?.features + ); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/http/signRawPayload.ts b/examples/kitchen-sink/src/http/signRawPayload.ts new file mode 100644 index 000000000..f11cad883 --- /dev/null +++ b/examples/kitchen-sink/src/http/signRawPayload.ts @@ -0,0 +1,47 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { TurnkeyClient, createActivityPoller } from "@turnkey/http"; +import { ApiKeyStamper } from "@turnkey/api-key-stamper"; + +async function main() { + // Initialize a Turnkey client + const turnkeyClient = new TurnkeyClient( + { baseUrl: process.env.BASE_URL! }, + new ApiKeyStamper({ + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + }) + ); + + const activityPoller = createActivityPoller({ + client: turnkeyClient, + requestFn: turnkeyClient.signRawPayload, + }); + + const activityResponse = await activityPoller({ + type: "ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2", + timestampMs: String(Date.now()), + organizationId: process.env.ORGANIZATION_ID!, + parameters: { + signWith: "", + payload: "", + // these parameters will largely be dependent on your use case + hashFunction: "HASH_FUNCTION_NO_OP", + encoding: "PAYLOAD_ENCODING_HEXADECIMAL", + }, + }); + + console.log( + "Successfully signed raw payload:", + activityResponse.result.signRawPayloadResult! + ); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/http/signTransaction.ts b/examples/kitchen-sink/src/http/signTransaction.ts new file mode 100644 index 000000000..9443d8c4c --- /dev/null +++ b/examples/kitchen-sink/src/http/signTransaction.ts @@ -0,0 +1,45 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { TurnkeyClient, createActivityPoller } from "@turnkey/http"; +import { ApiKeyStamper } from "@turnkey/api-key-stamper"; + +async function main() { + // Initialize a Turnkey client + const turnkeyClient = new TurnkeyClient( + { baseUrl: process.env.BASE_URL! }, + new ApiKeyStamper({ + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + }) + ); + + const activityPoller = createActivityPoller({ + client: turnkeyClient, + requestFn: turnkeyClient.signTransaction, + }); + + const activityResponse = await activityPoller({ + type: "ACTIVITY_TYPE_SIGN_TRANSACTION_V2", + timestampMs: String(Date.now()), + organizationId: process.env.ORGANIZATION_ID!, + parameters: { + signWith: "", + type: "TRANSACTION_TYPE_ETHEREUM", + unsignedTransaction: "", + }, + }); + + console.log( + "Successfully signed transaction:", + activityResponse.result.signTransactionResult?.signedTransaction + ); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/http/updateRootQuorum.ts b/examples/kitchen-sink/src/http/updateRootQuorum.ts new file mode 100644 index 000000000..0d5e192c6 --- /dev/null +++ b/examples/kitchen-sink/src/http/updateRootQuorum.ts @@ -0,0 +1,60 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { TurnkeyClient, createActivityPoller } from "@turnkey/http"; +import { ApiKeyStamper } from "@turnkey/api-key-stamper"; + +async function main() { + // Initialize a Turnkey client + const turnkeyClient = new TurnkeyClient( + { baseUrl: process.env.BASE_URL! }, + new ApiKeyStamper({ + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + }) + ); + + const activityPoller = createActivityPoller({ + client: turnkeyClient, + requestFn: turnkeyClient.updateRootQuorum, + }); + + const usersResponse = await turnkeyClient.getUsers({ + organizationId: process.env.ORGANIZATION_ID!, + }); + const whoamiResponse = await turnkeyClient.getWhoami({ + organizationId: process.env.ORGANIZATION_ID!, + }); + const orgConfigsResponse = await turnkeyClient.getOrganizationConfigs({ + organizationId: process.env.ORGANIZATION_ID!, + }); + + await activityPoller({ + type: "ACTIVITY_TYPE_UPDATE_ROOT_QUORUM", + timestampMs: String(Date.now()), + organizationId: process.env.ORGANIZATION_ID!, + parameters: { + threshold: 1, + userIds: [orgConfigsResponse.configs.quorum?.userIds[0]!], // retain the first root user + }, + }); + + const updatedOrgConfigsResponse = await turnkeyClient.getOrganizationConfigs({ + organizationId: process.env.ORGANIZATION_ID!, + }); + + console.log({ + users: usersResponse.users, + whoami: whoamiResponse, + rootQuorum: orgConfigsResponse.configs.quorum, + updatedRootQuorum: updatedOrgConfigsResponse.configs.quorum, + }); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/sdk-server/createEthereumPrivateKey.ts b/examples/kitchen-sink/src/sdk-server/createEthereumPrivateKey.ts index 25a2f848e..33f91df52 100644 --- a/examples/kitchen-sink/src/sdk-server/createEthereumPrivateKey.ts +++ b/examples/kitchen-sink/src/sdk-server/createEthereumPrivateKey.ts @@ -1,8 +1,14 @@ -import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; +import * as path from "path"; +import * as dotenv from "dotenv"; import * as crypto from "crypto"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; + import { refineNonNull } from "../utils"; -export async function createNewEthereumPrivateKey() { +async function main() { const turnkeyClient = new TurnkeySDKServer({ apiBaseUrl: "https://api.turnkey.com", apiPublicKey: process.env.API_PUBLIC_KEY!, @@ -12,33 +18,34 @@ export async function createNewEthereumPrivateKey() { const privateKeyName = `ETH Key ${crypto.randomBytes(2).toString("hex")}`; - try { - const { privateKeys } = await turnkeyClient.apiClient().createPrivateKeys({ - privateKeys: [ - { - privateKeyName, - curve: "CURVE_SECP256K1", - addressFormats: ["ADDRESS_FORMAT_ETHEREUM"], - privateKeyTags: [], - }, - ], - }); - - const privateKeyId = refineNonNull(privateKeys?.[0]?.privateKeyId); - const address = refineNonNull(privateKeys?.[0]?.addresses?.[0]?.address); - - // Success! - console.log( - [ - `New Ethereum private key created!`, - `- Name: ${privateKeyName}`, - `- Private key ID: ${privateKeyId}`, - `- Address: ${address}`, - ``, - "Now you can take the private key ID, put it in `.env.local`, then re-run the script.", - ].join("\n") - ); - } catch (err: any) { - throw new Error("Failed to create a new Ethereum private key: " + err); - } + const { privateKeys } = await turnkeyClient.apiClient().createPrivateKeys({ + privateKeys: [ + { + privateKeyName, + curve: "CURVE_SECP256K1", + addressFormats: ["ADDRESS_FORMAT_ETHEREUM"], + privateKeyTags: [], + }, + ], + }); + + const privateKeyId = refineNonNull(privateKeys?.[0]?.privateKeyId); + const address = refineNonNull(privateKeys?.[0]?.addresses?.[0]?.address); + + // Success! + console.log( + [ + `New Ethereum private key created!`, + `- Name: ${privateKeyName}`, + `- Private key ID: ${privateKeyId}`, + `- Address: ${address}`, + ``, + "Now you can take the private key ID, put it in `.env.local`, then re-run the script.", + ].join("\n") + ); } + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/sdk-server/createEthereumWallet.ts b/examples/kitchen-sink/src/sdk-server/createEthereumWallet.ts index 34bfbcd73..e5966f480 100644 --- a/examples/kitchen-sink/src/sdk-server/createEthereumWallet.ts +++ b/examples/kitchen-sink/src/sdk-server/createEthereumWallet.ts @@ -1,8 +1,15 @@ -import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; +import * as path from "path"; +import * as dotenv from "dotenv"; import * as crypto from "crypto"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; + import { refineNonNull } from "../utils"; -export async function createNewEthereumWallet() { +async function main() { const turnkeyClient = new TurnkeySDKServer({ apiBaseUrl: "https://api.turnkey.com", apiPublicKey: process.env.API_PUBLIC_KEY!, @@ -12,35 +19,34 @@ export async function createNewEthereumWallet() { const walletName = `ETH Wallet ${crypto.randomBytes(2).toString("hex")}`; - try { - const { walletId, addresses } = await turnkeyClient - .apiClient() - .createWallet({ - walletName, - accounts: [ - { - curve: "CURVE_SECP256K1", - pathFormat: "PATH_FORMAT_BIP32", - path: "m/44'/60'/0'/0/0", - addressFormat: "ADDRESS_FORMAT_ETHEREUM", - }, - ], - }); - - const address = refineNonNull(addresses[0]); - - // Success! - console.log( - [ - `New Ethereum wallet created!`, - `- Name: ${walletName}`, - `- Wallet ID: ${walletId}`, - `- Address: ${address}`, - ``, - "Now you can take the address, put it in `.env.local`, then re-run the script.", - ].join("\n") - ); - } catch (err: any) { - throw new Error("Failed to create a new Ethereum wallet: " + err); - } + const { walletId, addresses } = await turnkeyClient.apiClient().createWallet({ + walletName, + accounts: [ + { + curve: "CURVE_SECP256K1", + pathFormat: "PATH_FORMAT_BIP32", + path: "m/44'/60'/0'/0/0", + addressFormat: "ADDRESS_FORMAT_ETHEREUM", + }, + ], + }); + + const address = refineNonNull(addresses[0]); + + // Success! + console.log( + [ + `New Ethereum wallet created!`, + `- Name: ${walletName}`, + `- Wallet ID: ${walletId}`, + `- Address: ${address}`, + ``, + "Now you can take the address, put it in `.env.local`, then re-run the script.", + ].join("\n") + ); } + +main().catch((error) => { + console.error(error); + process.exit(1); +}); From b13b683a76c685d2989d859c7ad25d25a2aa238e Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Wed, 16 Oct 2024 11:07:49 -0400 Subject: [PATCH 10/21] update requests via sdk-server --- .../src/sdk-server/setOrganizationFeature.ts | 32 +++++++++++++++++++ .../src/sdk-server/signRawPayload.ts | 32 +++++++++++++++++++ .../src/sdk-server/signTransaction.ts | 32 +++++++++++++++++++ .../src/sdk-server/updateRootQuorum.ts | 2 +- .../src/requests/createPolicy.ts | 3 +- 5 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 examples/kitchen-sink/src/sdk-server/setOrganizationFeature.ts create mode 100644 examples/kitchen-sink/src/sdk-server/signRawPayload.ts create mode 100644 examples/kitchen-sink/src/sdk-server/signTransaction.ts diff --git a/examples/kitchen-sink/src/sdk-server/setOrganizationFeature.ts b/examples/kitchen-sink/src/sdk-server/setOrganizationFeature.ts new file mode 100644 index 000000000..79556f351 --- /dev/null +++ b/examples/kitchen-sink/src/sdk-server/setOrganizationFeature.ts @@ -0,0 +1,32 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { Turnkey as TurnkeyServerSDK } from "@turnkey/sdk-server"; + +async function main() { + // Initialize a Turnkey client + const turnkeyClient = new TurnkeyServerSDK({ + apiBaseUrl: process.env.BASE_URL!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + apiPublicKey: process.env.API_PUBLIC_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); + + const { features } = await turnkeyClient.apiClient().setOrganizationFeature({ + name: "FEATURE_NAME_EMAIL_AUTH", + value: "", + }); + + console.log( + "Successfully set organization feature. Updated features:", + features + ); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/sdk-server/signRawPayload.ts b/examples/kitchen-sink/src/sdk-server/signRawPayload.ts new file mode 100644 index 000000000..13a762639 --- /dev/null +++ b/examples/kitchen-sink/src/sdk-server/signRawPayload.ts @@ -0,0 +1,32 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { Turnkey as TurnkeyServerSDK } from "@turnkey/sdk-server"; + +async function main() { + // Initialize a Turnkey client + const turnkeyClient = new TurnkeyServerSDK({ + apiBaseUrl: process.env.BASE_URL!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + apiPublicKey: process.env.API_PUBLIC_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); + + const { r, s, v } = await turnkeyClient.apiClient().signRawPayload({ + signWith: "", + payload: "", + // these parameters will largely be dependent on your use case + hashFunction: "HASH_FUNCTION_NO_OP", + encoding: "PAYLOAD_ENCODING_HEXADECIMAL", + }); + + console.log("Successfully signed raw payload:", { r, s, v }); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/sdk-server/signTransaction.ts b/examples/kitchen-sink/src/sdk-server/signTransaction.ts new file mode 100644 index 000000000..511d1c3f2 --- /dev/null +++ b/examples/kitchen-sink/src/sdk-server/signTransaction.ts @@ -0,0 +1,32 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { Turnkey as TurnkeyServerSDK } from "@turnkey/sdk-server"; + +async function main() { + // Initialize a Turnkey client + const turnkeyClient = new TurnkeyServerSDK({ + apiBaseUrl: process.env.BASE_URL!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + apiPublicKey: process.env.API_PUBLIC_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); + + const { signedTransaction } = await turnkeyClient + .apiClient() + .signTransaction({ + signWith: "", + type: "TRANSACTION_TYPE_ETHEREUM", + unsignedTransaction: "", + }); + + console.log("Successfully signed transaction:", signedTransaction); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/sdk-server/updateRootQuorum.ts b/examples/kitchen-sink/src/sdk-server/updateRootQuorum.ts index 7b09a7f66..87e4cdb58 100644 --- a/examples/kitchen-sink/src/sdk-server/updateRootQuorum.ts +++ b/examples/kitchen-sink/src/sdk-server/updateRootQuorum.ts @@ -25,7 +25,7 @@ async function main() { await turnkeyClient.apiClient().updateRootQuorum({ threshold: 1, - userIds: [orgConfigsResponse.configs.quorum?.userIds[0]!], // retain the first root user, which would be the passkey user + userIds: [orgConfigsResponse.configs.quorum?.userIds[0]!], // retain the first root user }); const updatedOrgConfigsResponse = await turnkeyClient diff --git a/examples/trading-runner/src/requests/createPolicy.ts b/examples/trading-runner/src/requests/createPolicy.ts index cc849d19f..59484d85d 100644 --- a/examples/trading-runner/src/requests/createPolicy.ts +++ b/examples/trading-runner/src/requests/createPolicy.ts @@ -1,6 +1,5 @@ import type { TurnkeyClient } from "@turnkey/http"; -import { createActivityPoller } from "@turnkey/http"; -import { TurnkeyActivityError } from "@turnkey/ethers"; +import { createActivityPoller, TurnkeyActivityError } from "@turnkey/http"; import { refineNonNull } from "./utils"; export default async function createPolicy( From d11c8d7745bcaf7e0c3f50bb0412158a231146bf Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Wed, 16 Oct 2024 11:26:43 -0400 Subject: [PATCH 11/21] squash: updated kitchen sink --- .../sdk-server/createEthereumPrivateKey.ts | 1 + .../src/sdk-server/createPolicy.ts | 53 ++++++++++++++++++ .../src/sdk-server/createPrivateKeyTag.ts | 46 +++++++++++++++ .../src/sdk-server/createSolanaPrivateKey.ts | 56 +++++++++++++++++++ .../src/sdk-server/createSolanaWallet.ts | 56 +++++++++++++++++++ .../kitchen-sink/src/sdk-server/createUser.ts | 56 +++++++++++++++++++ .../src/sdk-server/createUserTag.ts | 43 ++++++++++++++ 7 files changed, 311 insertions(+) create mode 100644 examples/kitchen-sink/src/sdk-server/createPolicy.ts create mode 100644 examples/kitchen-sink/src/sdk-server/createPrivateKeyTag.ts create mode 100644 examples/kitchen-sink/src/sdk-server/createSolanaPrivateKey.ts create mode 100644 examples/kitchen-sink/src/sdk-server/createSolanaWallet.ts create mode 100644 examples/kitchen-sink/src/sdk-server/createUser.ts create mode 100644 examples/kitchen-sink/src/sdk-server/createUserTag.ts diff --git a/examples/kitchen-sink/src/sdk-server/createEthereumPrivateKey.ts b/examples/kitchen-sink/src/sdk-server/createEthereumPrivateKey.ts index 33f91df52..3170fa845 100644 --- a/examples/kitchen-sink/src/sdk-server/createEthereumPrivateKey.ts +++ b/examples/kitchen-sink/src/sdk-server/createEthereumPrivateKey.ts @@ -4,6 +4,7 @@ import * as crypto from "crypto"; // Load environment variables from `.env.local` dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; import { refineNonNull } from "../utils"; diff --git a/examples/kitchen-sink/src/sdk-server/createPolicy.ts b/examples/kitchen-sink/src/sdk-server/createPolicy.ts new file mode 100644 index 000000000..230200897 --- /dev/null +++ b/examples/kitchen-sink/src/sdk-server/createPolicy.ts @@ -0,0 +1,53 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; + +import { refineNonNull } from "../utils"; + +async function main() { + // Initialize a Turnkey client + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); + + const policyName = " { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/sdk-server/createPrivateKeyTag.ts b/examples/kitchen-sink/src/sdk-server/createPrivateKeyTag.ts new file mode 100644 index 000000000..7089292e7 --- /dev/null +++ b/examples/kitchen-sink/src/sdk-server/createPrivateKeyTag.ts @@ -0,0 +1,46 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; + +import { refineNonNull } from "../utils"; + +async function main() { + // Initialize a Turnkey client + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); + + const privateKeyTagName = ""; + const privateKeyIds = [""]; + + const { privateKeyTagId } = await turnkeyClient + .apiClient() + .createPrivateKeyTag({ + privateKeyTagName, + privateKeyIds, + }); + + const newPrivateKeyTagId = refineNonNull(privateKeyTagId); + + // Success! + console.log( + [ + `New private key tag created!`, + `- Name: ${privateKeyTagName}`, + `- Private key tag ID: ${newPrivateKeyTagId}`, + ``, + ].join("\n") + ); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/sdk-server/createSolanaPrivateKey.ts b/examples/kitchen-sink/src/sdk-server/createSolanaPrivateKey.ts new file mode 100644 index 000000000..ffc71af86 --- /dev/null +++ b/examples/kitchen-sink/src/sdk-server/createSolanaPrivateKey.ts @@ -0,0 +1,56 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; + +import * as crypto from "crypto"; + +import { refineNonNull } from "../utils"; + +async function main() { + console.log("creating a new Solana private key on Turnkey..."); + + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); + + const privateKeyName = `SOL Key ${crypto.randomBytes(2).toString("hex")}`; + + const { privateKeys } = await turnkeyClient.apiClient().createPrivateKeys({ + privateKeys: [ + { + privateKeyName, + curve: "CURVE_ED25519", + addressFormats: ["ADDRESS_FORMAT_SOLANA"], + privateKeyTags: [], + }, + ], + }); + + const newPrivateKeys = refineNonNull(privateKeys); + const privateKeyId = refineNonNull(newPrivateKeys[0]?.privateKeyId); + const address = refineNonNull(newPrivateKeys[0]?.addresses?.[0]?.address); + + // Success! + console.log( + [ + `New Solana private key created!`, + `- Name: ${privateKeyName}`, + `- Private key ID: ${privateKeyId}`, + `- Address: ${address}`, + ``, + "Now you can take the private key ID, put it in `.env.local`, then re-run the script.", + ].join("\n") + ); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/sdk-server/createSolanaWallet.ts b/examples/kitchen-sink/src/sdk-server/createSolanaWallet.ts new file mode 100644 index 000000000..efec4a259 --- /dev/null +++ b/examples/kitchen-sink/src/sdk-server/createSolanaWallet.ts @@ -0,0 +1,56 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; +import * as crypto from "crypto"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; + +import { refineNonNull } from "../utils"; + +async function main() { + console.log("creating a new wallet on Turnkey...\n"); + + const walletName = `SOL Wallet ${crypto.randomBytes(2).toString("hex")}`; + + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); + + const { walletId, addresses } = await turnkeyClient.apiClient().createWallet({ + walletName, + accounts: [ + { + pathFormat: "PATH_FORMAT_BIP32", + // https://github.com/satoshilabs/slips/blob/master/slip-0044.md + path: "m/44'/501'/0'/0'", + curve: "CURVE_ED25519", + addressFormat: "ADDRESS_FORMAT_SOLANA", + }, + ], + }); + + const newWalletId = refineNonNull(walletId); + const address = refineNonNull(addresses[0]); + + // Success! + console.log( + [ + `New SOL wallet created!`, + `- Name: ${walletName}`, + `- Wallet ID: ${newWalletId}`, + `- Address: ${address}`, + ``, + "Now you can take the address, put it in `.env.local` (`SIGN_WITH=
`), then re-run the script.", + ].join("\n") + ); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/sdk-server/createUser.ts b/examples/kitchen-sink/src/sdk-server/createUser.ts new file mode 100644 index 000000000..2e097d5e8 --- /dev/null +++ b/examples/kitchen-sink/src/sdk-server/createUser.ts @@ -0,0 +1,56 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; + +import { refineNonNull } from "../utils"; + +async function main() { + // Initialize a Turnkey client + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); + + const userName = ""; + const userTags = [""]; + const apiKeyName = ""; + const publicKey = ""; + + const { userIds } = await turnkeyClient.apiClient().createApiOnlyUsers({ + apiOnlyUsers: [ + { + userName, + userTags, + apiKeys: [ + { + apiKeyName, + publicKey, + }, + ], + }, + ], + }); + + const userId = refineNonNull(userIds[0]); + + // Success! + console.log( + [ + `New user created!`, + `- Name: ${userName}`, + `- User ID: ${userId}`, + ``, + ].join("\n") + ); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/sdk-server/createUserTag.ts b/examples/kitchen-sink/src/sdk-server/createUserTag.ts new file mode 100644 index 000000000..6e8751f1f --- /dev/null +++ b/examples/kitchen-sink/src/sdk-server/createUserTag.ts @@ -0,0 +1,43 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; + +import { refineNonNull } from "../utils"; + +async function main() { + // Initialize a Turnkey client + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); + + const userTagName = ""; + + const { userTagId } = await turnkeyClient.apiClient().createUserTag({ + userTagName, + userIds: [], // relevant user IDs + }); + + const newUserTagId = refineNonNull(userTagId); + + // Success! + console.log( + [ + `New user tag created!`, + `- Name: ${userTagName}`, + `- User tag ID: ${newUserTagId}`, + ``, + ].join("\n") + ); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); From 8d15b22fc1bdf5b9c3116a3f0f6d0d43e05a00d9 Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Wed, 16 Oct 2024 11:27:00 -0400 Subject: [PATCH 12/21] update nonce manager example --- examples/with-nonce-manager/package.json | 3 +- .../src/createNewEthereumPrivateKey.ts | 50 +++++++------------ .../with-nonce-manager/src/createNewWallet.ts | 45 ++++++----------- .../src/managedOptimistic.ts | 35 ++++++------- .../src/simpleSequential.ts | 27 +++++----- 5 files changed, 62 insertions(+), 98 deletions(-) diff --git a/examples/with-nonce-manager/package.json b/examples/with-nonce-manager/package.json index 98f6caf24..59401aeae 100644 --- a/examples/with-nonce-manager/package.json +++ b/examples/with-nonce-manager/package.json @@ -9,9 +9,8 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@turnkey/api-key-stamper": "workspace:^", + "@turnkey/sdk-server": "workspace:*", "@turnkey/ethers": "workspace:*", - "@turnkey/http": "workspace:*", "dotenv": "^16.0.3", "ethers": "^6.10.0" } diff --git a/examples/with-nonce-manager/src/createNewEthereumPrivateKey.ts b/examples/with-nonce-manager/src/createNewEthereumPrivateKey.ts index 45e45445f..d949276d6 100644 --- a/examples/with-nonce-manager/src/createNewEthereumPrivateKey.ts +++ b/examples/with-nonce-manager/src/createNewEthereumPrivateKey.ts @@ -1,46 +1,32 @@ -import { TurnkeyClient } from "@turnkey/http"; -import { createActivityPoller } from "@turnkey/http"; -import { ApiKeyStamper } from "@turnkey/api-key-stamper"; -import { TurnkeyActivityError } from "@turnkey/ethers"; +import { + Turnkey as TurnkeySDKServer, + TurnkeyActivityError, +} from "@turnkey/sdk-server"; import * as crypto from "crypto"; import { refineNonNull } from "./util"; export async function createNewEthereumPrivateKey() { - const turnkeyClient = new TurnkeyClient( - { baseUrl: process.env.BASE_URL! }, - new ApiKeyStamper({ - apiPublicKey: process.env.API_PUBLIC_KEY!, - apiPrivateKey: process.env.API_PRIVATE_KEY!, - }) - ); - - const activityPoller = createActivityPoller({ - client: turnkeyClient, - requestFn: turnkeyClient.createPrivateKeys, + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, }); const privateKeyName = `ETH Key ${crypto.randomBytes(2).toString("hex")}`; try { - const activity = await activityPoller({ - type: "ACTIVITY_TYPE_CREATE_PRIVATE_KEYS_V2", - organizationId: process.env.ORGANIZATION_ID!, - parameters: { - privateKeys: [ - { - privateKeyName, - curve: "CURVE_SECP256K1", - addressFormats: ["ADDRESS_FORMAT_ETHEREUM"], - privateKeyTags: [], - }, - ], - }, - timestampMs: String(Date.now()), // millisecond timestamp + const { privateKeys } = await turnkeyClient.apiClient().createPrivateKeys({ + privateKeys: [ + { + privateKeyName, + curve: "CURVE_SECP256K1", + addressFormats: ["ADDRESS_FORMAT_ETHEREUM"], + privateKeyTags: [], + }, + ], }); - const privateKeys = refineNonNull( - activity.result.createPrivateKeysResultV2?.privateKeys - ); const privateKeyId = refineNonNull(privateKeys?.[0]?.privateKeyId); const address = refineNonNull(privateKeys?.[0]?.addresses?.[0]?.address); diff --git a/examples/with-nonce-manager/src/createNewWallet.ts b/examples/with-nonce-manager/src/createNewWallet.ts index 12ffd7327..a61d83177 100644 --- a/examples/with-nonce-manager/src/createNewWallet.ts +++ b/examples/with-nonce-manager/src/createNewWallet.ts @@ -1,36 +1,24 @@ import { - TurnkeyClient, - createActivityPoller, + Turnkey as TurnkeySDKServer, TurnkeyActivityError, -} from "@turnkey/http"; -import { ApiKeyStamper } from "@turnkey/api-key-stamper"; +} from "@turnkey/sdk-server"; import * as crypto from "crypto"; import { refineNonNull } from "./util"; -export async function createNewWallet() { - console.log("creating a new wallet on Turnkey...\n"); +export async function createNewEthereumWallet() { + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); const walletName = `ETH Wallet ${crypto.randomBytes(2).toString("hex")}`; try { - const turnkeyClient = new TurnkeyClient( - { baseUrl: process.env.BASE_URL! }, - new ApiKeyStamper({ - apiPublicKey: process.env.API_PUBLIC_KEY!, - apiPrivateKey: process.env.API_PRIVATE_KEY!, - }) - ); - - const activityPoller = createActivityPoller({ - client: turnkeyClient, - requestFn: turnkeyClient.createWallet, - }); - - const completedActivity = await activityPoller({ - type: "ACTIVITY_TYPE_CREATE_WALLET", - timestampMs: String(Date.now()), - organizationId: process.env.ORGANIZATION_ID!, - parameters: { + const { walletId, addresses } = await turnkeyClient + .apiClient() + .createWallet({ walletName, accounts: [ { @@ -40,12 +28,9 @@ export async function createNewWallet() { addressFormat: "ADDRESS_FORMAT_ETHEREUM", }, ], - }, - }); + }); - const wallet = refineNonNull(completedActivity.result.createWalletResult); - const walletId = refineNonNull(wallet.walletId); - const address = refineNonNull(wallet.addresses[0]); + const address = refineNonNull(addresses[0]); // Success! console.log( @@ -55,7 +40,7 @@ export async function createNewWallet() { `- Wallet ID: ${walletId}`, `- Address: ${address}`, ``, - "Now you can take the address, put it in `.env.local` (`SIGN_WITH=
`), then re-run the script.", + "Now you can take the address, put it in `.env.local`, then re-run the script.", ].join("\n") ); } catch (error) { diff --git a/examples/with-nonce-manager/src/managedOptimistic.ts b/examples/with-nonce-manager/src/managedOptimistic.ts index a975de04a..786df0916 100644 --- a/examples/with-nonce-manager/src/managedOptimistic.ts +++ b/examples/with-nonce-manager/src/managedOptimistic.ts @@ -1,20 +1,20 @@ import * as path from "path"; import * as dotenv from "dotenv"; import * as fs from "fs"; - -// Load environment variables from `.env.local` -dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); - -import { TurnkeySigner } from "@turnkey/ethers"; import { ethers, type TransactionRequest, type Provider, type Signer, } from "ethers"; -import { TurnkeyClient } from "@turnkey/http"; -import { ApiKeyStamper } from "@turnkey/api-key-stamper"; -import { createNewWallet } from "./createNewWallet"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { TurnkeySigner } from "@turnkey/ethers"; +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; + +import { createNewEthereumWallet } from "./createNewWallet"; import { print, sleep, getUpdatedTransaction } from "./util"; import { DEFAULT_REFRESH_TIME_MS, @@ -140,23 +140,20 @@ async function monitor(provider: Provider, signer: Signer) { async function main() { if (!process.env.SIGN_WITH) { // If you don't specify a `SIGN_WITH`, we'll create a new wallet for you via calling the Turnkey API. - await createNewWallet(); + await createNewEthereumWallet(); return; } - const turnkeyClient = new TurnkeyClient( - { - baseUrl: process.env.BASE_URL!, - }, - new ApiKeyStamper({ - apiPublicKey: process.env.API_PUBLIC_KEY!, - apiPrivateKey: process.env.API_PRIVATE_KEY!, - }) - ); + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); // Initialize a Turnkey Signer const turnkeySigner = new TurnkeySigner({ - client: turnkeyClient, + client: turnkeyClient.apiClient(), organizationId: process.env.ORGANIZATION_ID!, signWith: process.env.SIGN_WITH!, }); diff --git a/examples/with-nonce-manager/src/simpleSequential.ts b/examples/with-nonce-manager/src/simpleSequential.ts index 6a688a72a..557a620c5 100644 --- a/examples/with-nonce-manager/src/simpleSequential.ts +++ b/examples/with-nonce-manager/src/simpleSequential.ts @@ -1,36 +1,33 @@ import * as path from "path"; import * as dotenv from "dotenv"; +import { ethers } from "ethers"; // Load environment variables from `.env.local` dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); import { TurnkeySigner } from "@turnkey/ethers"; -import { ethers } from "ethers"; -import { TurnkeyClient } from "@turnkey/http"; -import { ApiKeyStamper } from "@turnkey/api-key-stamper"; -import { createNewWallet } from "./createNewWallet"; +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; + +import { createNewEthereumWallet } from "./createNewWallet"; import { print } from "./util"; async function main() { if (!process.env.SIGN_WITH) { // If you don't specify a `SIGN_WITH`, we'll create a new wallet for you via calling the Turnkey API. - await createNewWallet(); + await createNewEthereumWallet(); return; } - const turnkeyClient = new TurnkeyClient( - { - baseUrl: process.env.BASE_URL!, - }, - new ApiKeyStamper({ - apiPublicKey: process.env.API_PUBLIC_KEY!, - apiPrivateKey: process.env.API_PRIVATE_KEY!, - }) - ); + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); // Initialize a Turnkey Signer const turnkeySigner = new TurnkeySigner({ - client: turnkeyClient, + client: turnkeyClient.apiClient(), organizationId: process.env.ORGANIZATION_ID!, signWith: process.env.SIGN_WITH!, }); From 9541f56436d178cca0294936a134467929b991c0 Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Wed, 16 Oct 2024 12:57:47 -0400 Subject: [PATCH 13/21] update trading runner example --- examples/trading-runner/package.json | 3 +- examples/trading-runner/src/index.ts | 87 +++++++++++-------- examples/trading-runner/src/provider.ts | 22 +++-- .../src/requests/createPolicy.ts | 39 ++++----- .../src/requests/createPrivateKey.ts | 45 ++++------ .../src/requests/createPrivateKeyTag.ts | 33 +++---- .../trading-runner/src/requests/createUser.ts | 50 +++++------ .../src/requests/createUserTag.ts | 34 +++----- .../src/requests/getPrivateKeysForTag.ts | 4 +- 9 files changed, 140 insertions(+), 177 deletions(-) diff --git a/examples/trading-runner/package.json b/examples/trading-runner/package.json index 5ec04d12c..3464f3f9b 100644 --- a/examples/trading-runner/package.json +++ b/examples/trading-runner/package.json @@ -9,9 +9,8 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@turnkey/api-key-stamper": "workspace:^", + "@turnkey/sdk-server": "workspace:*", "@turnkey/ethers": "workspace:*", - "@turnkey/http": "workspace:*", "@uniswap/sdk-core": "^3.1.1", "@uniswap/v3-core": "^1.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/examples/trading-runner/src/index.ts b/examples/trading-runner/src/index.ts index c0a9d3961..e3e204b84 100644 --- a/examples/trading-runner/src/index.ts +++ b/examples/trading-runner/src/index.ts @@ -1,13 +1,13 @@ import * as path from "path"; import * as dotenv from "dotenv"; +import prompts from "prompts"; +import { FeeData, ethers } from "ethers"; // Load environment variables from `.env.local` dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); -import { TurnkeyClient } from "@turnkey/http"; -import { ApiKeyStamper } from "@turnkey/api-key-stamper"; -import { FeeData, ethers } from "ethers"; -import prompts from "prompts"; +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; + import { isKeyOfObject, fromReadableAmount } from "./utils"; import { createPrivateKey, @@ -38,13 +38,12 @@ import { prepareV3Trade, executeTrade } from "./uniswap/base"; import { toReadableAmount } from "./utils"; // For demonstration purposes, create a globally accessible TurnkeyClient -const turnkeyClient = new TurnkeyClient( - { baseUrl: process.env.BASE_URL! }, - new ApiKeyStamper({ - apiPublicKey: process.env.API_PUBLIC_KEY!, - apiPrivateKey: process.env.API_PRIVATE_KEY!, - }) -); +const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, +}); async function main() { const args = process.argv.slice(2); @@ -106,19 +105,27 @@ main().catch((error) => { async function setup(_options: any) { // setup user tags - const adminTagId = await createUserTag(turnkeyClient, "Admin", []); - const traderTagId = await createUserTag(turnkeyClient, "Trader", []); + const adminTagId = await createUserTag( + turnkeyClient.apiClient(), + "Admin", + [] + ); + const traderTagId = await createUserTag( + turnkeyClient.apiClient(), + "Trader", + [] + ); // setup users await createUser( - turnkeyClient, + turnkeyClient.apiClient(), "Alice", [adminTagId], "Alice key", keys!.alice!.publicKey! ); await createUser( - turnkeyClient, + turnkeyClient.apiClient(), "Bob", [traderTagId], "Bob key", @@ -126,25 +133,35 @@ async function setup(_options: any) { ); // setup private key tags - const tradingTagId = await createPrivateKeyTag(turnkeyClient, "trading", []); - const personal = await createPrivateKeyTag(turnkeyClient, "personal", []); + const tradingTagId = await createPrivateKeyTag( + turnkeyClient.apiClient(), + "trading", + [] + ); + const personal = await createPrivateKeyTag( + turnkeyClient.apiClient(), + "personal", + [] + ); const longTermStorageTagId = await createPrivateKeyTag( - turnkeyClient, + turnkeyClient.apiClient(), "long-term-storage", [] ); // setup private keys - await createPrivateKey(turnkeyClient, "Trading Wallet", [tradingTagId]); - await createPrivateKey(turnkeyClient, "Long Term Storage", [ + await createPrivateKey(turnkeyClient.apiClient(), "Trading Wallet", [ + tradingTagId, + ]); + await createPrivateKey(turnkeyClient.apiClient(), "Long Term Storage", [ longTermStorageTagId, ]); - await createPrivateKey(turnkeyClient, "Personal", [personal]); + await createPrivateKey(turnkeyClient.apiClient(), "Personal", [personal]); // setup policies: grant specific users permissions to use specific private keys // ADMIN await createPolicy( - turnkeyClient, + turnkeyClient.apiClient(), "Admin users can do everything", "EFFECT_ALLOW", `approvers.any(user, user.tags.contains('${adminTagId}'))`, @@ -157,35 +174,35 @@ async function setup(_options: any) { // TRADING await createPolicy( - turnkeyClient, + turnkeyClient.apiClient(), "Traders can use trading keys to deposit, aka wrap, ETH", "EFFECT_ALLOW", `approvers.any(user, user.tags.contains('${traderTagId}'))`, `private_key.tags.contains('${tradingTagId}') && eth.tx.to == '${WETH_TOKEN_GOERLI.address}' && eth.tx.data[0..10] == '${DEPOSIT_SELECTOR}'` ); await createPolicy( - turnkeyClient, + turnkeyClient.apiClient(), "Traders can use trading keys to withdraw, aka unwrap, WETH", "EFFECT_ALLOW", `approvers.any(user, user.tags.contains('${traderTagId}'))`, `private_key.tags.contains('${tradingTagId}') && eth.tx.to == '${WETH_TOKEN_GOERLI.address}' && eth.tx.data[0..10] == '${WITHDRAW_SELECTOR}'` ); await createPolicy( - turnkeyClient, + turnkeyClient.apiClient(), "Traders can use trading keys to make ERC20 token approvals for WETH for usage with Uniswap", "EFFECT_ALLOW", `approvers.any(user, user.tags.contains('${traderTagId}'))`, `private_key.tags.contains('${tradingTagId}') && eth.tx.to == '${WETH_TOKEN_GOERLI.address}' && eth.tx.data[0..10] == '${APPROVE_SELECTOR}' && eth.tx.data[10..74] == '${paddedRouterAddress}'` ); await createPolicy( - turnkeyClient, + turnkeyClient.apiClient(), "Traders can use trading keys to make ERC20 token approvals for USDC for usage with Uniswap", "EFFECT_ALLOW", `approvers.any(user, user.tags.contains('${traderTagId}'))`, `private_key.tags.contains('${tradingTagId}') && eth.tx.to == '${USDC_TOKEN_GOERLI.address}' && eth.tx.data[0..10] == '${APPROVE_SELECTOR}' && eth.tx.data[10..74] == '${paddedRouterAddress}'` ); await createPolicy( - turnkeyClient, + turnkeyClient.apiClient(), "Traders can use trading keys to make trades using Uniswap", "EFFECT_ALLOW", `approvers.any(user, user.tags.contains('${traderTagId}'))`, @@ -195,7 +212,7 @@ async function setup(_options: any) { // SENDING // first, get long term storage address(es) const longTermStoragePrivateKey = ( - await getPrivateKeysForTag(turnkeyClient, "long-term-storage") + await getPrivateKeysForTag(turnkeyClient.apiClient(), "long-term-storage") )[0]; const longTermStorageAddress = longTermStoragePrivateKey?.addresses.find( (address: any) => { @@ -214,21 +231,21 @@ async function setup(_options: any) { .padStart(64, "0"); await createPolicy( - turnkeyClient, + turnkeyClient.apiClient(), "Traders can use trading keys to send ETH to long term storage addresses", "EFFECT_ALLOW", `approvers.any(user, user.tags.contains('${traderTagId}'))`, `private_key.tags.contains('${tradingTagId}') && eth.tx.to == '${longTermStorageAddress.address!}'` ); await createPolicy( - turnkeyClient, + turnkeyClient.apiClient(), "Traders can use trading keys to send WETH to long term storage addresses", "EFFECT_ALLOW", `approvers.any(user, user.tags.contains('${traderTagId}'))`, `private_key.tags.contains('${tradingTagId}') && eth.tx.to == '${WETH_TOKEN_GOERLI.address}' && eth.tx.data[0..10] == '${TRANSFER_SELECTOR}' && eth.tx.data[10..74] == '${paddedLongTermStorageAddress}'` ); await createPolicy( - turnkeyClient, + turnkeyClient.apiClient(), "Traders can use trading keys to send USDC to long term storage addresses", "EFFECT_ALLOW", `approvers.any(user, user.tags.contains('${traderTagId}'))`, @@ -270,7 +287,7 @@ async function trade(options: { [key: string]: string }) { async function wrapUnwrapImpl(baseAsset: string, baseAmount: string) { // find "trading" private key const tradingPrivateKey = ( - await getPrivateKeysForTag(turnkeyClient, "trading") + await getPrivateKeysForTag(turnkeyClient.apiClient(), "trading") )[0]; const provider = getProvider(); const connectedSigner = getTurnkeySigner( @@ -336,7 +353,7 @@ async function tradeImpl( ) { // find "trading" private key const tradingPrivateKey = ( - await getPrivateKeysForTag(turnkeyClient, "trading") + await getPrivateKeysForTag(turnkeyClient.apiClient(), "trading") )[0]; const provider = getProvider(); const connectedSigner = getTurnkeySigner( @@ -508,12 +525,12 @@ async function sweep(options: any) { async function sweepImpl(asset: string, destination: string, amount: string) { // find trading private keys const tradingPrivateKey = ( - await getPrivateKeysForTag(turnkeyClient, "trading") + await getPrivateKeysForTag(turnkeyClient.apiClient(), "trading") )[0]!; // find long term storage private key const longTermStoragePrivateKey = ( - await getPrivateKeysForTag(turnkeyClient, "long-term-storage") + await getPrivateKeysForTag(turnkeyClient.apiClient(), "long-term-storage") )[0]; // send from trading address to long term storage diff --git a/examples/trading-runner/src/provider.ts b/examples/trading-runner/src/provider.ts index d9cde7f68..2cdcc9a74 100644 --- a/examples/trading-runner/src/provider.ts +++ b/examples/trading-runner/src/provider.ts @@ -2,8 +2,9 @@ import * as path from "path"; import * as dotenv from "dotenv"; import { ethers } from "ethers"; import { TurnkeySigner } from "@turnkey/ethers"; -import { TurnkeyClient } from "@turnkey/http"; -import { ApiKeyStamper } from "@turnkey/api-key-stamper"; + +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; + import { Environment } from "./utils"; const DEFAULT_INFURA_COMMUNITY_KEY = "84842078b09946638c03157f83405213"; @@ -34,19 +35,16 @@ export function getTurnkeySigner( provider: ethers.Provider, signWith: string ): TurnkeySigner { - const turnkeyClient = new TurnkeyClient( - { - baseUrl: process.env.BASE_URL!, - }, - new ApiKeyStamper({ - apiPublicKey: process.env.API_PUBLIC_KEY!, - apiPrivateKey: process.env.API_PRIVATE_KEY!, - }) - ); + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); // Initialize a Turnkey Signer const turnkeySigner = new TurnkeySigner({ - client: turnkeyClient, + client: turnkeyClient.apiClient(), organizationId: process.env.ORGANIZATION_ID!, signWith, }); diff --git a/examples/trading-runner/src/requests/createPolicy.ts b/examples/trading-runner/src/requests/createPolicy.ts index 59484d85d..8d1b49640 100644 --- a/examples/trading-runner/src/requests/createPolicy.ts +++ b/examples/trading-runner/src/requests/createPolicy.ts @@ -1,43 +1,34 @@ -import type { TurnkeyClient } from "@turnkey/http"; -import { createActivityPoller, TurnkeyActivityError } from "@turnkey/http"; +import { + type TurnkeyServerClient, + TurnkeyActivityError, +} from "@turnkey/sdk-server"; + import { refineNonNull } from "./utils"; export default async function createPolicy( - turnkeyClient: TurnkeyClient, + turnkeyClient: TurnkeyServerClient, policyName: string, effect: "EFFECT_ALLOW" | "EFFECT_DENY", consensus: string, condition: string ): Promise { - const activityPoller = createActivityPoller({ - client: turnkeyClient, - requestFn: turnkeyClient.createPolicy, - }); - try { - const activity = await activityPoller({ - type: "ACTIVITY_TYPE_CREATE_POLICY_V3", - organizationId: process.env.ORGANIZATION_ID!, - parameters: { - policyName, - condition, - consensus, - effect, - notes: "", - }, - timestampMs: String(Date.now()), // millisecond timestamp + const { policyId } = await turnkeyClient.apiClient().createPolicy({ + policyName, + condition, + consensus, + effect, + notes: "", }); - const policyId = refineNonNull( - activity.result.createPolicyResult?.policyId - ); + const newPolicyId = refineNonNull(policyId); // Success! console.log( [ `New policy created!`, `- Name: ${policyName}`, - `- Policy ID: ${policyId}`, + `- Policy ID: ${newPolicyId}`, `- Effect: ${effect}`, `- Consensus: ${consensus}`, `- Condition: ${condition}`, @@ -45,7 +36,7 @@ export default async function createPolicy( ].join("\n") ); - return policyId; + return newPolicyId; } catch (error) { // If needed, you can read from `TurnkeyActivityError` to find out why the activity didn't succeed if (error instanceof TurnkeyActivityError) { diff --git a/examples/trading-runner/src/requests/createPrivateKey.ts b/examples/trading-runner/src/requests/createPrivateKey.ts index cd634d360..2c0cb2081 100644 --- a/examples/trading-runner/src/requests/createPrivateKey.ts +++ b/examples/trading-runner/src/requests/createPrivateKey.ts @@ -1,42 +1,31 @@ -import type { TurnkeyClient } from "@turnkey/http"; -import { createActivityPoller } from "@turnkey/http"; -import { TurnkeyActivityError } from "@turnkey/ethers"; +import { + type TurnkeyServerClient, + TurnkeyActivityError, +} from "@turnkey/sdk-server"; import { refineNonNull } from "./utils"; export default async function createPrivateKey( - turnkeyClient: TurnkeyClient, + turnkeyClient: TurnkeyServerClient, privateKeyName: string, privateKeyTags: string[] ): Promise { console.log("creating a new Ethereum private key on Turnkey...\n"); - const activityPoller = createActivityPoller({ - client: turnkeyClient, - requestFn: turnkeyClient.createPrivateKeys, - }); - try { - const activity = await activityPoller({ - type: "ACTIVITY_TYPE_CREATE_PRIVATE_KEYS_V2", - organizationId: process.env.ORGANIZATION_ID!, - parameters: { - privateKeys: [ - { - privateKeyName, - privateKeyTags, - curve: "CURVE_SECP256K1", - addressFormats: ["ADDRESS_FORMAT_ETHEREUM"], - }, - ], - }, - timestampMs: String(Date.now()), // millisecond timestamp + const { privateKeys } = await turnkeyClient.apiClient().createPrivateKeys({ + privateKeys: [ + { + privateKeyName, + privateKeyTags, + curve: "CURVE_SECP256K1", + addressFormats: ["ADDRESS_FORMAT_ETHEREUM"], + }, + ], }); - const privateKeys = refineNonNull( - activity.result.createPrivateKeysResultV2?.privateKeys - ); - const privateKeyId = refineNonNull(privateKeys?.[0]?.privateKeyId); - const address = refineNonNull(privateKeys?.[0]?.addresses?.[0]?.address); + const newPrivateKeys = refineNonNull(privateKeys); + const privateKeyId = refineNonNull(newPrivateKeys?.[0]?.privateKeyId); + const address = refineNonNull(newPrivateKeys?.[0]?.addresses?.[0]?.address); // Success! console.log( diff --git a/examples/trading-runner/src/requests/createPrivateKeyTag.ts b/examples/trading-runner/src/requests/createPrivateKeyTag.ts index e5a422552..f752f3e5e 100644 --- a/examples/trading-runner/src/requests/createPrivateKeyTag.ts +++ b/examples/trading-runner/src/requests/createPrivateKeyTag.ts @@ -1,44 +1,33 @@ -import type { TurnkeyClient } from "@turnkey/http"; -import { createActivityPoller } from "@turnkey/http"; -import { TurnkeyActivityError } from "@turnkey/ethers"; +import { + type TurnkeyServerClient, + TurnkeyActivityError, +} from "@turnkey/sdk-server"; import { refineNonNull } from "./utils"; export default async function createPrivateKeyTag( - turnkeyClient: TurnkeyClient, + turnkeyClient: TurnkeyServerClient, privateKeyTagName: string, privateKeyIds: string[] ): Promise { - const activityPoller = createActivityPoller({ - client: turnkeyClient, - requestFn: turnkeyClient.createPrivateKeyTag, - }); - try { - const activity = await activityPoller({ - type: "ACTIVITY_TYPE_CREATE_PRIVATE_KEY_TAG", - organizationId: process.env.ORGANIZATION_ID!, - parameters: { - privateKeyTagName, - privateKeyIds, - }, - timestampMs: String(Date.now()), // millisecond timestamp + const { privateKeyTagId } = await turnkeyClient.createPrivateKeyTag({ + privateKeyTagName, + privateKeyIds, }); - const privateKeyTagId = refineNonNull( - activity.result.createPrivateKeyTagResult?.privateKeyTagId - ); + const newPrivateKeyTagId = refineNonNull(privateKeyTagId); // Success! console.log( [ `New private key tag created!`, `- Name: ${privateKeyTagName}`, - `- Private key tag ID: ${privateKeyTagId}`, + `- Private key tag ID: ${newPrivateKeyTagId}`, ``, ].join("\n") ); - return privateKeyTagId; + return newPrivateKeyTagId; } catch (error) { // If needed, you can read from `TurnkeyActivityError` to find out why the activity didn't succeed if (error instanceof TurnkeyActivityError) { diff --git a/examples/trading-runner/src/requests/createUser.ts b/examples/trading-runner/src/requests/createUser.ts index 5fd706e1a..f18a24bc0 100644 --- a/examples/trading-runner/src/requests/createUser.ts +++ b/examples/trading-runner/src/requests/createUser.ts @@ -1,44 +1,34 @@ -import type { TurnkeyClient } from "@turnkey/http"; -import { createActivityPoller } from "@turnkey/http"; -import { TurnkeyActivityError } from "@turnkey/ethers"; +import { + type TurnkeyServerClient, + TurnkeyActivityError, +} from "@turnkey/sdk-server"; + import { refineNonNull } from "./utils"; export default async function createUser( - turnkeyClient: TurnkeyClient, + turnkeyClient: TurnkeyServerClient, userName: string, userTags: string[], apiKeyName: string, publicKey: string ): Promise { - const activityPoller = createActivityPoller({ - client: turnkeyClient, - requestFn: turnkeyClient.createApiOnlyUsers, - }); - try { - const activity = await activityPoller({ - type: "ACTIVITY_TYPE_CREATE_API_ONLY_USERS", - organizationId: process.env.ORGANIZATION_ID!, - parameters: { - apiOnlyUsers: [ - { - userName, - userTags, - apiKeys: [ - { - apiKeyName, - publicKey, - }, - ], - }, - ], - }, - timestampMs: String(Date.now()), // millisecond timestamp + const { userIds } = await turnkeyClient.apiClient().createApiOnlyUsers({ + apiOnlyUsers: [ + { + userName, + userTags, + apiKeys: [ + { + apiKeyName, + publicKey, + }, + ], + }, + ], }); - const userId = refineNonNull( - activity.result.createApiOnlyUsersResult?.userIds?.[0] - ); + const userId = refineNonNull(userIds?.[0]); // Success! console.log( diff --git a/examples/trading-runner/src/requests/createUserTag.ts b/examples/trading-runner/src/requests/createUserTag.ts index c4fcd70a9..ff96693d1 100644 --- a/examples/trading-runner/src/requests/createUserTag.ts +++ b/examples/trading-runner/src/requests/createUserTag.ts @@ -1,44 +1,34 @@ -import type { TurnkeyClient } from "@turnkey/http"; -import { createActivityPoller } from "@turnkey/http"; -import { TurnkeyActivityError } from "@turnkey/ethers"; +import { + type TurnkeyServerClient, + TurnkeyActivityError, +} from "@turnkey/sdk-server"; + import { refineNonNull } from "./utils"; export default async function createUserTag( - turnkeyClient: TurnkeyClient, + turnkeyClient: TurnkeyServerClient, userTagName: string, userIds: string[] ): Promise { - const activityPoller = createActivityPoller({ - client: turnkeyClient, - requestFn: turnkeyClient.createUserTag, - }); - try { - const activity = await activityPoller({ - type: "ACTIVITY_TYPE_CREATE_USER_TAG", - organizationId: process.env.ORGANIZATION_ID!, - parameters: { - userTagName, - userIds, - }, - timestampMs: String(Date.now()), // millisecond timestamp + const { userTagId } = await turnkeyClient.createUserTag({ + userTagName, + userIds, }); - const userTagId = refineNonNull( - activity.result.createUserTagResult?.userTagId - ); + const newUserTagId = refineNonNull(userTagId); // Success! console.log( [ `New user tag created!`, `- Name: ${userTagName}`, - `- User tag ID: ${userTagId}`, + `- User tag ID: ${newUserTagId}`, ``, ].join("\n") ); - return userTagId; + return newUserTagId; } catch (error) { // If needed, you can read from `TurnkeyActivityError` to find out why the activity didn't succeed if (error instanceof TurnkeyActivityError) { diff --git a/examples/trading-runner/src/requests/getPrivateKeysForTag.ts b/examples/trading-runner/src/requests/getPrivateKeysForTag.ts index 952d1510a..4ab3408fc 100644 --- a/examples/trading-runner/src/requests/getPrivateKeysForTag.ts +++ b/examples/trading-runner/src/requests/getPrivateKeysForTag.ts @@ -1,4 +1,4 @@ -import type { TurnkeyClient, TurnkeyApiTypes } from "@turnkey/http"; +import type { TurnkeyServerClient, TurnkeyApiTypes } from "@turnkey/sdk-server"; /** * Get a list of private keys for a given tag @@ -7,7 +7,7 @@ import type { TurnkeyClient, TurnkeyApiTypes } from "@turnkey/http"; * @returns a list of private keys matching the passed in tag */ export default async function getPrivateKeysForTag( - turnkeyClient: TurnkeyClient, + turnkeyClient: TurnkeyServerClient, tagName: string ): Promise { const response = await turnkeyClient.listPrivateKeyTags({ From a5597eaffa3d6398026564f7b747fa8b6beca45a Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Wed, 16 Oct 2024 13:09:57 -0400 Subject: [PATCH 14/21] update rebalancer example --- examples/rebalancer/package.json | 2 -- examples/rebalancer/src/provider.ts | 22 ++++++++++------------ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/examples/rebalancer/package.json b/examples/rebalancer/package.json index 84b5d2ae9..eebe5c7eb 100644 --- a/examples/rebalancer/package.json +++ b/examples/rebalancer/package.json @@ -9,9 +9,7 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@turnkey/api-key-stamper": "workspace:^", "@turnkey/ethers": "workspace:*", - "@turnkey/http": "workspace:*", "@turnkey/sdk-server": "workspace:*", "dotenv": "^16.0.3", "ethers": "^6.10.0" diff --git a/examples/rebalancer/src/provider.ts b/examples/rebalancer/src/provider.ts index 08653d169..6fd008594 100644 --- a/examples/rebalancer/src/provider.ts +++ b/examples/rebalancer/src/provider.ts @@ -1,9 +1,10 @@ import * as path from "path"; import * as dotenv from "dotenv"; import { ethers } from "ethers"; + import { TurnkeySigner } from "@turnkey/ethers"; -import { TurnkeyClient } from "@turnkey/http"; -import { ApiKeyStamper } from "@turnkey/api-key-stamper"; +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; + import { Environment } from "./utils"; const DEFAULT_INFURA_COMMUNITY_KEY = "84842078b09946638c03157f83405213"; @@ -34,20 +35,17 @@ export function getTurnkeySigner( provider: ethers.Provider, signWith: string ): TurnkeySigner { - const turnkeyClient = new TurnkeyClient( - { - baseUrl: process.env.BASE_URL!, - }, - new ApiKeyStamper({ - apiPublicKey: process.env.API_PUBLIC_KEY!, - apiPrivateKey: process.env.API_PRIVATE_KEY!, - }) - ); + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); // Initialize a Turnkey Signer // TODO: Update this once @turnkey/ethers supports sdk-server types const turnkeySigner = new TurnkeySigner({ - client: turnkeyClient, + client: turnkeyClient.apiClient(), organizationId: process.env.ORGANIZATION_ID!, signWith, }); From 789c7949894091e3d80e42ade7dac80037ff2076 Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Wed, 16 Oct 2024 13:10:04 -0400 Subject: [PATCH 15/21] update sweeper example --- examples/sweeper/package.json | 3 +-- examples/sweeper/src/provider.ts | 28 +++++++++++++--------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/examples/sweeper/package.json b/examples/sweeper/package.json index 64e0940a8..a14849a64 100644 --- a/examples/sweeper/package.json +++ b/examples/sweeper/package.json @@ -8,9 +8,8 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@turnkey/api-key-stamper": "workspace:*", + "@turnkey/sdk-server": "workspace:*", "@turnkey/ethers": "workspace:*", - "@turnkey/http": "workspace:*", "@uniswap/sdk-core": "^3.1.1", "dotenv": "^16.0.3", "ethers": "^6.10.0", diff --git a/examples/sweeper/src/provider.ts b/examples/sweeper/src/provider.ts index f9e5fc2fd..c9dafd0a7 100644 --- a/examples/sweeper/src/provider.ts +++ b/examples/sweeper/src/provider.ts @@ -1,17 +1,18 @@ import * as path from "path"; import * as dotenv from "dotenv"; import { ethers } from "ethers"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + import { TurnkeySigner } from "@turnkey/ethers"; -import { TurnkeyClient } from "@turnkey/http"; -import { ApiKeyStamper } from "@turnkey/api-key-stamper"; +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; + import { Environment } from "./utils"; const DEFAULT_INFURA_COMMUNITY_KEY = "84842078b09946638c03157f83405213"; const DEFAULT_ENV = Environment.GOERLI; -// Load environment variables from `.env.local` -dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); - let provider = new ethers.InfuraProvider( DEFAULT_ENV, process.env.INFURA_KEY || DEFAULT_INFURA_COMMUNITY_KEY @@ -31,19 +32,16 @@ export function getProvider(env = Environment.GOERLI): ethers.Provider { // getTurnkeySigner returns a TurnkeySigner connected to the passed-in Provider // (https://docs.ethers.org/v6/api/providers/) export function getTurnkeySigner(provider: ethers.Provider): TurnkeySigner { - const turnkeyClient = new TurnkeyClient( - { - baseUrl: process.env.BASE_URL!, - }, - new ApiKeyStamper({ - apiPublicKey: process.env.API_PUBLIC_KEY!, - apiPrivateKey: process.env.API_PRIVATE_KEY!, - }) - ); + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); // Initialize a Turnkey Signer const turnkeySigner = new TurnkeySigner({ - client: turnkeyClient, + client: turnkeyClient.apiClient(), organizationId: process.env.ORGANIZATION_ID!, signWith: process.env.SIGN_WITH!, }); From 3d7b7cba80f9165266574760d841fc0ff8eded4d Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Wed, 16 Oct 2024 13:10:25 -0400 Subject: [PATCH 16/21] update uniswap example --- examples/with-uniswap/package.json | 3 +-- examples/with-uniswap/src/provider.ts | 22 ++++++++++------------ 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/examples/with-uniswap/package.json b/examples/with-uniswap/package.json index ac2b95a2e..d911c6672 100644 --- a/examples/with-uniswap/package.json +++ b/examples/with-uniswap/package.json @@ -8,9 +8,8 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@turnkey/api-key-stamper": "workspace:*", + "@turnkey/sdk-server": "workspace:*", "@turnkey/ethers": "workspace:*", - "@turnkey/http": "workspace:*", "@uniswap/sdk-core": "^3.1.1", "@uniswap/v3-core": "^1.0.1", "@uniswap/v3-sdk": "^3.9.0", diff --git a/examples/with-uniswap/src/provider.ts b/examples/with-uniswap/src/provider.ts index 03556e6dc..e3ad83687 100644 --- a/examples/with-uniswap/src/provider.ts +++ b/examples/with-uniswap/src/provider.ts @@ -1,9 +1,10 @@ import * as path from "path"; import * as dotenv from "dotenv"; import { ethers, type Provider } from "ethers"; + import { TurnkeySigner } from "@turnkey/ethers"; -import { TurnkeyClient } from "@turnkey/http"; -import { ApiKeyStamper } from "@turnkey/api-key-stamper"; +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; + import { Environment } from "./constants"; const DEFAULT_INFURA_COMMUNITY_KEY = "84842078b09946638c03157f83405213"; @@ -31,19 +32,16 @@ export function getProvider(env = Environment.GOERLI): Provider { // getTurnkeySigner returns a TurnkeySigner connected to the passed-in Provider // (https://docs.ethers.org/v6/api/providers/) export function getTurnkeySigner(provider: ethers.Provider): TurnkeySigner { - const turnkeyClient = new TurnkeyClient( - { - baseUrl: process.env.BASE_URL!, - }, - new ApiKeyStamper({ - apiPublicKey: process.env.API_PUBLIC_KEY!, - apiPrivateKey: process.env.API_PRIVATE_KEY!, - }) - ); + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); // Initialize a Turnkey Signer const turnkeySigner = new TurnkeySigner({ - client: turnkeyClient, + client: turnkeyClient.apiClient(), organizationId: process.env.ORGANIZATION_ID!, signWith: process.env.SIGN_WITH!, }); From c87df787702a413bb5590c2a727dcf67b79557f3 Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Wed, 16 Oct 2024 11:27:04 -0400 Subject: [PATCH 17/21] update pnpm lock --- pnpm-lock.yaml | 44 ++++++++++---------------------------------- 1 file changed, 10 insertions(+), 34 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e3c114400..388a5c085 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -66,9 +66,6 @@ importers: '@turnkey/ethers': specifier: workspace:* version: link:../../packages/ethers - '@turnkey/http': - specifier: workspace:* - version: link:../../packages/http '@turnkey/sdk-server': specifier: workspace:* version: link:../../packages/sdk-server @@ -401,15 +398,9 @@ importers: examples/rebalancer: dependencies: - '@turnkey/api-key-stamper': - specifier: workspace:^ - version: link:../../packages/api-key-stamper '@turnkey/ethers': specifier: workspace:* version: link:../../packages/ethers - '@turnkey/http': - specifier: workspace:* - version: link:../../packages/http '@turnkey/sdk-server': specifier: workspace:* version: link:../../packages/sdk-server @@ -422,15 +413,12 @@ importers: examples/sweeper: dependencies: - '@turnkey/api-key-stamper': - specifier: workspace:* - version: link:../../packages/api-key-stamper '@turnkey/ethers': specifier: workspace:* version: link:../../packages/ethers - '@turnkey/http': + '@turnkey/sdk-server': specifier: workspace:* - version: link:../../packages/http + version: link:../../packages/sdk-server '@uniswap/sdk-core': specifier: ^3.1.1 version: 3.1.1 @@ -453,15 +441,12 @@ importers: examples/trading-runner: dependencies: - '@turnkey/api-key-stamper': - specifier: workspace:^ - version: link:../../packages/api-key-stamper '@turnkey/ethers': specifier: workspace:* version: link:../../packages/ethers - '@turnkey/http': + '@turnkey/sdk-server': specifier: workspace:* - version: link:../../packages/http + version: link:../../packages/sdk-server '@uniswap/sdk-core': specifier: ^3.1.1 version: 3.1.1 @@ -917,15 +902,12 @@ importers: '@safe-global/safe-ethers-lib': specifier: ^1.9.2 version: 1.9.2 - '@turnkey/api-key-stamper': - specifier: workspace:^ - version: link:../../packages/api-key-stamper '@turnkey/ethers': specifier: workspace:* version: link:../../packages/ethers - '@turnkey/http': + '@turnkey/sdk-server': specifier: workspace:* - version: link:../../packages/http + version: link:../../packages/sdk-server dotenv: specifier: ^16.0.3 version: 16.0.3 @@ -935,15 +917,12 @@ importers: examples/with-nonce-manager: dependencies: - '@turnkey/api-key-stamper': - specifier: workspace:^ - version: link:../../packages/api-key-stamper '@turnkey/ethers': specifier: workspace:* version: link:../../packages/ethers - '@turnkey/http': + '@turnkey/sdk-server': specifier: workspace:* - version: link:../../packages/http + version: link:../../packages/sdk-server dotenv: specifier: ^16.0.3 version: 16.0.3 @@ -1133,15 +1112,12 @@ importers: examples/with-uniswap: dependencies: - '@turnkey/api-key-stamper': - specifier: workspace:* - version: link:../../packages/api-key-stamper '@turnkey/ethers': specifier: workspace:* version: link:../../packages/ethers - '@turnkey/http': + '@turnkey/sdk-server': specifier: workspace:* - version: link:../../packages/http + version: link:../../packages/sdk-server '@uniswap/sdk-core': specifier: ^3.1.1 version: 3.1.1 From 9071734cd02bbd1d09511fe1282cbb00d8f2415a Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Wed, 16 Oct 2024 16:23:29 -0400 Subject: [PATCH 18/21] add createApiKey to kitchen sink --- .../kitchen-sink/src/http/createApiKey.ts | 68 +++++++++++++++++++ .../src/sdk-server/createApiKey.ts | 52 ++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 examples/kitchen-sink/src/http/createApiKey.ts create mode 100644 examples/kitchen-sink/src/sdk-server/createApiKey.ts diff --git a/examples/kitchen-sink/src/http/createApiKey.ts b/examples/kitchen-sink/src/http/createApiKey.ts new file mode 100644 index 000000000..54240721d --- /dev/null +++ b/examples/kitchen-sink/src/http/createApiKey.ts @@ -0,0 +1,68 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { TurnkeyClient, createActivityPoller } from "@turnkey/http"; +import { ApiKeyStamper } from "@turnkey/api-key-stamper"; +import { refineNonNull } from "../utils"; + +async function main() { + console.log("creating a new private key on Turnkey...\n"); + + const turnkeyClient = new TurnkeyClient( + { baseUrl: process.env.BASE_URL! }, + new ApiKeyStamper({ + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + }) + ); + + const activityPoller = createActivityPoller({ + client: turnkeyClient, + requestFn: turnkeyClient.createApiKeys, + }); + + const userId = ""; + const apiKeyName = ""; + const publicKey = ""; + const curveType = "API_KEY_CURVE_P256"; // this is the default + + const activity = await activityPoller({ + type: "ACTIVITY_TYPE_CREATE_API_KEYS_V2", + organizationId: process.env.ORGANIZATION_ID!, + parameters: { + userId, + apiKeys: [ + { + apiKeyName, + publicKey, + curveType, + }, + ], + }, + timestampMs: String(Date.now()), // millisecond timestamp + }); + + const newApiKeyIds = refineNonNull( + activity.result.createApiKeysResult?.apiKeyIds + ); + + // Success! + console.log( + [ + `New API key created!`, + `- ID: ${newApiKeyIds[0]}`, + `- Public Key: ${publicKey}`, + `- Name: ${apiKeyName}`, + `- User ID: ${userId}`, + ``, + ].join("\n") + ); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/kitchen-sink/src/sdk-server/createApiKey.ts b/examples/kitchen-sink/src/sdk-server/createApiKey.ts new file mode 100644 index 000000000..f78d4c2b3 --- /dev/null +++ b/examples/kitchen-sink/src/sdk-server/createApiKey.ts @@ -0,0 +1,52 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +import { Turnkey as TurnkeySDKServer } from "@turnkey/sdk-server"; + +import { refineNonNull } from "../utils"; + +async function main() { + // Initialize a Turnkey client + const turnkeyClient = new TurnkeySDKServer({ + apiBaseUrl: "https://api.turnkey.com", + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + defaultOrganizationId: process.env.ORGANIZATION_ID!, + }); + + const userId = ""; + const apiKeyName = "" + const publicKey = "" + const curveType = "API_KEY_CURVE_P256" // this is the default + + const { apiKeyIds } = await turnkeyClient.apiClient().createApiKeys({ + userId, + apiKeys: [{ + apiKeyName, + publicKey, + curveType + }] + }); + + const newApiKeyIds = refineNonNull(apiKeyIds); + + // Success! + console.log( + [ + `New API key created!`, + `- ID: ${newApiKeyIds[0]}`, + `- Public Key: ${publicKey}`, + `- Name: ${apiKeyName}`, + `- User ID: ${userId}`, + ``, + ].join("\n") + ); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); From 57bcd4e7cd92cabc4a8fc8e30f0e90b56ca869ec Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Wed, 16 Oct 2024 16:23:37 -0400 Subject: [PATCH 19/21] remove unnecessary client file --- examples/kitchen-sink/sdkServerClient.ts | 48 ------------------------ 1 file changed, 48 deletions(-) delete mode 100644 examples/kitchen-sink/sdkServerClient.ts diff --git a/examples/kitchen-sink/sdkServerClient.ts b/examples/kitchen-sink/sdkServerClient.ts deleted file mode 100644 index 7b09a7f66..000000000 --- a/examples/kitchen-sink/sdkServerClient.ts +++ /dev/null @@ -1,48 +0,0 @@ -import * as path from "path"; -import * as dotenv from "dotenv"; - -// Load environment variables from `.env.local` -dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); - -import { Turnkey as TurnkeyServerSDK } from "@turnkey/sdk-server"; - -async function main() { - // Initialize a Turnkey client - const turnkeyClient = new TurnkeyServerSDK({ - apiBaseUrl: process.env.BASE_URL!, - apiPrivateKey: process.env.API_PRIVATE_KEY!, - apiPublicKey: process.env.API_PUBLIC_KEY!, - defaultOrganizationId: process.env.ORGANIZATION_ID!, - }); - - const usersResponse = await turnkeyClient.apiClient().getUsers(); - const whoamiResponse = await turnkeyClient.apiClient().getWhoami(); - const orgConfigsResponse = await turnkeyClient - .apiClient() - .getOrganizationConfigs({ - organizationId: process.env.ORGANIZATION_ID!, - }); - - await turnkeyClient.apiClient().updateRootQuorum({ - threshold: 1, - userIds: [orgConfigsResponse.configs.quorum?.userIds[0]!], // retain the first root user, which would be the passkey user - }); - - const updatedOrgConfigsResponse = await turnkeyClient - .apiClient() - .getOrganizationConfigs({ - organizationId: process.env.ORGANIZATION_ID!, - }); - - console.log({ - users: usersResponse.users, - whoami: whoamiResponse, - rootQuorum: orgConfigsResponse.configs.quorum, - updatedRootQuorum: updatedOrgConfigsResponse.configs.quorum, - }); -} - -main().catch((error) => { - console.error(error); - process.exit(1); -}); From 7eea49fab8e3c2242ad39fde16cfd41cdd5d738d Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Wed, 16 Oct 2024 17:08:12 -0400 Subject: [PATCH 20/21] feedback: prettier --- .../kitchen-sink/src/sdk-server/createApiKey.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/kitchen-sink/src/sdk-server/createApiKey.ts b/examples/kitchen-sink/src/sdk-server/createApiKey.ts index f78d4c2b3..5390b0f01 100644 --- a/examples/kitchen-sink/src/sdk-server/createApiKey.ts +++ b/examples/kitchen-sink/src/sdk-server/createApiKey.ts @@ -18,17 +18,19 @@ async function main() { }); const userId = ""; - const apiKeyName = "" - const publicKey = "" - const curveType = "API_KEY_CURVE_P256" // this is the default + const apiKeyName = ""; + const publicKey = ""; + const curveType = "API_KEY_CURVE_P256"; // this is the default const { apiKeyIds } = await turnkeyClient.apiClient().createApiKeys({ userId, - apiKeys: [{ + apiKeys: [ + { apiKeyName, publicKey, - curveType - }] + curveType, + }, + ], }); const newApiKeyIds = refineNonNull(apiKeyIds); From 41d84d399d265be8eea11525f442e0f1f354554f Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Wed, 16 Oct 2024 17:10:29 -0400 Subject: [PATCH 21/21] feedback: restore sign_with tip --- examples/deployer/src/createNewWallet.ts | 2 +- examples/with-nonce-manager/src/createNewWallet.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/deployer/src/createNewWallet.ts b/examples/deployer/src/createNewWallet.ts index ef31988d9..f662ce3f4 100644 --- a/examples/deployer/src/createNewWallet.ts +++ b/examples/deployer/src/createNewWallet.ts @@ -37,7 +37,7 @@ export async function createNewWallet() { `- Wallet ID: ${walletId}`, `- Address: ${address}`, ``, - "Now you can take the address, put it in `.env.local`, then re-run the script.", + "Now you can take the address, put it in `.env.local` (`SIGN_WITH=
`), then re-run the script.", ].join("\n") ); } catch (err: any) { diff --git a/examples/with-nonce-manager/src/createNewWallet.ts b/examples/with-nonce-manager/src/createNewWallet.ts index a61d83177..73f1345df 100644 --- a/examples/with-nonce-manager/src/createNewWallet.ts +++ b/examples/with-nonce-manager/src/createNewWallet.ts @@ -40,7 +40,7 @@ export async function createNewEthereumWallet() { `- Wallet ID: ${walletId}`, `- Address: ${address}`, ``, - "Now you can take the address, put it in `.env.local`, then re-run the script.", + "Now you can take the address, put it in `.env.local` (`SIGN_WITH=
`), then re-run the script.", ].join("\n") ); } catch (error) {