-
Notifications
You must be signed in to change notification settings - Fork 960
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
signAndSendTransaction + signAndSendAllTransactions API #889
base: sign-and-send-all-transactions
Are you sure you want to change the base?
Changes from 1 commit
94cb465
0f1d065
d3c6337
566088f
157f431
65755db
f99e918
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,23 +18,22 @@ export interface SignAndSendTransactionOptions extends SendOptions { | |
|
||
export interface SendOptions { | ||
minContextSlot?: number; | ||
/** @deprecated Wallets are not expected to support this option. */ | ||
/** @deprecated Wallets are not expected to support this option. */ | ||
skipPreflight?: boolean; | ||
/** @deprecated Wallets are not expected to support this option. */ | ||
/** @deprecated Wallets are not expected to support this option. */ | ||
preflightCommitment?: Commitment; | ||
/** @deprecated Wallets are not expected to support this option. */ | ||
/** @deprecated Wallets are not expected to support this option. */ | ||
maxRetries?: number; | ||
/** Mode for signing and sending transactions. */ | ||
mode?: SolanaSignAndSendTransactionMode; | ||
} | ||
|
||
/** Mode for signing and sending transactions. */ | ||
export type SolanaSignAndSendTransactionMode = 'parallel' | 'serial'; | ||
|
||
/** @deprecated Use `SignAndSendTransactionOptions` instead. */ | ||
export type SendTransactionOptions = SignAndSendTransactionOptions; | ||
|
||
export interface SignAndSendAllTransactionsError { | ||
type: string; | ||
code: number; | ||
message: string; | ||
} | ||
|
||
// WalletName is a nominal type that wallet adapters should use, e.g. `'MyCryptoWallet' as WalletName<'MyCryptoWallet'>` | ||
// https://medium.com/@KevinBGreene/surviving-the-typescript-ecosystem-branding-and-type-tagging-6cf6e516523d | ||
export type WalletName<T extends string = string> = T & { __brand__: 'WalletName' }; | ||
|
@@ -61,7 +60,7 @@ export interface WalletAdapterProps<Name extends string = string> { | |
transactions: TransactionOrVersionedTransaction<this['supportedTransactionVersions']>[], | ||
connection: Connection, | ||
options?: SignAndSendTransactionOptions | ||
): Promise<(TransactionSignature | SignAndSendAllTransactionsError)[]>; | ||
): Promise<(TransactionSignature | undefined)[]>; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Returning Unfortunately returning either What is an app supposed to do with this result? I don't think we can kick the can on having an error of some kind. |
||
/** @deprecated Use `signAndSendTransaction` instead. */ | ||
sendTransaction( | ||
transaction: TransactionOrVersionedTransaction<this['supportedTransactionVersions']>, | ||
|
@@ -134,17 +133,12 @@ export abstract class BaseWalletAdapter<Name extends string = string> | |
transactions: TransactionOrVersionedTransaction<this['supportedTransactionVersions']>[], | ||
connection: Connection, | ||
options?: SignAndSendTransactionOptions | undefined | ||
): Promise<(TransactionSignature | SignAndSendAllTransactionsError)[]> { | ||
): Promise<(TransactionSignature | undefined)[]> { | ||
const results = await Promise.allSettled( | ||
transactions.map((transaction) => this.signAndSendTransaction(transaction, connection, options)) | ||
); | ||
return results.map((result) => { | ||
if (result.status === 'fulfilled') return result.value; | ||
return { | ||
type: result.reason.type || result.reason.name, | ||
code: result.reason.code, | ||
message: result.reason.message, | ||
}; | ||
return result.status === 'fulfilled' ? result.value : undefined; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. |
||
}); | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,6 +43,10 @@ interface PhantomWallet extends EventEmitter<PhantomWalletEvents> { | |
transaction: T, | ||
options?: SendOptions | ||
): Promise<{ signature: TransactionSignature }>; | ||
signAndSendAllTransactions<T extends Transaction | VersionedTransaction>( | ||
transactions: T[], | ||
options?: SendOptions | ||
): Promise<{ signatures: TransactionSignature[] }>; | ||
signMessage(message: Uint8Array): Promise<{ signature: Uint8Array }>; | ||
connect(): Promise<void>; | ||
disconnect(): Promise<void>; | ||
|
@@ -224,6 +228,43 @@ export class PhantomWalletAdapter extends BaseMessageSignerWalletAdapter { | |
} | ||
} | ||
|
||
async signAndSendAllTransactions<T extends Transaction | VersionedTransaction>( | ||
transactions: T[], | ||
connection: Connection, | ||
options: SignAndSendTransactionOptions = {} | ||
): Promise<TransactionSignature[]> { | ||
try { | ||
const wallet = this._wallet; | ||
if (!wallet) throw new WalletNotConnectedError(); | ||
|
||
try { | ||
const { signers, ...sendOptions } = options; | ||
|
||
transactions = await Promise.all( | ||
transactions.map(async (transaction) => { | ||
if (isVersionedTransaction(transaction)) { | ||
signers?.length && transaction.sign(signers); | ||
} else { | ||
transaction = (await this.prepareTransaction(transaction, connection, sendOptions)) as T; | ||
signers?.length && (transaction as Transaction).partialSign(...signers); | ||
} | ||
return transaction; | ||
}) | ||
); | ||
sendOptions.preflightCommitment = sendOptions.preflightCommitment || connection.commitment; | ||
|
||
const { signatures } = await wallet.signAndSendAllTransactions(transactions, sendOptions); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we can call this without feature detection because there's no guarantee of what version of the wallet the user has that supports this method. If it's older, it'll just null reference with nothing for the app to do. We should consider having/calling a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suppose we don't even need to add an implementation for signAndSendAll in individual wallet adapters (other than the unsafe burner, where we won't have to do feature detection)? |
||
return signatures; | ||
} catch (error: any) { | ||
if (error instanceof WalletError) throw error; | ||
throw new WalletSendTransactionError(error?.message, error); | ||
} | ||
} catch (error: any) { | ||
this.emit('error', error); | ||
throw error; | ||
} | ||
} | ||
|
||
async signTransaction<T extends Transaction | VersionedTransaction>(transaction: T): Promise<T> { | ||
try { | ||
const wallet = this._wallet; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to re-export this from the
@solana/wallet-standard-features
package.