Skip to content
Open

wip #935

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 60 additions & 37 deletions examples/with-viem/src/advanced.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ async function main() {
new ApiKeyStamper({
apiPublicKey: process.env.API_PUBLIC_KEY!,
apiPrivateKey: process.env.API_PRIVATE_KEY!,
}),
})
);

const turnkeyAccount = await createAccount({
Expand All @@ -47,7 +47,7 @@ async function main() {
account: turnkeyAccount as Account,
chain: sepolia,
transport: http(
`https://sepolia.infura.io/v3/${process.env.INFURA_API_KEY!}`,
`https://sepolia.infura.io/v3/${process.env.INFURA_API_KEY!}`
),
});

Expand Down Expand Up @@ -83,47 +83,70 @@ async function main() {
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",
domain: {
name: "Test",
version: "1",
chainId: 1,
verifyingContract: "0x0000000000000000000000000000000000000000",
},
types: {
TestMessage: [{ name: "number", type: "uint256" }],
},
primaryType: "TestMessage",
message: {
from: {
name: "Cow",
wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
},
to: {
name: "Bob",
wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
},
contents: "Hello, Bob!",
number: 42n, // BigInt
},
} as const;
};

const types = {
TransferRequest: [
{ name: "selector", type: "bytes4" },
{ name: "destination", type: "address" },
{ name: "token", type: "address" },
{ name: "nonStandardIndex", type: "uint256" },
{ name: "tokenId", type: "uint256" },
{ name: "amount", type: "uint256" },
{ name: "amounts", type: "uint256[]" },
{ name: "tokenIds", type: "uint256[]" },
{ name: "data", type: "bytes" },
{ name: "nonce", type: "uint256" },
],
};

const request = {
destination: "0x54FFabdc775e54bc852010C4AfF553183420E6bb",
token: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
nonStandardIndex: 0n,
tokenId: 0n,
amount: 11527707n,
amounts: [],
tokenIds: [],
data: "0x",
selector: "0xc9a4324f",
nonce: 3375574816n,
};

const message = {
...request
};

const td = {
domain: {
name: "AccountImplementation",
version: "1",
chainId: sepolia.id,
verifyingContract: "0x0000000000000000000000000000000000000000",
},
types,
primaryType: "TransferRequest",
message,
}

signature = await client.signTypedData(typedData);
signature = await client.signTypedData(td);
recoveredAddress = await recoverTypedDataAddress({
...typedData,
...td,
signature,
});

