Skip to content

Commit

Permalink
createAccountWithAddress + tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mshrieve authored and andrewkmin committed Sep 18, 2024
1 parent 2093060 commit 89acf37
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 22 deletions.
3 changes: 2 additions & 1 deletion packages/viem/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ API_PRIVATE_KEY="<Turnkey API Private Key>"
BASE_URL="https://api.turnkey.com"
ORGANIZATION_ID="<Turnkey organization ID>"
PRIVATE_KEY_ID="<Turnkey (crypto) private key ID>"
EXPECTED_ETH_ADDRESS="<Corresponding to the private key above>"
EXPECTED_PRIVATE_KEY_ETH_ADDRESS="<Corresponding to the private key above>"
EXPECTED_WALLET_ACCOUNT_ETH_ADDRESS="<0x...>"
BANNED_TO_ADDRESS="<0x...>"
20 changes: 18 additions & 2 deletions packages/viem/src/__tests__/index-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
import { foundry } from "viem/chains";
import { TurnkeyClient } from "@turnkey/http";
import { ApiKeyStamper } from "@turnkey/api-key-stamper";
import { createAccount } from "../";
import { createAccount, createAccountWithAddress } from "../";
import Test721 from "./Test721.json";
import { expect, beforeEach, describe, test } from "@jest/globals";

Expand Down Expand Up @@ -77,6 +77,11 @@ describe("TurnkeyAccount", () => {
signWith: expectedWalletAccountEthAddress,
expectedEthAddress: expectedWalletAccountEthAddress,
},
{
configName: "Wallet Account using createAccountWithAddress",
signWith: expectedWalletAccountEthAddress,
expectedEthAddress: expectedWalletAccountEthAddress,
},
{
configName: "Private Key ID",
signWith: privateKeyId,
Expand All @@ -87,6 +92,11 @@ describe("TurnkeyAccount", () => {
signWith: expectedPrivateKeyEthAddress,
expectedEthAddress: expectedPrivateKeyEthAddress,
},
{
configName: "Private Key Address using createAccountWithAddress",
signWith: expectedPrivateKeyEthAddress,
expectedEthAddress: expectedPrivateKeyEthAddress,
},
].forEach(async (signingConfig) => {
describe(`using config ${signingConfig.configName}`, () => {
beforeEach(async () => {
Expand All @@ -101,7 +111,11 @@ describe("TurnkeyAccount", () => {
})
);

turnkeyAccount = await createAccount({
turnkeyAccount = signingConfig.configName.includes("createAccountWithAddress") ? createAccountWithAddress({
client: turnkeyClient,
organizationId,
signWith: signingConfig.signWith
}) : await createAccount({
client: turnkeyClient,
organizationId,
signWith: signingConfig.signWith,
Expand Down Expand Up @@ -361,6 +375,8 @@ describe("TurnkeyAccount", () => {
});
});



function assertNonEmptyString(input: unknown, name: string): string {
if (typeof input !== "string" || !input) {
throw new Error(`Expected non empty string for "${name}", got ${input}`);
Expand Down
73 changes: 54 additions & 19 deletions packages/viem/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,15 @@ export class TurnkeyActivityError extends BaseError {
}
}

export async function createAccount(input: {
export function createAccountWithAddress(input: {
client: TurnkeyClient | TurnkeyBrowserClient | TurnkeyServerClient;
organizationId: string;
// This can be a wallet account address, private key address, or private key ID.
signWith: string;
// Ethereum address to use for this account, in the case that a private key ID is used to sign.
// If left undefined, `createAccount` will fetch it from the Turnkey API.
// We recommend setting this if you're using a passkey client, so that your users are not prompted for a passkey signature just to fetch their address.
// You may leave this undefined if using an API key client.
// Can be left undefined if signWith is a wallet account address.
ethereumAddress?: string;
}): Promise<LocalAccount> {
}): LocalAccount {
const { client, organizationId, signWith } = input;
let { ethereumAddress } = input;

Expand All @@ -97,21 +95,9 @@ export async function createAccount(input: {
// override provided `ethereumAddress`
ethereumAddress = signWith;
} else if (!ethereumAddress) {
// we have a private key ID, but not an ethereumAddress
const data = await client.getPrivateKey({
privateKeyId: signWith,
organizationId: organizationId,
throw new TurnkeyActivityError({
message: `Missing ethereumAddress parameter`,
});

ethereumAddress = data.privateKey.addresses.find(
(item: any) => item.format === "ADDRESS_FORMAT_ETHEREUM"
)?.address;

if (typeof ethereumAddress !== "string" || !ethereumAddress) {
throw new TurnkeyHttpActivityError({
message: `Unable to find Ethereum address for key ${signWith} under organization ${organizationId}`,
});
}
}

return toAccount({
Expand Down Expand Up @@ -151,6 +137,55 @@ export async function createAccount(input: {
});
}

export async function createAccount(input: {
client: TurnkeyClient | TurnkeyBrowserClient | TurnkeyServerClient;
organizationId: string;
// This can be a wallet account address, private key address, or private key ID.
signWith: string;
// Ethereum address to use for this account, in the case that a private key ID is used to sign.
// If left undefined, `createAccount` will fetch it from the Turnkey API.
// We recommend setting this if you're using a passkey client, so that your users are not prompted for a passkey signature just to fetch their address.
// You may leave this undefined if using an API key client.
ethereumAddress?: string;
}): Promise<LocalAccount> {
const { client, organizationId, signWith } = input;
let { ethereumAddress } = input;

if (!signWith) {
throw new TurnkeyActivityError({
message: `Missing signWith parameter`,
});
}

if (isAddress(signWith)) {
// override provided `ethereumAddress`
ethereumAddress = signWith;
} else if (!ethereumAddress) {
// we have a private key ID, but not an ethereumAddress
const data = await client.getPrivateKey({
privateKeyId: signWith,
organizationId: organizationId,
});

ethereumAddress = data.privateKey.addresses.find(
(item: any) => item.format === "ADDRESS_FORMAT_ETHEREUM"
)?.address;

if (typeof ethereumAddress !== "string" || !ethereumAddress) {
throw new TurnkeyActivityError({
message: `Unable to find Ethereum address for key ${signWith} under organization ${organizationId}`,
});
}
}

return createAccountWithAddress({
client,
organizationId,
signWith,
ethereumAddress,
});
}

/**
* Type bundling configuration for an API Key Viem account creation
* @deprecated this is used only with {@link createApiKeyAccount}, a deprecated API. See {@link createAccount}.
Expand Down

0 comments on commit 89acf37

Please sign in to comment.