From 4c021a2b7a4bbc4d0ab79bbf9eebe9d91f23b5a2 Mon Sep 17 00:00:00 2001 From: Andrew Hariri Date: Mon, 22 Jan 2024 11:42:21 -0800 Subject: [PATCH] [passkey] update example --- examples/typescript/passkey/src/App.css | 7 + examples/typescript/passkey/src/App.tsx | 175 +++++++++--------- pnpm-lock.yaml | 61 ++++-- src/api/aptos.ts | 1 - src/internal/transactionSubmission.ts | 2 +- .../transactionBuilder/transactionBuilder.ts | 9 +- 6 files changed, 144 insertions(+), 111 deletions(-) diff --git a/examples/typescript/passkey/src/App.css b/examples/typescript/passkey/src/App.css index a5c23eb40..389dfbe2c 100644 --- a/examples/typescript/passkey/src/App.css +++ b/examples/typescript/passkey/src/App.css @@ -3,6 +3,7 @@ margin: 0 auto; padding: 2rem; text-align: center; + width: 100%; } .logo { @@ -41,9 +42,15 @@ display: flex; flex-direction: row; justify-content: center; + flex-wrap: wrap; gap: 8px; + width: 100%; } .read-the-docs { color: #888; } + +.text-wrap { + word-break: break-all; +} \ No newline at end of file diff --git a/examples/typescript/passkey/src/App.tsx b/examples/typescript/passkey/src/App.tsx index 8f05c703b..ac9b29c48 100644 --- a/examples/typescript/passkey/src/App.tsx +++ b/examples/typescript/passkey/src/App.tsx @@ -1,47 +1,40 @@ import { useState } from "react"; -import reactLogo from "./assets/react.svg"; -import viteLogo from "/vite.svg"; import "./App.css"; -import { AccountAddress, Aptos, AptosConfig, parseTypeTag, Network, Secp256r1PublicKey, - U64, } from "@aptos-labs/ts-sdk"; +import { AccountAddress, Aptos, AptosConfig, Network, Secp256r1PublicKey } from "@aptos-labs/ts-sdk"; -const APTOS_COIN = "0x1::aptos_coin::AptosCoin"; const ALICE_INITIAL_BALANCE = 100_000_000; -const BOB_INITIAL_BALANCE = 100; -const TRANSFER_AMOUNT = 7777777; const COIN_STORE = "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>"; const config = new AptosConfig({ network: Network.DEVNET }); const aptos = new Aptos(config); -const BOB_ADDR = "0x6c2fe73e11ed74b32a2f583f4df93190edd521d023925d148fbf7d66a2891835" function App() { - const [credentialId, setCredentialId] = useState( - window.localStorage.getItem("credentialId") - ); + const [credentialId, setCredentialId] = useState(window.localStorage.getItem("credentialId")); - const [publicKey, setPublicKey] = useState( - window.localStorage.getItem("publicKey") - ); + const [publicKey, setPublicKey] = useState(window.localStorage.getItem("publicKey")); + + const [recipientAddress, setRecipientAddress] = useState(null); + const [sendAmount, setSendAmount] = useState(0); + const [passkeyAddr, setPasskeyAddr] = useState(null); + + /** + * Prints the balance of an account + * @param aptos + * @param name + * @param address + * @returns {Promise<*>} + * + */ + const balance = async (aptos: Aptos, name: string, address: AccountAddress) => { + type Coin = { coin: { value: string } }; + const resource = await aptos.getAccountResource({ + accountAddress: address, + resourceType: COIN_STORE, + }); + const amount = Number(resource.coin.value); -/** - * Prints the balance of an account - * @param aptos - * @param name - * @param address - * @returns {Promise<*>} - * - */ -const balance = async (aptos: Aptos, name: string, address: AccountAddress) => { - type Coin = { coin: { value: string } }; - const resource = await aptos.getAccountResource({ - accountAddress: address, - resourceType: COIN_STORE, - }); - const amount = Number(resource.coin.value); - - console.log(`${name}'s balance is: ${amount}`); - return amount; -}; + console.log(`${name}'s balance is: ${amount}`); + return amount; + }; // Create the passkey via credential registration ceremony const createPasskey = async () => { @@ -50,10 +43,10 @@ const balance = async (aptos: Aptos, name: string, address: AccountAddress) => { rpID: window.location.hostname, userName: "Andrew", userID: "andrew.apt", - authenticatorAttachment: "platform" + authenticatorAttachment: "platform", }); - const cred = await aptos.registerCredential(options) + const cred = await aptos.registerCredential(options); const pubKey = aptos.parsePublicKey(cred); const addr = await aptos.getPasskeyAccountAddress({ publicKey: pubKey.toString() }); @@ -61,7 +54,8 @@ const balance = async (aptos: Aptos, name: string, address: AccountAddress) => { setCredentialId(cred.rawId); setPublicKey(aptos.parsePublicKey(cred).toString()); - console.log(cred) + setPasskeyAddr(addr.toString()); + console.log(cred); window.localStorage.setItem("credentialId", cred.rawId); window.localStorage.setItem("publicKey", aptos.parsePublicKey(cred).toString()); }; @@ -72,26 +66,19 @@ const balance = async (aptos: Aptos, name: string, address: AccountAddress) => { return; } - const addr = await aptos.getPasskeyAccountAddress({publicKey}) + const addr = await aptos.getPasskeyAccountAddress({ publicKey }); - await aptos.faucet.fundAccount({ + const pendingTxn = await aptos.faucet.fundAccount({ accountAddress: addr.toUint8Array(), amount: ALICE_INITIAL_BALANCE, }); - console.log("\n=== Balances ===\n"); - await balance(aptos, "Passkey Account", new AccountAddress(addr.toUint8Array())); - } - - const fundBobAccount = async () => { - await aptos.faucet.fundAccount({ - accountAddress: AccountAddress.fromString(BOB_ADDR), - amount: BOB_INITIAL_BALANCE, - }); + const confirmedTxn = await aptos.waitForTransaction({ transactionHash: pendingTxn.hash }); + alert("Faucet 1 APT deposited, txn hash: " + confirmedTxn.hash); console.log("\n=== Balances ===\n"); - await balance(aptos, "Bob Account", AccountAddress.fromString(BOB_ADDR)); - } + await balance(aptos, "Passkey Account", new AccountAddress(addr.toUint8Array())); + }; const checkBalance = async () => { if (!publicKey) { @@ -99,21 +86,13 @@ const balance = async (aptos: Aptos, name: string, address: AccountAddress) => { return; } - const addr = await aptos.getPasskeyAccountAddress({publicKey}) + const addr = await aptos.getPasskeyAccountAddress({ publicKey }); console.log("\n=== Balances ===\n"); const bal = await balance(aptos, "Passkey Account", new AccountAddress(addr.toUint8Array())); - window.alert(bal); - } - - const checkBobBalance = async () => { - - console.log("\n=== Balances ===\n"); - const bal = await balance(aptos, "Bob Account", AccountAddress.fromString(BOB_ADDR)); - - window.alert(bal); - } + window.alert(bal / 1e8 + " APT"); + }; /** * Use the passkey credential registered to the user to sign a coin transfer @@ -129,59 +108,75 @@ const balance = async (aptos: Aptos, name: string, address: AccountAddress) => { return; } - const addr = await aptos.getPasskeyAccountAddress({publicKey}) + const addr = await aptos.getPasskeyAccountAddress({ publicKey }); + const recipient = AccountAddress.fromString(recipientAddress || "0x1"); - console.log(aptos) - const txn = await aptos.build.simple({ + const txn = await aptos.transferCoinTransaction({ sender: addr, - data: { - function: "0x1::coin::transfer", - typeArguments: [parseTypeTag(APTOS_COIN)], - functionArguments: [AccountAddress.fromString(BOB_ADDR), new U64(TRANSFER_AMOUNT)], - }, + recipient: recipient, + amount: sendAmount * 1e8, }); console.log("\n=== Transfer transaction ===\n"); - // const committedTxn = - await aptos.signAndSubmitWithPasskey({ - credentialId: credentialId, - transaction: txn, - publicKey: new Secp256r1PublicKey(publicKey), - }); + // const committedTxn = + const pendingTxn = await aptos.signAndSubmitWithPasskey({ + credentialId: credentialId, + transaction: txn, + publicKey: new Secp256r1PublicKey(publicKey), + }); + + const committedTxn = await aptos.waitForTransaction({ transactionHash: pendingTxn.hash }); + console.log(committedTxn); // This doesn't work until the indexer works for passkeys // await aptos.waitForTransaction({ transactionHash: committedTxn.hash }); // console.log(`Committed transaction: ${committedTxn.hash}`); }; + const getAddress = async () => { + if (!credentialId) { + alert("No registered credential"); + return; + } + + if (!publicKey) { + alert("No registered publicKey"); + return; + } + + const addr = await aptos.getPasskeyAccountAddress({ publicKey: publicKey }); + setPasskeyAddr(addr.toString()); + + alert(addr); + }; + return ( <> -

Passkeys Demo

+ {passkeyAddr ?

{"Your address: " + passkeyAddr}

: null} + {passkeyAddr ? ( + + Explorer link + + ) : null}
- - +
-

- Edit src/App.tsx and save to test HMR -

+

Recipient address

+ setRecipientAddress(e.currentTarget.value)} /> +