Expand Down
72 changes: 40 additions & 32 deletions packages/viem/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import {
hexToBytes,
parseTransaction,
serializeTypedData,
hashTypedData,
} from "viem";
import {
SignAuthorizationReturnType,
toAccount,
SignAuthorizationParameters,
} from "viem/accounts";
import type {
HashTypedDataParameters,
Hex,
LocalAccount,
SerializeTransactionFn,
Expand Down Expand Up @@ -153,7 +155,7 @@ export function createAccountWithAddress(input: {
serializer?:
| SerializeTransactionFn<TTransactionSerializable>
| undefined;
},
}
): Promise<Hex> {
const serializer: SerializeTransactionFn<TTransactionSerializable> =
options?.serializer ??
Expand All @@ -163,16 +165,16 @@ export function createAccountWithAddress(input: {
transaction,
serializer,
organizationId,
signWith,
signWith
);
},
signTypedData: function (
typedData: TypedData | { [key: string]: unknown },
typedData: TypedData | { [key: string]: unknown }
): Promise<Hex> {
return signTypedData(client, typedData, organizationId, signWith);
},
signAuthorization: function (
parameters: TSignAuthorizationParameters,
parameters: TSignAuthorizationParameters
): Promise<SignAuthorizationReturnType> {
return signAuthorization(client, parameters, organizationId, signWith);
},
Expand Down Expand Up @@ -210,7 +212,7 @@ export async function createAccount(input: {
});

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

if (typeof ethereumAddress !== "string" || !ethereumAddress) {
Expand Down Expand Up @@ -260,7 +262,7 @@ type TApiKeyAccountConfig = {
* @deprecated use {@link createAccount} instead.
*/
export async function createApiKeyAccount(
config: TApiKeyAccountConfig,
config: TApiKeyAccountConfig
): Promise<LocalAccount> {
const { apiPublicKey, apiPrivateKey, baseUrl, organizationId, privateKeyId } =
config;
Expand All @@ -274,7 +276,7 @@ export async function createApiKeyAccount(
{
baseUrl: baseUrl,
},
stamper,
stamper
);

const data = await client.getPrivateKey({
Expand All @@ -283,7 +285,7 @@ export async function createApiKeyAccount(
});

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

if (typeof ethereumAddress !== "string" || !ethereumAddress) {
Expand Down Expand Up @@ -313,7 +315,7 @@ export async function createApiKeyAccount(
serializer?:
| SerializeTransactionFn<TTransactionSerializable>
| undefined;
},
}
): Promise<Hex> {
const serializer: SerializeTransactionFn<TTransactionSerializable> =
options?.serializer ??
Expand All @@ -323,22 +325,22 @@ export async function createApiKeyAccount(
transaction,
serializer,
organizationId,
privateKeyId,
privateKeyId
);
},
signTypedData: function (
typedData: TypedData | { [key: string]: unknown },
typedData: TypedData | { [key: string]: unknown }
): Promise<Hex> {
return signTypedData(client, typedData, organizationId, privateKeyId);
},
signAuthorization: function (
parameters: TSignAuthorizationParameters,
parameters: TSignAuthorizationParameters
): Promise<SignAuthorizationReturnType> {
return signAuthorization(
client,
parameters,
organizationId,
privateKeyId,
privateKeyId
);
},
});
Expand All @@ -348,7 +350,7 @@ export async function signAuthorization(
client: TurnkeyClient | TurnkeyBrowserClient | TurnkeyServerClient,
parameters: TSignAuthorizationParameters,
organizationId: string,
signWith: string,
signWith: string
): Promise<SignAuthorizationReturnType> {
const { chainId, nonce, to = "object" } = parameters;
const address = parameters.contractAddress ?? parameters.address;
Expand All @@ -369,7 +371,7 @@ export async function signAuthorization(
organizationId,
signWith,
"PAYLOAD_ENCODING_EIP7702_AUTHORIZATION",
to,
to
);

if (to === "object")
Expand All @@ -388,13 +390,13 @@ export async function signMessage(
client: TurnkeyClient | TurnkeyBrowserClient | TurnkeyServerClient,
message: SignableMessage,
organizationId: string,
signWith: string,
signWith: string
): Promise<Hex> {
const signedMessage = await signMessageWithErrorWrapping(
client,
message as Hex,
organizationId,
signWith,
signWith
);
return `${signedMessage}` as Hex;
}
Expand All @@ -406,7 +408,7 @@ export async function signTransaction<
transaction: TTransactionSerializable,
serializer: SerializeTransactionFn<TTransactionSerializable>,
organizationId: string,
signWith: string,
signWith: string
): Promise<Hex> {
// Note: for Type 3 transactions, we are specifically handling parsing for payloads containing only the transaction payload body, without any wrappers around blobs, commitments, or proofs.
// See more: https://github.com/wevm/viem/blob/3ef19eac4963014fb20124d1e46d1715bed5509f/src/accounts/utils/signTransaction.ts#L54-L55
Expand All @@ -421,7 +423,7 @@ export async function signTransaction<
client,
nonHexPrefixedSerializedTx,
organizationId,
signWith,
signWith
);

if (transaction.type === "eip4844") {
Expand All @@ -443,31 +445,37 @@ export async function signTypedData(
client: TurnkeyClient | TurnkeyBrowserClient | TurnkeyServerClient,
data: TypedData | { [key: string]: unknown },
organizationId: string,
signWith: string,
signWith: string
): Promise<Hex> {
const hashToSign = hashTypedData(data as HashTypedDataParameters);

console.log("hash to sign", hashToSign);

return (await signMessageWithErrorWrapping(
client,
serializeTypedData(data as SignTypedDataParameters),
// serializeTypedData(data as SignTypedDataParameters),
hashToSign,
organizationId,
signWith,
"PAYLOAD_ENCODING_EIP712",
"hex",
// "PAYLOAD_ENCODING_EIP712",
"PAYLOAD_ENCODING_HEXADECIMAL",
"hex"
)) as Hex;
}

async function signTransactionWithErrorWrapping(
client: TurnkeyClient | TurnkeyBrowserClient | TurnkeyServerClient,
unsignedTransaction: string,
organizationId: string,
signWith: string,
signWith: string
): Promise<Hex> {
let signedTx: string;
try {
signedTx = await signTransactionImpl(
client,
unsignedTransaction,
organizationId,
signWith,
signWith
);
} catch (error: any) {
// Wrap Turnkey error in Viem-specific error
Expand Down Expand Up @@ -499,7 +507,7 @@ async function signTransactionImpl(
client: TurnkeyClient | TurnkeyBrowserClient | TurnkeyServerClient,
unsignedTransaction: string,
organizationId: string,
signWith: string,
signWith: string
): Promise<string> {
if (isHttpClient(client)) {
const { activity } = await client.signTransaction({
Expand All @@ -516,7 +524,7 @@ async function signTransactionImpl(
assertActivityCompleted(activity);

return assertNonNull(
activity?.result?.signTransactionResult?.signedTransaction,
activity?.result?.signTransactionResult?.signedTransaction
);
} else {
const { activity, signedTransaction } = await client.signTransaction({
Expand All @@ -538,7 +546,7 @@ async function signMessageWithErrorWrapping(
organizationId: string,
signWith: string,
payloadEncoding: TPayloadEncoding = "PAYLOAD_ENCODING_HEXADECIMAL",
to: TSignatureFormat = "hex",
to: TSignatureFormat = "hex"
): Promise<TSignMessageResult> {
let signedMessage: TSignMessageResult;

Expand All @@ -549,7 +557,7 @@ async function signMessageWithErrorWrapping(
organizationId,
signWith,
payloadEncoding,
to,
to
);
} catch (error: any) {
// Wrap Turnkey error in Viem-specific error
Expand Down Expand Up @@ -583,7 +591,7 @@ async function signMessageImpl(
organizationId: string,
signWith: string,
payloadEncoding: TPayloadEncoding,
to: TSignatureFormat,
to: TSignatureFormat
): Promise<TSignMessageResult> {
let result: TSignature;

Expand Down Expand Up @@ -636,7 +644,7 @@ async function signMessageImpl(
// https://github.com/wevm/viem/blob/c8378d22f692f48edde100693159874702f36330/src/utils/signature/serializeSignature.ts#L38-L39
export function serializeSignature(
sig: TSignature,
to: TSignatureFormat = "hex",
to: TSignatureFormat = "hex"
) {
const { r: rString, s: sString, v: vString } = sig;

Expand All @@ -649,7 +657,7 @@ export function serializeSignature(

const signature = `0x${new secp256k1.Signature(
hexToBigInt(r),
hexToBigInt(s),
hexToBigInt(s)
).toCompactHex()}${yParity_ === 0n ? "1b" : "1c"}` as const;

if (to === "hex") return signature;
Expand Down
Loading