diff --git a/.changeset/nervous-mayflies-reply.md b/.changeset/nervous-mayflies-reply.md new file mode 100644 index 00000000..f23a3987 --- /dev/null +++ b/.changeset/nervous-mayflies-reply.md @@ -0,0 +1,7 @@ +--- +"@aptos-labs/wallet-adapter-react": major +"@aptos-labs/wallet-adapter-core": major +"@aptos-labs/wallet-adapter-nextjs-example": major +--- + +Refactor the account info output type to be compatible with AIP-62 diff --git a/apps/nextjs-example/src/app/page.tsx b/apps/nextjs-example/src/app/page.tsx index 032a79e0..e75363e7 100644 --- a/apps/nextjs-example/src/app/page.tsx +++ b/apps/nextjs-example/src/app/page.tsx @@ -25,6 +25,7 @@ import { WalletSelector as AntdWalletSelector } from "@aptos-labs/wallet-adapter import { WalletConnector as MuiWalletSelector } from "@aptos-labs/wallet-adapter-mui-design"; import { AccountInfo, + AccountInfoOutput, AptosChangeNetworkOutput, NetworkInfo, WalletInfo, @@ -48,7 +49,9 @@ import { registerWallet } from "@aptos-labs/wallet-standard"; registerWallet(myWallet); })(); -const isTelegramMiniApp = typeof window !== 'undefined' && (window as any).TelegramWebviewProxy !== undefined; +const isTelegramMiniApp = + typeof window !== "undefined" && + (window as any).TelegramWebviewProxy !== undefined; if (isTelegramMiniApp) { initTelegram(); } @@ -147,7 +150,7 @@ function WalletSelection() { } interface WalletConnectionProps { - account: AccountInfo | null; + account: AccountInfoOutput | null; network: NetworkInfo | null; wallet: WalletInfo | null; changeNetwork: (network: Network) => Promise; @@ -225,7 +228,7 @@ function WalletConnection({ label: "Address", value: ( ), diff --git a/apps/nextjs-example/src/components/WalletSelector.tsx b/apps/nextjs-example/src/components/WalletSelector.tsx index e66ea8c3..c5b86fd2 100644 --- a/apps/nextjs-example/src/components/WalletSelector.tsx +++ b/apps/nextjs-example/src/components/WalletSelector.tsx @@ -54,7 +54,7 @@ export function WalletSelector(walletSortingOptions: WalletSortingOptions) { const copyAddress = useCallback(async () => { if (!account?.address) return; try { - await navigator.clipboard.writeText(account.address); + await navigator.clipboard.writeText(account.address.toString()); toast({ title: "Success", description: "Copied wallet address to clipboard.", diff --git a/apps/nextjs-example/src/components/transactionFlows/SingleSigner.tsx b/apps/nextjs-example/src/components/transactionFlows/SingleSigner.tsx index 5da557e5..53c6f1ed 100644 --- a/apps/nextjs-example/src/components/transactionFlows/SingleSigner.tsx +++ b/apps/nextjs-example/src/components/transactionFlows/SingleSigner.tsx @@ -77,7 +77,7 @@ export function SingleSigner() { data: { function: "0x1::coin::transfer", typeArguments: [parseTypeTag(APTOS_COIN)], - functionArguments: [AccountAddress.from(account.address), new U64(1)], // 1 is in Octas + functionArguments: [account.address, new U64(1)], // 1 is in Octas }, }); await aptosClient(network).waitForTransaction({ @@ -99,7 +99,7 @@ export function SingleSigner() { type: "entry_function_payload", function: "0x1::coin::transfer", type_arguments: ["0x1::aptos_coin::AptosCoin"], - arguments: [account?.address, 1], // 1 is in Octas + arguments: [account?.address.toString(), 1], // 1 is in Octas }; const response = await signTransaction(payload); toast({ @@ -116,13 +116,13 @@ export function SingleSigner() { try { const transactionToSign = await aptosClient( - network, + network ).transaction.build.simple({ sender: account.address, data: { function: "0x1::coin::transfer", typeArguments: [APTOS_COIN], - functionArguments: [account.address, 1], // 1 is in Octas + functionArguments: [account.address.toString(), 1], // 1 is in Octas }, }); const response = await signTransaction(transactionToSign); diff --git a/packages/wallet-adapter-core/src/AIP62StandardWallets/WalletStandard.ts b/packages/wallet-adapter-core/src/AIP62StandardWallets/WalletStandard.ts index 688bf03b..afc040aa 100644 --- a/packages/wallet-adapter-core/src/AIP62StandardWallets/WalletStandard.ts +++ b/packages/wallet-adapter-core/src/AIP62StandardWallets/WalletStandard.ts @@ -130,11 +130,11 @@ export class WalletStandardCore { transaction: AnyRawTransaction, wallet: Wallet, asFeePayer?: boolean - ): Promise + ): Promise; async signTransaction( input: AptosSignTransactionInputV1_1, - wallet: Wallet, - ): Promise + wallet: Wallet + ): Promise; async signTransaction( transactionOrInput: AnyRawTransaction | AptosSignTransactionInputV1_1, wallet: Wallet, diff --git a/packages/wallet-adapter-core/src/AIP62StandardWallets/types.ts b/packages/wallet-adapter-core/src/AIP62StandardWallets/types.ts index e0ba26a9..e2b01d2f 100644 --- a/packages/wallet-adapter-core/src/AIP62StandardWallets/types.ts +++ b/packages/wallet-adapter-core/src/AIP62StandardWallets/types.ts @@ -1,3 +1,4 @@ +import { AccountAddress, PublicKey } from "@aptos-labs/ts-sdk"; import { WalletName } from "../LegacyWalletPlugins/types"; import { WalletReadyState } from "../constants"; @@ -16,6 +17,21 @@ export interface AptosStandardSupportedWallet { isAIP62Standard: true; } +export type StandardAccountInfoInput = { + address: AccountAddress; + publicKey: PublicKey; + ansName?: string; +}; + +// Output type for the account to support AIP-62 standard wallets +export type AccountInfoOutput = { + address: AccountAddress; + // PublicKey[] for backward compatibility, + publicKey: PublicKey | PublicKey[]; + minKeysRequired?: number; + ansName?: string | null; +}; + // Update this with the name of your wallet when you create a new wallet plugin. export type AvailableWallets = | "Nightly" diff --git a/packages/wallet-adapter-core/src/LegacyWalletPlugins/types.ts b/packages/wallet-adapter-core/src/LegacyWalletPlugins/types.ts index edeed803..652b7978 100644 --- a/packages/wallet-adapter-core/src/LegacyWalletPlugins/types.ts +++ b/packages/wallet-adapter-core/src/LegacyWalletPlugins/types.ts @@ -8,7 +8,8 @@ import { InputGenerateTransactionPayloadData, AnyRawTransaction, Signature, - AccountAuthenticator, + AccountAddress, + PublicKey, } from "@aptos-labs/ts-sdk"; import { WalletReadyState } from "../constants"; import { @@ -20,7 +21,10 @@ import { AptosChangeNetworkMethod, AptosSignAndSubmitTransactionInput, } from "@aptos-labs/wallet-standard"; -import { AptosStandardSupportedWallet } from "../AIP62StandardWallets/types"; +import { + AptosStandardSupportedWallet, + StandardAccountInfoInput, +} from "../AIP62StandardWallets/types"; export { TxnBuilderTypes, Types } from "aptos"; export type { @@ -55,6 +59,7 @@ export type WalletInfo = { url: string; }; +// Input type to handle legacy wallets that are not AIP-62 compatible export type AccountInfo = { address: string; publicKey: string | string[]; @@ -74,7 +79,7 @@ export declare interface WalletCoreEvents { readyStateChange(wallet: Wallet): void; standardWalletsAdded(wallets: Wallet | AptosStandardSupportedWallet): void; networkChange(network: NetworkInfo | null): void; - accountChange(account: AccountInfo | null): void; + accountChange(account: AccountInfo | StandardAccountInfoInput | null): void; } export interface SignMessagePayload { diff --git a/packages/wallet-adapter-core/src/WalletCore.ts b/packages/wallet-adapter-core/src/WalletCore.ts index 8f2bdf23..e742bb49 100644 --- a/packages/wallet-adapter-core/src/WalletCore.ts +++ b/packages/wallet-adapter-core/src/WalletCore.ts @@ -8,14 +8,13 @@ import { Ed25519PublicKey, InputGenerateTransactionOptions, Ed25519Signature, - AptosConfig, InputSubmitTransactionData, PendingTransactionResponse, Aptos, generateRawTransaction, SimpleTransaction, NetworkToChainId, - Hex, + PublicKey, } from "@aptos-labs/ts-sdk"; import EventEmitter from "eventemitter3"; import { @@ -60,7 +59,6 @@ import { WalletName, WalletCoreV1, CompatibleTransactionOptions, - convertNetwork, convertPayloadInputV1ToV2, generateTransactionPayloadFromV1Input, } from "./LegacyWalletPlugins"; @@ -80,6 +78,8 @@ import { WalletStandardCore, AptosStandardSupportedWallet, AvailableWallets, + StandardAccountInfoInput, + AccountInfoOutput, } from "./AIP62StandardWallets"; import { GA4 } from "./ga"; import { WALLET_ADAPTER_CORE_VERSION } from "./version"; @@ -131,7 +131,7 @@ export class WalletCore extends EventEmitter { private _wallet: Wallet | null = null; // Current connected account - private _account: AccountInfo | null = null; + private _account: AccountInfo | StandardAccountInfoInput | null = null; // Current connected network private _network: NetworkInfo | null = null; @@ -465,7 +465,7 @@ export class WalletCore extends EventEmitter { * @param account An account */ private ensureAccountExists( - account: AccountInfo | null + account: AccountInfo | StandardAccountInfoInput | null ): asserts account is AccountInfo { if (!account) { throw new WalletAccountError("Account is not set").name; @@ -541,57 +541,12 @@ export class WalletCore extends EventEmitter { * Sets the connected account * * `AccountInfo` type comes from a legacy wallet adapter plugin - * `StandardAccountInfo` type comes from AIP-62 standard compatible wallet when onAccountChange event is called - * `UserResponse` type comes from AIP-62 standard compatible wallet on wallet connect + * `StandardAccountInfo` type comes from AIP-62 standard compatible wallet * * @param account An account */ - setAccount( - account: - | AccountInfo - | StandardAccountInfo - | UserResponse - | null - ): void { - if (account === null) { - this._account = null; - return; - } - - // Check if wallet is of type AIP-62 standard - if (this._wallet?.isAIP62Standard) { - // Check if account is of type UserResponse which means the `account` - // comes from the `connect` method - if ("status" in account) { - const connectStandardAccount = - account as UserResponse; - if (connectStandardAccount.status === UserResponseStatus.REJECTED) { - this._connecting = false; - throw new WalletConnectionError("User has rejected the request") - .message; - } - // account is of type - this._account = { - address: connectStandardAccount.args.address.toString(), - publicKey: connectStandardAccount.args.publicKey.toString(), - ansName: connectStandardAccount.args.ansName, - }; - return; - } else { - // account is of type `StandardAccountInfo` which means it comes from onAccountChange event - const standardAccount = account as StandardAccountInfo; - this._account = { - address: standardAccount.address.toString(), - publicKey: standardAccount.publicKey.toString(), - ansName: standardAccount.ansName, - }; - return; - } - } - - // account is of type `AccountInfo` - this._account = { ...(account as AccountInfo) }; - return; + setAccount(account: AccountInfo | StandardAccountInfo | null): void { + this._account = account; } /** @@ -687,9 +642,30 @@ export class WalletCore extends EventEmitter { * @return account info * @throws WalletAccountError */ - get account(): AccountInfo | null { + get account(): AccountInfoOutput | null { try { - return this._account; + if (!this._account) return null; + return { + address: + typeof this._account.address === "string" + ? AccountAddress.from(this._account.address) + : this._account.address, + publicKey: + // for backward compatibility, if the account public key is of type `string` convert it to Ed25519PublicKey + typeof this._account.publicKey === "string" + ? new Ed25519PublicKey(this._account.publicKey) + : // for backward compatibility, if the account public key is of type `string[]` convert each string to Ed25519PublicKey + Array.isArray(this._account.publicKey) && + this._account.publicKey.every( + (item) => typeof item === "string" + ) + ? this._account.publicKey.map((key) => new Ed25519PublicKey(key)) + : // else, the account is of the new standard and return it with the exact type + (this._account.publicKey as PublicKey), + minKeysRequired: + (this._account as AccountInfo).minKeysRequired ?? undefined, + ansName: this._account.ansName, + }; } catch (error: any) { throw new WalletAccountError(error).message; } @@ -931,7 +907,7 @@ export class WalletCore extends EventEmitter { if (this._wallet.signTransaction) { // If current connected wallet is AIP-62 standard compatible // we want to make sure the transaction input is what the - // standard expects, i,e new sdk v2 input + // standard expects, i.e new sdk v2 input if (this._wallet.isAIP62Standard) { // if rawTransaction prop it means transaction input data is // compatible with new sdk v2 input diff --git a/packages/wallet-adapter-core/src/utils/walletSelector.ts b/packages/wallet-adapter-core/src/utils/walletSelector.ts index 3dc905bf..c7dd47cd 100644 --- a/packages/wallet-adapter-core/src/utils/walletSelector.ts +++ b/packages/wallet-adapter-core/src/utils/walletSelector.ts @@ -1,3 +1,4 @@ +import { AccountAddress } from "@aptos-labs/ts-sdk"; import { AptosStandardWallet } from "../AIP62StandardWallets"; import { WalletInfo } from "../LegacyWalletPlugins"; import { AnyAptosWallet } from "../WalletCore"; @@ -44,9 +45,9 @@ export function isInstallRequired(wallet: AnyAptosWallet) { } /** Truncates the provided wallet address at the middle with an ellipsis. */ -export function truncateAddress(address: string | undefined) { +export function truncateAddress(address: AccountAddress | undefined) { if (!address) return; - return `${address.slice(0, 6)}...${address.slice(-5)}`; + return `${address.toString().slice(0, 6)}...${address.toString().slice(-5)}`; } /** Returns `true` if the provided wallet is an Aptos Connect wallet. */ diff --git a/packages/wallet-adapter-react/src/WalletProvider.tsx b/packages/wallet-adapter-react/src/WalletProvider.tsx index 67930667..c79effa1 100644 --- a/packages/wallet-adapter-react/src/WalletProvider.tsx +++ b/packages/wallet-adapter-react/src/WalletProvider.tsx @@ -18,6 +18,7 @@ import type { Network, AptosStandardSupportedWallet, AvailableWallets, + AccountInfoOutput, } from "@aptos-labs/wallet-adapter-core"; import { DappConfig, WalletCore } from "@aptos-labs/wallet-adapter-core"; @@ -32,7 +33,7 @@ export interface AptosWalletProviderProps { } const initialState: { - account: AccountInfo | null; + account: AccountInfoOutput | null; network: NetworkInfo | null; connected: boolean; wallet: WalletInfo | null; diff --git a/packages/wallet-adapter-react/src/useWallet.tsx b/packages/wallet-adapter-react/src/useWallet.tsx index 98a531df..e333aaa6 100644 --- a/packages/wallet-adapter-react/src/useWallet.tsx +++ b/packages/wallet-adapter-react/src/useWallet.tsx @@ -16,13 +16,14 @@ import { AptosChangeNetworkOutput, Network, AptosStandardSupportedWallet, + AccountInfoOutput, } from "@aptos-labs/wallet-adapter-core"; import { createContext, useContext } from "react"; export interface WalletContextState { connected: boolean; isLoading: boolean; - account: AccountInfo | null; + account: AccountInfoOutput | null; network: NetworkInfo | null; connect(walletName: WalletName): void; disconnect(): void;