From b3e396aba660e03a441bc5dcb29d4709d78a04a9 Mon Sep 17 00:00:00 2001 From: Andrew Min Date: Sat, 16 Sep 2023 17:15:36 -0400 Subject: [PATCH] updated examples --- examples/with-viem/package.json | 1 + examples/with-viem/src/advanced.ts | 128 +++++++++++++++++++++++++++++ examples/with-viem/src/index.ts | 23 ++++-- examples/with-viem/src/util.ts | 9 ++ 4 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 examples/with-viem/src/advanced.ts create mode 100644 examples/with-viem/src/util.ts diff --git a/examples/with-viem/package.json b/examples/with-viem/package.json index 862f1998f..949683f74 100644 --- a/examples/with-viem/package.json +++ b/examples/with-viem/package.json @@ -4,6 +4,7 @@ "private": true, "scripts": { "start": "pnpm -w run build-all && tsx src/index.ts", + "start-advanced": "pnpm -w run build-all && tsx src/advanced.ts", "clean": "rimraf ./dist ./.cache", "typecheck": "tsc --noEmit" }, diff --git a/examples/with-viem/src/advanced.ts b/examples/with-viem/src/advanced.ts new file mode 100644 index 000000000..d49790bd2 --- /dev/null +++ b/examples/with-viem/src/advanced.ts @@ -0,0 +1,128 @@ +import * as path from "path"; +import * as dotenv from "dotenv"; + +import { createAccount } from "@turnkey/viem"; +import { TurnkeyClient } from "@turnkey/http"; +import { ApiKeyStamper } from "@turnkey/api-key-stamper"; +import { + createWalletClient, + http, + recoverMessageAddress, + recoverTypedDataAddress, + stringToHex, + hexToBytes, + type Account, +} from "viem"; +import { sepolia } from "viem/chains"; +import { print, assertEqual } from "./util"; + +// Load environment variables from `.env.local` +dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); + +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!, + }) + ); + + const turnkeyAccount = await createAccount({ + client: turnkeyClient, + organizationId: process.env.ORGANIZATION_ID!, + privateKeyId: process.env.PRIVATE_KEY_ID!, + }); + + 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; + 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, + domain, + types, + primaryType: "Mail", + message: { + from: { + name: "Cow", + wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", + }, + to: { + name: "Bob", + wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB", + }, + contents: "Hello, Bob!", + }, + } as const; + + signature = await client.signTypedData(typedData); + recoveredAddress = await recoverTypedDataAddress({ + ...typedData, + signature, + }); + + print("Turnkey-powered signature - typed data:", `${signature}`); + assertEqual(address, recoveredAddress); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/examples/with-viem/src/index.ts b/examples/with-viem/src/index.ts index 146aec83f..60f1908d5 100644 --- a/examples/with-viem/src/index.ts +++ b/examples/with-viem/src/index.ts @@ -4,8 +4,9 @@ import * as dotenv from "dotenv"; import { createAccount } from "@turnkey/viem"; import { TurnkeyClient } from "@turnkey/http"; import { ApiKeyStamper } from "@turnkey/api-key-stamper"; -import { createWalletClient, http } from "viem"; +import { createWalletClient, http, recoverMessageAddress } from "viem"; import { sepolia } from "viem/chains"; +import { print, assertEqual } from "./util"; // Load environment variables from `.env.local` dotenv.config({ path: path.resolve(process.cwd(), ".env.local") }); @@ -38,6 +39,7 @@ async function main() { // This demo sends ETH back to our faucet (we keep a bunch of Sepolia ETH at this address) const turnkeyFaucet = "0x08d2b0a37F869FF76BACB5Bab3278E26ab7067B7"; + // 1. Simple send tx const transactionRequest = { to: turnkeyFaucet as `0x${string}`, value: 1000000000000000n, @@ -47,13 +49,24 @@ async function main() { print("Source address", client.account.address); print("Transaction", `https://sepolia.etherscan.io/tx/${txHash}`); + + // 2. Sign a simple message + let address = client.account.address; + let message = "Hello Turnkey"; + let signature = await client.signMessage({ + message, + }); + let recoveredAddress = await recoverMessageAddress({ + message, + signature, + }); + + print("Turnkey-powered signature:", `${signature}`); + print("Recovered address:", `${recoveredAddress}`); + assertEqual(address, recoveredAddress); } main().catch((error) => { console.error(error); process.exit(1); }); - -function print(header: string, body: string): void { - console.log(`${header}\n\t${body}\n`); -} diff --git a/examples/with-viem/src/util.ts b/examples/with-viem/src/util.ts new file mode 100644 index 000000000..de3641621 --- /dev/null +++ b/examples/with-viem/src/util.ts @@ -0,0 +1,9 @@ +export function print(header: string, body: string): void { + console.log(`${header}\n\t${body}\n`); +} + +export function assertEqual(left: T, right: T) { + if (left !== right) { + throw new Error(`${JSON.stringify(left)} !== ${JSON.stringify(right)}`); + } +}