Skip to content

Commit

Permalink
Merge pull-request #195
Browse files Browse the repository at this point in the history
  • Loading branch information
r-n-o committed Jan 18, 2024
2 parents 43e9c18 + 9b20af6 commit a209220
Show file tree
Hide file tree
Showing 25 changed files with 616 additions and 173 deletions.
1 change: 1 addition & 0 deletions .codesandbox/ci.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"packages/cosmjs",
"packages/ethers",
"packages/http",
"packages/solana",
"packages/viem",
"packages/webauthn-stamper",
"packages/api-key-stamper",
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ typings/
.env
.env.*
!.env.local.example
!.env.test.example
!.env.example

# parcel-bundler cache (https://parceljs.org/)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ API Docs: https://docs.turnkey.com/
| [`@turnkey/ethers`](/packages/ethers) | [![npm](https://img.shields.io/npm/v/@turnkey/ethers?color=%234C48FF)](https://www.npmjs.com/package/@turnkey/ethers) | Turnkey Signer for Ethers | [CHANGELOG](/packages/ethers/CHANGELOG.md) |
| [`@turnkey/viem`](/packages/viem) | [![npm](https://img.shields.io/npm/v/@turnkey/viem?color=%234C48FF)](https://www.npmjs.com/package/@turnkey/viem) | (Experimental) Turnkey Helpers to work with Viem | [CHANGELOG](/packages/viem/CHANGELOG.md) |
| [`@turnkey/cosmjs`](/packages/cosmjs) | [![npm](https://img.shields.io/npm/v/@turnkey/cosmjs?color=%234C48FF)](https://www.npmjs.com/package/@turnkey/cosmjs) | (Experimental) Turnkey Cosmos Signer for CosmJS | [CHANGELOG](/packages/cosmjs/CHANGELOG.md) |
| [`@turnkey/solana`](/packages/solana) | [![npm](https://img.shields.io/npm/v/@turnkey/solana?color=%234C48FF)](https://www.npmjs.com/package/@turnkey/solana) | (Experimental) Turnkey Signer for Solana | [CHANGELOG](/packages/solana/CHANGELOG.md) |
| [`@turnkey/http`](/packages/http) | [![npm](https://img.shields.io/npm/v/@turnkey/http?color=%234C48FF)](https://www.npmjs.com/package/@turnkey/http) | Lower-level, fully typed HTTP client for interacting with Turnkey API | [CHANGELOG](/packages/http/CHANGELOG.md) |
| [`@turnkey/api-key-stamper`](/packages/api-key-stamper) | [![npm](https://img.shields.io/npm/v/@turnkey/api-key-stamper?color=%234C48FF)](https://www.npmjs.com/package/@turnkey/api-key-stamper) | Provide API key signatures over Turnkey requests | [CHANGELOG](/packages/api-key-stamper/CHANGELOG.md) |
| [`@turnkey/iframe-stamper`](/packages/iframe-stamper) | [![npm](https://img.shields.io/npm/v/@turnkey/iframe-stamper?color=%234C48FF)](https://www.npmjs.com/package/@turnkey/iframe-stamper) | Provide API key signatures over Turnkey requests within iframe contexts | [CHANGELOG](/packages/iframe-stamper/CHANGELOG.md) |
Expand Down
2 changes: 1 addition & 1 deletion examples/with-solana/.env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ API_PUBLIC_KEY="<Turnkey API Public Key (that starts with 02 or 03)>"
API_PRIVATE_KEY="<Turnkey API Private Key>"
BASE_URL="https://api.turnkey.com"
ORGANIZATION_ID="<Turnkey organization ID>"
PRIVATE_KEY_ID="<(optional) Turnkey (crypto) Private Key ID>"
SOLANA_ADDRESS="<(optional) If you want to use an existing Solana address in your organization, put it here!>"
32 changes: 16 additions & 16 deletions examples/with-solana/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

This example walks through the following:

- Creation of a new Turnkey private key
- Derivation of a new Solana address
- Creation of a new Turnkey wallet with a new Solana account
- Monitoring of devnet tokens landing on that address
- Construction of a transaction sending the funds out
- Construction of a transaction sending the funds out with the `@turnkey/solana` signer

## Getting started

Expand All @@ -24,7 +23,7 @@ $ cd examples/with-solana/

### 2/ Setting up Turnkey

The first step is to set up your Turnkey organization and account. By following the [Quickstart](https://docs.turnkey.com/getting-started/quickstart) guide, you should have:
The first step is to set up your Turnkey organization. By following the [Quickstart](https://docs.turnkey.com/getting-started/quickstart) guide, you should have:

- A public/private API key pair for Turnkey
- An organization ID
Expand All @@ -42,13 +41,13 @@ Now open `.env.local` and add the missing environment variables:
- `BASE_URL`
- `ORGANIZATION_ID`

You can also add a Turnkey Private Key ID if you have one already:
You can specify an existing Turnkey Solana address if you have one already:

```
PRIVATE_KEY_ID=<your Turnkey Private Key ID>
SOLANA_ADDRESS=<your Turnkey Solana address>
```

This is optional: the script will create a new one if you don't specify one in your `.env.local` file
Note that this is optional: the script gives you a fresh one if you don't specify one in your `.env.local` file

### 3/ Running the script

Expand All @@ -59,23 +58,24 @@ $ pnpm start
You should see output similar to the following:

```
creating a new Solana private key on your Turnkey organization...
creating a new Solana wallet in your Turnkey organization...
New Solana private key created!
- Name: Solana Key ff73
- Private key ID: e082a9c4-046a-422c-9836-1910615d8100
New Solana wallet created!
- Name: Solana Wallet 9dab
- Wallet ID: 28da5d1a-4d8d-57db-926a-ca36e1c31f63
- Solana address: ARWHYAx8aiNrMkNfCMJxA7FpBBxRdrRbi7Biuzcssxjs
Your Solana address: "6ziT1tk8YhQx8nEiJHAEM5eh9g4DnLwdek7Zfx7KYGAo"
Your new Solana address: "ARWHYAx8aiNrMkNfCMJxA7FpBBxRdrRbi7Biuzcssxjs"
💸 To continue this demo you'll need some devnet funds. You can use:
💸 Your onchain balance is at 0! To continue this demo you'll need devnet funds! You can use:
- The faucet in this example: `pnpm run faucet`
- The official Solana CLI: `solana airdrop 1 6ziT1tk8YhQx8nEiJHAEM5eh9g4DnLwdek7Zfx7KYGAo`
- The official Solana CLI: `solana airdrop 1 ARWHYAx8aiNrMkNfCMJxA7FpBBxRdrRbi7Biuzcssxjs`
- Any online faucet (e.g. https://faucet.triangleplatform.com/solana/devnet)
To check your balance: https://explorer.solana.com/address/6ziT1tk8YhQx8nEiJHAEM5eh9g4DnLwdek7Zfx7KYGAo?cluster=devnet
To check your balance: https://explorer.solana.com/address/ARWHYAx8aiNrMkNfCMJxA7FpBBxRdrRbi7Biuzcssxjs?cluster=devnet
--------
? Do you have devnet funds in 6ziT1tk8YhQx8nEiJHAEM5eh9g4DnLwdek7Zfx7KYGAo? (Y/n)Y
? Do you have devnet funds in ARWHYAx8aiNrMkNfCMJxA7FpBBxRdrRbi7Biuzcssxjs? (Y/n)Y
? Amount (in Lamports) to send to tkhqC9QX2gkqJtUFk2QKhBmQfFyyqZXSpr73VFRi35C: 6000000
New signature: dac3995b81a464fdcd5f914f0264695380562f432387e8240422f6e591b4cf5465c12390042889f8d4890242d289b98fd9a29f808cdee11a745c27c497b2fe0d
Expand Down
1 change: 1 addition & 0 deletions examples/with-solana/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
},
"dependencies": {
"@turnkey/http": "workspace:*",
"@turnkey/solana": "workspace:*",
"@turnkey/api-key-stamper": "workspace:*",
"dotenv": "^16.0.3",
"bs58": "^5.0.0",
Expand Down
72 changes: 0 additions & 72 deletions examples/with-solana/src/createSolanaKey.ts

This file was deleted.

38 changes: 6 additions & 32 deletions examples/with-solana/src/createSolanaTransfer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { PublicKey, SystemProgram, Transaction } from "@solana/web3.js";
import type { TurnkeyClient } from "@turnkey/http";
import { recentBlockhash } from "./solanaNetwork";
import base58 from "bs58";
import { TurnkeySigner } from "@turnkey/solana";

/**
* Creates a Solana transfer and signs it with Turnkey.
Expand All @@ -17,16 +17,9 @@ export async function createAndSignTransfer(input: {
toAddress: string;
amount: number;
turnkeyOrganizationId: string;
turnkeyPrivateKeyId: string;
}): Promise<Buffer> {
const {
client,
fromAddress,
toAddress,
amount,
turnkeyOrganizationId,
turnkeyPrivateKeyId,
} = input;
const { client, fromAddress, toAddress, amount, turnkeyOrganizationId } =
input;
const fromKey = new PublicKey(fromAddress);
const toKey = new PublicKey(toAddress);

Expand All @@ -43,29 +36,10 @@ export async function createAndSignTransfer(input: {
// Set the signer
transferTransaction.feePayer = fromKey;

const messageToSign = transferTransaction.serializeMessage();

const activity = await client.signRawPayload({
type: "ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2",
const signer = new TurnkeySigner({
organizationId: turnkeyOrganizationId,
timestampMs: String(Date.now()),
parameters: {
signWith: turnkeyPrivateKeyId,
payload: messageToSign.toString("hex"),
encoding: "PAYLOAD_ENCODING_HEXADECIMAL",
// Note: unlike ECDSA, EdDSA's API does not support signing raw digests (see RFC 8032).
// Turnkey's signer requires an explicit value to be passed here to minimize ambiguity.
hashFunction: "HASH_FUNCTION_NOT_APPLICABLE",
},
client,
});

const signature = `${activity.activity.result.signRawPayloadResult?.r}${activity.activity.result.signRawPayloadResult?.s}`;
console.log(
`New signature: ${signature}\n(base58: ${base58.encode(
Buffer.from(signature, "hex")
)})`
);

transferTransaction.addSignature(fromKey, Buffer.from(signature, "hex"));
await signer.addSignature(transferTransaction, fromAddress);
return transferTransaction.serialize();
}
80 changes: 80 additions & 0 deletions examples/with-solana/src/createSolanaWallet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import {
TurnkeyActivityError,
TurnkeyClient,
createActivityPoller,
} from "@turnkey/http";
import * as crypto from "crypto";

export async function createNewSolanaWallet(
client: TurnkeyClient,
turnkeyOrganizationId: string
) {
console.log("creating a new Solana wallet in your Turnkey organization...\n");

const walletName = `Solana Wallet ${crypto.randomBytes(2).toString("hex")}`;

try {
const activityPoller = createActivityPoller({
client: client,
requestFn: client.createWallet,
});

const completedActivity = await activityPoller({
type: "ACTIVITY_TYPE_CREATE_WALLET",
organizationId: turnkeyOrganizationId,
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",
},
],
},
timestampMs: String(Date.now()), // millisecond timestamp
});

const walletId = completedActivity.result.createWalletResult?.walletId;
if (!walletId) {
console.error(
"activity doesn't contain a valid wallet ID",
completedActivity
);
process.exit(1);
}

const address = completedActivity.result.createWalletResult?.addresses[0];
if (!address) {
console.error(
"activity result doesn't contain a valid address",
completedActivity
);
process.exit(1);
}

console.log(
[
`New Solana wallet created!`,
`- Name: ${walletName}`,
`- Wallet ID: ${walletId}`,
`- Solana address: ${address}`,
].join("\n")
);
return address;
} 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 Solana wallet: ${
(error as Error).message
}`,
cause: error as Error,
});
}
}
19 changes: 7 additions & 12 deletions examples/with-solana/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ const TURNKEY_WAR_CHEST = "tkhqC9QX2gkqJtUFk2QKhBmQfFyyqZXSpr73VFRi35C";
// Load environment variables from `.env.local`
dotenv.config({ path: path.resolve(process.cwd(), ".env.local") });

import { createNewSolanaPrivateKey } from "./createSolanaKey";
import { deriveSolanaAddress } from "./solanaAddress";
import { createNewSolanaWallet } from "./createSolanaWallet";
import * as solanaNetwork from "./solanaNetwork";
import { createAndSignTransfer } from "./createSolanaTransfer";
import { input, confirm } from "@inquirer/prompts";
Expand All @@ -27,16 +26,13 @@ async function main() {
})
);

let privateKeyId = process.env.PRIVATE_KEY_ID;
if (!privateKeyId) {
privateKeyId = await createNewSolanaPrivateKey(
turnkeyClient,
organizationId
);
let solAddress = process.env.SOLANA_ADDRESS;
if (!solAddress) {
solAddress = await createNewSolanaWallet(turnkeyClient, organizationId);
console.log(`\nYour new Solana address: "${solAddress}"`);
} else {
console.log(`\nUsing existing Solana address from ENV: "${solAddress}"`);
}
const solAddress = await deriveSolanaAddress(turnkeyClient, privateKeyId);

console.log(`\nYour Solana address: "${solAddress}"`);

let balance = await solanaNetwork.balance(connection, solAddress);
while (balance === 0) {
Expand Down Expand Up @@ -92,7 +88,6 @@ async function main() {
toAddress: destination,
amount: Number(amount),
turnkeyOrganizationId: organizationId,
turnkeyPrivateKeyId: privateKeyId,
});

// Broadcast the signed payload on devnet
Expand Down
21 changes: 0 additions & 21 deletions examples/with-solana/src/solanaAddress.ts

This file was deleted.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@
"overrides": {
"@confio/[email protected]>protobufjs": ">=7.2.4",
"protobufjs@>=6.10.0 <7.2.4": ">=7.2.4",
"@babel/traverse": ">=7.23.2"
"@babel/traverse": ">=7.23.2",
"follow-redirects": ">=1.15.4"
}
}
}
Loading

0 comments on commit a209220

Please sign in to comment.