From 8eed436134350e4a1a95b082dcae455b90fed2f2 Mon Sep 17 00:00:00 2001 From: crStiv Date: Sun, 2 Feb 2025 02:20:02 +0100 Subject: [PATCH 1/2] Update package.json --- examples/with-viem/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/with-viem/package.json b/examples/with-viem/package.json index b96b10d2a..3bfd03660 100644 --- a/examples/with-viem/package.json +++ b/examples/with-viem/package.json @@ -19,11 +19,11 @@ "@turnkey/sdk-server": "workspace:*", "@turnkey/viem": "workspace:*", "dotenv": "^16.0.3", - "fetch": "^1.1.0", "prompts": "^2.4.2", - "viem": "^1.16.6" + "viem": "^2.0.0" }, "devDependencies": { + "@types/node": "^20.0.0", "@types/prompts": "^2.4.2", "typescript": "^5.1.3" } From 11ef166dcdb928b639f7502d870cb93d6a64bc6c Mon Sep 17 00:00:00 2001 From: crStiv Date: Sun, 2 Feb 2025 02:21:39 +0100 Subject: [PATCH 2/2] Update advanced.ts --- examples/with-viem/src/advanced.ts | 239 ++++++++++++++++------------- 1 file changed, 134 insertions(+), 105 deletions(-) diff --git a/examples/with-viem/src/advanced.ts b/examples/with-viem/src/advanced.ts index 7207e755a..821be299c 100644 --- a/examples/with-viem/src/advanced.ts +++ b/examples/with-viem/src/advanced.ts @@ -20,115 +20,144 @@ import { createNewWallet } from "./createNewWallet"; // Load environment variables from `.env.local` dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); -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(); - return; - } - - const turnkeyClient = new TurnkeyClient( - { - baseUrl: process.env.BASE_URL!, - }, - new ApiKeyStamper({ - apiPublicKey: process.env.API_PUBLIC_KEY!, - apiPrivateKey: process.env.API_PRIVATE_KEY!, - }), +// Validate required environment variables +const requiredEnvVars = [ + "BASE_URL", + "API_PUBLIC_KEY", + "API_PRIVATE_KEY", + "ORGANIZATION_ID", + "INFURA_API_KEY" +]; + +function validateEnvVars() { + const missing = requiredEnvVars.filter( + (envVar) => !process.env[envVar] ); + + if (missing.length > 0) { + throw new Error( + `Missing required environment variables: ${missing.join(", ")}\n` + + "Please check your .env.local file and ensure all required variables are set." + ); + } +} - const turnkeyAccount = await createAccount({ - client: turnkeyClient, - organizationId: process.env.ORGANIZATION_ID!, - signWith: process.env.SIGN_WITH!, - }); - - const client = createWalletClient({ - account: turnkeyAccount as Account, - chain: sepolia, - transport: http( - `https://sepolia.infura.io/v3/${process.env.INFURA_API_KEY!}`, - ), - }); - - const address = client.account.address; - print("Address:", address); - - const baseMessage = "Hello Turnkey"; - - // 1. Sign a raw hex message - const hexMessage = { raw: stringToHex(baseMessage) }; - let signature = await client.signMessage({ - message: hexMessage, - }); - let recoveredAddress = await recoverMessageAddress({ - message: hexMessage, - signature, - }); - - print("Turnkey-powered signature - raw hex message:", `${signature}`); - assertEqual(address, recoveredAddress); - - // 2. Sign a raw bytes message - const bytesMessage = { raw: hexToBytes(stringToHex(baseMessage)) }; - signature = await client.signMessage({ - message: bytesMessage, - }); - recoveredAddress = await recoverMessageAddress({ - message: bytesMessage, - signature, - }); - - print("Turnkey-powered signature - raw bytes message:", `${signature}`); - assertEqual(address, recoveredAddress); - - // 3. Sign typed data (EIP-712) - const domain = { - name: "Ether Mail", - version: "1", - chainId: 1, - verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", - } as const; - - // The named list of all type definitions - const types = { - Person: [ - { name: "name", type: "string" }, - { name: "wallet", type: "address" }, - ], - Mail: [ - { name: "from", type: "Person" }, - { name: "to", type: "Person" }, - { name: "contents", type: "string" }, - ], - } as const; - - const typedData = { - account: turnkeyAccount as Account, - domain, - types, - primaryType: "Mail", - message: { - from: { - name: "Cow", - wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", +async function main() { + try { + validateEnvVars(); + + 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(); + return; + } + + const turnkeyClient = new TurnkeyClient( + { + baseUrl: process.env.BASE_URL!, }, - to: { - name: "Bob", - wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB", + new ApiKeyStamper({ + apiPublicKey: process.env.API_PUBLIC_KEY!, + apiPrivateKey: process.env.API_PRIVATE_KEY!, + }), + ); + + const turnkeyAccount = await createAccount({ + client: turnkeyClient, + organizationId: process.env.ORGANIZATION_ID!, + signWith: process.env.SIGN_WITH!, + }); + + const client = createWalletClient({ + account: turnkeyAccount as Account, + chain: sepolia, + transport: http( + `https://sepolia.infura.io/v3/${process.env.INFURA_API_KEY!}`, + ), + }); + + const address = client.account.address; + print("Address:", address); + + const baseMessage = "Hello Turnkey"; + + // 1. Sign a raw hex message + const hexMessage = { raw: stringToHex(baseMessage) }; + let signature = await client.signMessage({ + message: hexMessage, + }); + let recoveredAddress = await recoverMessageAddress({ + message: hexMessage, + signature, + }); + + print("Turnkey-powered signature - raw hex message:", `${signature}`); + assertEqual(address, recoveredAddress); + + // 2. Sign a raw bytes message + const bytesMessage = { raw: hexToBytes(stringToHex(baseMessage)) }; + signature = await client.signMessage({ + message: bytesMessage, + }); + recoveredAddress = await recoverMessageAddress({ + message: bytesMessage, + signature, + }); + + print("Turnkey-powered signature - raw bytes message:", `${signature}`); + assertEqual(address, recoveredAddress); + + // 3. Sign typed data (EIP-712) + const domain = { + name: "Ether Mail", + version: "1", + chainId: 1, + verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", + } as const; + + // The named list of all type definitions + const types = { + Person: [ + { name: "name", type: "string" }, + { name: "wallet", type: "address" }, + ], + Mail: [ + { name: "from", type: "Person" }, + { name: "to", type: "Person" }, + { name: "contents", type: "string" }, + ], + } as const; + + const typedData = { + account: turnkeyAccount as Account, + domain, + types, + primaryType: "Mail", + message: { + from: { + name: "Cow", + wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", + }, + to: { + name: "Bob", + wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB", + }, + contents: "Hello, Bob!", }, - contents: "Hello, Bob!", - }, - } as const; - - signature = await client.signTypedData(typedData); - recoveredAddress = await recoverTypedDataAddress({ - ...typedData, - signature, - }); - - print("Turnkey-powered signature - typed data (EIP-712):", `${signature}`); - assertEqual(address, recoveredAddress); + } as const; + + signature = await client.signTypedData(typedData); + recoveredAddress = await recoverTypedDataAddress({ + ...typedData, + signature, + }); + + print("Turnkey-powered signature - typed data (EIP-712):", `${signature}`); + assertEqual(address, recoveredAddress); + } catch (error) { + console.error(error); + process.exit(1); + } } main().catch((error) => {