Send amount (APT)

+ setSendAmount(Number(e.currentTarget.value))} />

rpId: {window.location.hostname}

-

- Click on the Vite and React logos to learn more -

); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2ec41917d..2cb7c212a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -991,48 +991,48 @@ packages: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true - /@cbor-extract/cbor-extract-darwin-arm64@2.1.1: - resolution: {integrity: sha512-blVBy5MXz6m36Vx0DfLd7PChOQKEs8lK2bD1WJn/vVgG4FXZiZmZb2GECHFvVPA5T7OnODd9xZiL3nMCv6QUhA==} + /@cbor-extract/cbor-extract-darwin-arm64@2.2.0: + resolution: {integrity: sha512-P7swiOAdF7aSi0H+tHtHtr6zrpF3aAq/W9FXx5HektRvLTM2O89xCyXF3pk7pLc7QpaY7AoaE8UowVf9QBdh3w==} cpu: [arm64] os: [darwin] requiresBuild: true dev: false optional: true - /@cbor-extract/cbor-extract-darwin-x64@2.1.1: - resolution: {integrity: sha512-h6KFOzqk8jXTvkOftyRIWGrd7sKQzQv2jVdTL9nKSf3D2drCvQB/LHUxAOpPXo3pv2clDtKs3xnHalpEh3rDsw==} + /@cbor-extract/cbor-extract-darwin-x64@2.2.0: + resolution: {integrity: sha512-1liF6fgowph0JxBbYnAS7ZlqNYLf000Qnj4KjqPNW4GViKrEql2MgZnAsExhY9LSy8dnvA4C0qHEBgPrll0z0w==} cpu: [x64] os: [darwin] requiresBuild: true dev: false optional: true - /@cbor-extract/cbor-extract-linux-arm64@2.1.1: - resolution: {integrity: sha512-SxAaRcYf8S0QHaMc7gvRSiTSr7nUYMqbUdErBEu+HYA4Q6UNydx1VwFE68hGcp1qvxcy9yT5U7gA+a5XikfwSQ==} + /@cbor-extract/cbor-extract-linux-arm64@2.2.0: + resolution: {integrity: sha512-rQvhNmDuhjTVXSPFLolmQ47/ydGOFXtbR7+wgkSY0bdOxCFept1hvg59uiLPT2fVDuJFuEy16EImo5tE2x3RsQ==} cpu: [arm64] os: [linux] requiresBuild: true dev: false optional: true - /@cbor-extract/cbor-extract-linux-arm@2.1.1: - resolution: {integrity: sha512-ds0uikdcIGUjPyraV4oJqyVE5gl/qYBpa/Wnh6l6xLE2lj/hwnjT2XcZCChdXwW/YFZ1LUHs6waoYN8PmK0nKQ==} + /@cbor-extract/cbor-extract-linux-arm@2.2.0: + resolution: {integrity: sha512-QeBcBXk964zOytiedMPQNZr7sg0TNavZeuUCD6ON4vEOU/25+pLhNN6EDIKJ9VLTKaZ7K7EaAriyYQ1NQ05s/Q==} cpu: [arm] os: [linux] requiresBuild: true dev: false optional: true - /@cbor-extract/cbor-extract-linux-x64@2.1.1: - resolution: {integrity: sha512-GVK+8fNIE9lJQHAlhOROYiI0Yd4bAZ4u++C2ZjlkS3YmO6hi+FUxe6Dqm+OKWTcMpL/l71N6CQAmaRcb4zyJuA==} + /@cbor-extract/cbor-extract-linux-x64@2.2.0: + resolution: {integrity: sha512-cWLAWtT3kNLHSvP4RKDzSTX9o0wvQEEAj4SKvhWuOVZxiDAeQazr9A+PSiRILK1VYMLeDml89ohxCnUNQNQNCw==} cpu: [x64] os: [linux] requiresBuild: true dev: false optional: true - /@cbor-extract/cbor-extract-win32-x64@2.1.1: - resolution: {integrity: sha512-2Niq1C41dCRIDeD8LddiH+mxGlO7HJ612Ll3D/E73ZWBmycued+8ghTr/Ho3CMOWPUEr08XtyBMVXAjqF+TcKw==} + /@cbor-extract/cbor-extract-win32-x64@2.2.0: + resolution: {integrity: sha512-l2M+Z8DO2vbvADOBNLbbh9y5ST1RY5sqkWOg/58GkUPBYou/cuNZ68SGQ644f1CvZ8kcOxyZtw06+dxWHIoN/w==} cpu: [x64] os: [win32] requiresBuild: true @@ -2500,7 +2500,7 @@ packages: '@peculiar/asn1-schema': 2.3.8 '@peculiar/asn1-x509': 2.3.8 '@simplewebauthn/typescript-types': 8.3.4 - cbor-x: 1.5.4 + cbor-x: 1.5.8 cross-fetch: 4.0.0 transitivePeerDependencies: - encoding @@ -3499,6 +3499,28 @@ packages: upper-case-first: 2.0.2 dev: true + /cbor-extract@2.2.0: + resolution: {integrity: sha512-Ig1zM66BjLfTXpNgKpvBePq271BPOvu8MR0Jl080yG7Jsl+wAZunfrwiwA+9ruzm/WEdIV5QF/bjDZTqyAIVHA==} + hasBin: true + requiresBuild: true + dependencies: + node-gyp-build-optional-packages: 5.1.1 + optionalDependencies: + '@cbor-extract/cbor-extract-darwin-arm64': 2.2.0 + '@cbor-extract/cbor-extract-darwin-x64': 2.2.0 + '@cbor-extract/cbor-extract-linux-arm': 2.2.0 + '@cbor-extract/cbor-extract-linux-arm64': 2.2.0 + '@cbor-extract/cbor-extract-linux-x64': 2.2.0 + '@cbor-extract/cbor-extract-win32-x64': 2.2.0 + dev: false + optional: true + + /cbor-x@1.5.8: + resolution: {integrity: sha512-gc3bHBsvG6GClCY6c0/iip+ghlqizkVp+TtaL927lwvP4VP9xBdi1HmqPR5uj/Mj/0TOlngMkIYa25wKg+VNrQ==} + optionalDependencies: + cbor-extract: 2.2.0 + dev: false + /chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -3904,6 +3926,13 @@ packages: engines: {node: '>=8'} dev: true + /detect-libc@2.0.2: + resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} + engines: {node: '>=8'} + requiresBuild: true + dev: false + optional: true + /detect-newline@3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} @@ -6060,10 +6089,12 @@ packages: dependencies: whatwg-url: 5.0.0 - /node-gyp-build-optional-packages@5.0.3: - resolution: {integrity: sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==} + /node-gyp-build-optional-packages@5.1.1: + resolution: {integrity: sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==} hasBin: true requiresBuild: true + dependencies: + detect-libc: 2.0.2 dev: false optional: true diff --git a/src/api/aptos.ts b/src/api/aptos.ts index c83232547..5407274f5 100644 --- a/src/api/aptos.ts +++ b/src/api/aptos.ts @@ -13,7 +13,6 @@ import { ANS } from "./ans"; import { PasskeysBrowser } from "./passkey"; import { Staking } from "./staking"; import { Transaction } from "./transaction"; -import { PasskeysBrowser } from "./passkeysBrowser"; /** * This class is the main entry point into Aptos's diff --git a/src/internal/transactionSubmission.ts b/src/internal/transactionSubmission.ts index c73ab7830..4d7f5ae47 100644 --- a/src/internal/transactionSubmission.ts +++ b/src/internal/transactionSubmission.ts @@ -21,7 +21,7 @@ import { sign, generateSigningMessage, } from "../transactions/transactionBuilder/transactionBuilder"; -import { +import type { InputGenerateTransactionData, AnyRawTransaction, InputSimulateTransactionData, diff --git a/src/transactions/transactionBuilder/transactionBuilder.ts b/src/transactions/transactionBuilder/transactionBuilder.ts index 3b97f4bdf..eb5b4cfc3 100644 --- a/src/transactions/transactionBuilder/transactionBuilder.ts +++ b/src/transactions/transactionBuilder/transactionBuilder.ts @@ -82,6 +82,7 @@ import { memoizeAsync } from "../../utils/memoize"; import { HexInput, SigningScheme } from "../../types"; import { getFunctionParts, isScriptDataInput } from "./helpers"; import { WebAuthnSignature } from "../../core/crypto/webauthn"; +import { getSigningMessage } from "../../internal/transactionSubmission"; /** * We are defining function signatures, each with its specific input and output. @@ -458,8 +459,8 @@ export async function signWithPasskey(args: { ]; // Get the signing message and hash it to create the challenge - const transactionToSign = deriveTransactionType(transaction); - const signingMessage = getSigningMessage(transactionToSign); + const transactionToSign: SimpleTransaction = { rawTransaction: deriveTransactionType(transaction) as RawTransaction }; + const signingMessage = getSigningMessage({ transaction: transactionToSign as AnyRawTransaction }); const challenge = sha3Hash(signingMessage); const options = await generateAuthenticationOptions({ @@ -504,9 +505,9 @@ export function getAuthenticatorForWebAuthn(args: { clientDataJSON: HexInput; }): AccountAuthenticator { const { publicKey, signature, authenticatorData, clientDataJSON } = args; - let signatureObj: Signature; + let signatureObj: AnySignature; if (publicKey instanceof Secp256r1PublicKey) { - signatureObj = new Secp256r1Signature(signature); + signatureObj = new AnySignature(new Secp256r1Signature(signature)); } else { throw new Error("Unsupported public key"); }