diff --git a/.changeset/cyan-worms-own.md b/.changeset/cyan-worms-own.md new file mode 100644 index 000000000..30ed8efb8 --- /dev/null +++ b/.changeset/cyan-worms-own.md @@ -0,0 +1,23 @@ +--- +"@crossmint/wallets-sdk": major +--- + +# Breaking Change: Promote experimental APIs to stable + +We're promoting several experimental APIs to stable by removing the `experimental_` prefix. This is a breaking change that requires updating your code. + +## Migration Guide + +Update your code to use the new stable API names: + +- `experimental_prepareOnly` → `prepareOnly` +- `experimental_callbacks` → `callbacks` +- `experimental_loginWithOAuth` → `loginWithOAuth` +- `experimental_getNfts` → `getNfts` +- `experimental_activity` → `activity` +- `experimental_signer` → `signer` +- `experimental_approval` → `approval` +- `experimental_transaction` → `transaction` +- `experimental_transactions` → `transactions` + +These APIs have been thoroughly tested and are now considered stable for production use. \ No newline at end of file diff --git a/apps/wallets/quickstart-devkit/components/activity.tsx b/apps/wallets/quickstart-devkit/components/activity.tsx index b5ecd9311..3e3554b6a 100644 --- a/apps/wallets/quickstart-devkit/components/activity.tsx +++ b/apps/wallets/quickstart-devkit/components/activity.tsx @@ -14,7 +14,7 @@ export function Activity() { } setLoading(true); try { - const activity = await wallet.experimental_activity(); + const activity = await wallet.activity(); setActivity(activity); } catch (error) { console.error("Error fetching wallet activity:", error); diff --git a/apps/wallets/quickstart-devkit/components/approval-test.tsx b/apps/wallets/quickstart-devkit/components/approval-test.tsx index a58646e69..6ba301727 100644 --- a/apps/wallets/quickstart-devkit/components/approval-test.tsx +++ b/apps/wallets/quickstart-devkit/components/approval-test.tsx @@ -60,7 +60,7 @@ export function ApprovalTest() { // const evmWallet = EVMWallet.from(wallet); // const txn = await evmWallet.sendTransaction({ // transaction: "0x", - // options: { experimental_prepareOnly: true }, + // options: { prepareOnly: true }, // }); // const sigSigned = await evmWallet.signTypedData({ @@ -86,12 +86,12 @@ export function ApprovalTest() { // chainId: BigInt(1), // verifyingContract: "0x0000000000000000000000000000000000000000", // }, - // options: { experimental_prepareOnly: false }, + // options: { prepareOnly: false }, // }); // const sigMessage = await evmWallet.signMessage({ // message: "Hello, world!", - // options: { experimental_prepareOnly: true }, + // options: { prepareOnly: true }, // }); try { @@ -103,7 +103,7 @@ export function ApprovalTest() { prepareTransfer.recipient, prepareTransfer.token, prepareTransfer.amount, - { experimental_prepareOnly: true } + { prepareOnly: true } ); setPreparedTransactionId(transaction.transactionId); diff --git a/packages/client/react-base/src/providers/CrossmintWalletBaseProvider.tsx b/packages/client/react-base/src/providers/CrossmintWalletBaseProvider.tsx index 2aac2ad71..cff087c87 100644 --- a/packages/client/react-base/src/providers/CrossmintWalletBaseProvider.tsx +++ b/packages/client/react-base/src/providers/CrossmintWalletBaseProvider.tsx @@ -176,8 +176,8 @@ export function CrossmintWalletBaseProvider({ setWalletStatus("in-progress"); const wallets = CrossmintWallets.from(crossmint); - const _onWalletCreationStart = args.options?.experimental_callbacks?.onWalletCreationStart; - const _onTransactionStart = args.options?.experimental_callbacks?.onTransactionStart; + const _onWalletCreationStart = args.options?.callbacks?.onWalletCreationStart; + const _onTransactionStart = args.options?.callbacks?.onTransactionStart; const resolvedSigner = resolveSignerConfig(args.signer) as SignerConfigForChain; @@ -192,7 +192,7 @@ export function CrossmintWalletBaseProvider({ alias: args.alias, options: { clientTEEConnection: clientTEEConnection?.(), - experimental_callbacks: { + callbacks: { onWalletCreationStart: _onWalletCreationStart ?? callbacks?.onWalletCreationStart, onTransactionStart: _onTransactionStart ?? callbacks?.onTransactionStart, }, @@ -240,7 +240,7 @@ export function CrossmintWalletBaseProvider({ signer: resolvedSigner, options: { clientTEEConnection: clientTEEConnection?.(), - experimental_callbacks: callbacks, + callbacks: callbacks, shadowSignerStorage, }, }); diff --git a/packages/client/ui/react-ui/src/hooks/useAuth.ts b/packages/client/ui/react-ui/src/hooks/useAuth.ts index dc026bab4..9d313af03 100644 --- a/packages/client/ui/react-ui/src/hooks/useAuth.ts +++ b/packages/client/ui/react-ui/src/hooks/useAuth.ts @@ -4,7 +4,7 @@ import type { OAuthProvider } from "@crossmint/common-sdk-auth"; import { AuthContext } from "@/providers"; export interface CrossmintAuthContext extends CrossmintAuthBaseContextType { - experimental_loginWithOAuth: (provider: OAuthProvider) => Promise; + loginWithOAuth: (provider: OAuthProvider) => Promise; } export function useCrossmintAuth(): CrossmintAuthContext { diff --git a/packages/client/ui/react-ui/src/providers/CrossmintAuthProvider.tsx b/packages/client/ui/react-ui/src/providers/CrossmintAuthProvider.tsx index 3dad5eaf6..c04d55345 100644 --- a/packages/client/ui/react-ui/src/providers/CrossmintAuthProvider.tsx +++ b/packages/client/ui/react-ui/src/providers/CrossmintAuthProvider.tsx @@ -26,7 +26,7 @@ const defaultContextValue: CrossmintAuthContext = { status: "initializing", getUser: () => {}, experimental_externalWalletSigner: undefined, - experimental_loginWithOAuth: () => Promise.resolve(), + loginWithOAuth: () => Promise.resolve(), loginMethods: [], }; @@ -112,7 +112,7 @@ function CrossmintAuthProviderContent({ return "logged-out"; }, [baseAuth.status, baseAuth.jwt, isWeb3Enabled, dynamicSdkLoaded, dialogOpen]); - const experimental_loginWithOAuth = useCallback( + const loginWithOAuth = useCallback( async (provider: OAuthProvider) => { if (baseAuth.jwt != null) { console.log("User already logged in"); @@ -129,10 +129,10 @@ function CrossmintAuthProviderContent({ login, status: getAuthStatus(), experimental_externalWalletSigner: externalWalletSigner, - experimental_loginWithOAuth, + loginWithOAuth, loginMethods, }), - [baseAuth, login, getAuthStatus, externalWalletSigner, experimental_loginWithOAuth, loginMethods] + [baseAuth, login, getAuthStatus, externalWalletSigner, loginWithOAuth, loginMethods] ); return ( diff --git a/packages/wallets/README.md b/packages/wallets/README.md index d66f7dbb0..ad6849de8 100644 --- a/packages/wallets/README.md +++ b/packages/wallets/README.md @@ -61,7 +61,7 @@ console.log(transaction.explorerLink); ### Get wallet activity ```ts -const activity = await wallet.experimental_activity(); +const activity = await wallet.activity(); console.log(activity.events); ``` diff --git a/packages/wallets/src/api/client.ts b/packages/wallets/src/api/client.ts index 16a35110a..eb7ede731 100644 --- a/packages/wallets/src/api/client.ts +++ b/packages/wallets/src/api/client.ts @@ -125,7 +125,7 @@ class ApiClient extends CrossmintApiClient { return response.json(); } - async experimental_getNfts(params: { + async getNfts(params: { address: string; perPage: number; page: number; @@ -141,7 +141,7 @@ class ApiClient extends CrossmintApiClient { return response.json(); } - async experimental_activity(walletLocator: WalletLocator, params: { chain: Chain }): Promise { + async activity(walletLocator: WalletLocator, params: { chain: Chain }): Promise { let legacyLocator = walletLocator; if (!this.isServerSide) { legacyLocator = `me:${params.chain === "solana" ? "solana-smart-wallet" : "evm-smart-wallet"}`; diff --git a/packages/wallets/src/wallets/evm.ts b/packages/wallets/src/wallets/evm.ts index 73553fbfa..a4d5ac039 100644 --- a/packages/wallets/src/wallets/evm.ts +++ b/packages/wallets/src/wallets/evm.ts @@ -46,7 +46,7 @@ export class EVMWallet extends Wallet { const builtTransaction = this.buildTransaction(params); const createdTransaction = await this.createTransaction(builtTransaction, params.options); - if (params.options?.experimental_prepareOnly) { + if (params.options?.prepareOnly) { return { hash: undefined, explorerLink: undefined, @@ -73,7 +73,7 @@ export class EVMWallet extends Wallet { throw new SignatureNotCreatedError(JSON.stringify(signatureCreationResponse)); } - if (params.options?.experimental_prepareOnly) { + if (params.options?.prepareOnly) { return { signature: undefined, signatureId: signatureCreationResponse.id, @@ -120,7 +120,7 @@ export class EVMWallet extends Wallet { throw new SignatureNotCreatedError(JSON.stringify(signatureCreationResponse)); } - if (params.options?.experimental_prepareOnly) { + if (params.options?.prepareOnly) { return { signature: undefined, signatureId: signatureCreationResponse.id, @@ -141,7 +141,7 @@ export class EVMWallet extends Wallet { transaction: FormattedEVMTransaction, options?: TransactionInputOptions ): Promise { - const signer = options?.experimental_signer ?? this.signer.locator(); + const signer = options?.signer ?? this.signer.locator(); const transactionCreationResponse = await this.apiClient.createTransaction(this.walletLocator, { params: { signer, diff --git a/packages/wallets/src/wallets/solana.ts b/packages/wallets/src/wallets/solana.ts index a0f78f8c9..9142d07bf 100644 --- a/packages/wallets/src/wallets/solana.ts +++ b/packages/wallets/src/wallets/solana.ts @@ -42,7 +42,7 @@ export class SolanaWallet extends Wallet { await this.preAuthIfNeeded(); const createdTransaction = await this.createTransaction(params); - if (params.options?.experimental_prepareOnly) { + if (params.options?.prepareOnly) { return { hash: undefined, explorerLink: undefined, @@ -71,7 +71,7 @@ export class SolanaWallet extends Wallet { } private async createTransaction(params: SolanaTransactionInput): Promise { - const signer = params.options?.experimental_signer ?? this.signer.locator(); + const signer = params.options?.signer ?? this.signer.locator(); let serializedTransaction: string; diff --git a/packages/wallets/src/wallets/stellar.ts b/packages/wallets/src/wallets/stellar.ts index deafc9c69..a39365be8 100644 --- a/packages/wallets/src/wallets/stellar.ts +++ b/packages/wallets/src/wallets/stellar.ts @@ -40,7 +40,7 @@ export class StellarWallet extends Wallet { await this.preAuthIfNeeded(); const createdTransaction = await this.createTransaction(params); - if (params.options?.experimental_prepareOnly) { + if (params.options?.prepareOnly) { return { hash: undefined, explorerLink: undefined, @@ -55,7 +55,7 @@ export class StellarWallet extends Wallet { private async createTransaction(params: StellarTransactionInput): Promise { const { contractId, options } = params; - const signer = options?.experimental_signer ?? this.signer.locator(); + const signer = options?.signer ?? this.signer.locator(); let transaction: any; diff --git a/packages/wallets/src/wallets/types.ts b/packages/wallets/src/wallets/types.ts index 4ae4433a3..17590363d 100644 --- a/packages/wallets/src/wallets/types.ts +++ b/packages/wallets/src/wallets/types.ts @@ -10,10 +10,10 @@ import type { ShadowSignerStorage } from "../signers/shadow-signer"; export type { Activity } from "../api/types"; -export type PrepareOnly = { experimental_prepareOnly: T }; +export type PrepareOnly = { prepareOnly: T }; export type TransactionInputOptions = PrepareOnly & { - experimental_signer?: string; + signer?: string; }; export type SignatureInputOptions = PrepareOnly; @@ -116,7 +116,7 @@ export type StellarWalletPlugin = string; export type WalletPlugin = C extends StellarChain ? StellarWalletPlugin : never; export type WalletOptions = { - experimental_callbacks?: Callbacks; + callbacks?: Callbacks; clientTEEConnection?: HandshakeParent; shadowSignerStorage?: ShadowSignerStorage; shadowSignerEnabled?: boolean; @@ -188,7 +188,7 @@ export type Signature = TPrepareOnly exten }; export type ApproveOptions = { - experimental_approval?: Approval; + approval?: Approval; additionalSigners?: Signer[]; }; diff --git a/packages/wallets/src/wallets/wallet-factory.ts b/packages/wallets/src/wallets/wallet-factory.ts index 2a0b2b0d1..fefea1ada 100644 --- a/packages/wallets/src/wallets/wallet-factory.ts +++ b/packages/wallets/src/wallets/wallet-factory.ts @@ -100,7 +100,7 @@ export class WalletFactory { } public async createWallet(args: WalletCreateArgs): Promise> { - await args.options?.experimental_callbacks?.onWalletCreationStart?.(); + await args.options?.callbacks?.onWalletCreationStart?.(); let adminSignerConfig = args.onCreateConfig?.adminSigner ?? args.signer; const { delegatedSigners, shadowSignerPublicKey, shadowSignerPublicKeyBase64 } = diff --git a/packages/wallets/src/wallets/wallet.ts b/packages/wallets/src/wallets/wallet.ts index 9b8ce4951..9bdb486c3 100644 --- a/packages/wallets/src/wallets/wallet.ts +++ b/packages/wallets/src/wallets/wallet.ts @@ -216,7 +216,7 @@ export class Wallet { * @experimental This API is experimental and may change in the future */ public async experimental_nfts(params: { perPage: number; page: number }) { - return await this.#apiClient.experimental_getNfts({ + return await this.#apiClient.getNfts({ ...params, chain: this.chain, address: this.address, @@ -228,7 +228,7 @@ export class Wallet { * @returns The transactions * @throws {Error} If the transactions cannot be retrieved */ - public async experimental_transactions(): Promise { + public async transactions(): Promise { const response = await this.#apiClient.getTransactions(this.walletLocator); if ("error" in response) { throw new Error(`Failed to get transactions: ${JSON.stringify(response.message)}`); @@ -241,7 +241,7 @@ export class Wallet { * @returns The transaction * @throws {Error} If the transaction cannot be retrieved */ - public async experimental_transaction(transactionId: string): Promise { + public async transaction(transactionId: string): Promise { const response = await this.#apiClient.getTransaction(this.walletLocator, transactionId); if ("error" in response) { throw new Error(`Failed to get transaction: ${JSON.stringify(response.error)}`); @@ -255,8 +255,8 @@ export class Wallet { * @experimental This API is experimental and may change in the future * @throws {Error} If the activity cannot be retrieved */ - public async experimental_activity(): Promise { - const response = await this.apiClient.experimental_activity(this.walletLocator, { chain: this.chain }); + public async activity(): Promise { + const response = await this.apiClient.activity(this.walletLocator, { chain: this.chain }); if ("error" in response) { throw new Error(`Failed to get activity: ${JSON.stringify(response.message)}`); } @@ -283,9 +283,7 @@ export class Wallet { const sendParams = { recipient, amount, - ...(options?.experimental_signer != null - ? { signer: options.experimental_signer } - : { signer: this.signer.locator() }), + ...(options?.signer != null ? { signer: options.signer } : { signer: this.signer.locator() }), }; const transactionCreationResponse = await this.#apiClient.send(this.walletLocator, tokenLocator, sendParams); @@ -295,7 +293,7 @@ export class Wallet { ); } - if (options?.experimental_prepareOnly) { + if (options?.prepareOnly) { return { hash: undefined, explorerLink: undefined, @@ -312,7 +310,7 @@ export class Wallet { * @param params - The parameters * @param params.transactionId - The transaction id * @param params.options - The options for the transaction - * @param params.options.experimental_approval - The approval + * @param params.options.approval - The approval * @param params.options.additionalSigners - The additional signers * @returns The transaction */ @@ -330,7 +328,7 @@ export class Wallet { * @param params.transactionId - The transaction id or * @param params.signatureId - The signature id * @param params.options - The options for the transaction - * @param params.options.experimental_approval - The approval + * @param params.options.approval - The approval * @param params.options.additionalSigners - The additional signers * @returns The transaction or signature */ @@ -349,7 +347,7 @@ export class Wallet { * Add a delegated signer to the wallet * @param signer - The signer. For Solana, it must be a string. For EVM, it can be a string or a passkey. * @param options - The options for the operation - * @param options.experimental_prepareOnly - If true, returns the transaction/signature ID without auto-approving + * @param options.prepareOnly - If true, returns the transaction/signature ID without auto-approving */ public async addDelegatedSigner(params: { signer: string | RegisterSignerPasskeyParams; @@ -371,7 +369,7 @@ export class Wallet { const transactionId = response.transaction.id; - if (params.options?.experimental_prepareOnly) { + if (params.options?.prepareOnly) { return { transactionId } as any; } @@ -385,7 +383,7 @@ export class Wallet { const chainResponse = response.chains?.[this.chain]; - if (params.options?.experimental_prepareOnly) { + if (params.options?.prepareOnly) { const signatureId = chainResponse?.status !== "success" ? chainResponse?.id : undefined; return { signatureId } as any; } @@ -502,8 +500,8 @@ export class Wallet { } // If an external signature is provided, use it to approve the transaction - if (options?.experimental_approval != null) { - const approvals = [options.experimental_approval]; + if (options?.approval != null) { + const approvals = [options.approval]; return await this.executeApproveSignatureWithErrorHandling(signatureId, approvals); } @@ -544,7 +542,7 @@ export class Wallet { throw new TransactionNotAvailableError(JSON.stringify(transaction)); } - await this.#options?.experimental_callbacks?.onTransactionStart?.(); + await this.#options?.callbacks?.onTransactionStart?.(); // API key signers approve automatically if (this.signer.type === "api-key") { @@ -552,8 +550,8 @@ export class Wallet { } // If an external signature is provided, use it to approve the transaction - if (options?.experimental_approval != null) { - const approvals = [options.experimental_approval]; + if (options?.approval != null) { + const approvals = [options.approval]; return await this.executeApproveTransactionWithErrorHandling(transactionId, approvals); }