diff --git a/packages/wallets/src/signers/evm-api-key.ts b/packages/wallets/src/signers/evm-api-key.ts index 4d70f979f..184624ca5 100644 --- a/packages/wallets/src/signers/evm-api-key.ts +++ b/packages/wallets/src/signers/evm-api-key.ts @@ -9,6 +9,13 @@ export class EVMApiKeySigner implements Signer { return this.config.locator; } + async sign() { + return await Promise.reject( + new Error( + "API key signers do not support direct transaction signing - transaction are handled automatically by the backend" + ) + ); + } async signMessage() { return await Promise.reject( new Error( diff --git a/packages/wallets/src/signers/evm-external-wallet.ts b/packages/wallets/src/signers/evm-external-wallet.ts index e44a85a76..dea11f02e 100644 --- a/packages/wallets/src/signers/evm-external-wallet.ts +++ b/packages/wallets/src/signers/evm-external-wallet.ts @@ -25,11 +25,11 @@ export class EVMExternalWalletSigner implements Signer { return this.config.locator; } - async signMessage(message: string) { + async sign(payload: string): Promise<{ signature: string }> { if (this.provider != null) { const signature = await this.provider.request({ method: "personal_sign", - params: [message, this._address] as any, + params: [payload, this._address] as any, }); if (signature == null) { throw new Error( @@ -41,7 +41,7 @@ export class EVMExternalWalletSigner implements Signer { if (this.viemAccount?.signMessage != null) { const signature = await this.viemAccount.signMessage({ message: { - raw: message as `0x${string}`, + raw: payload as `0x${string}`, }, }); if (signature == null) { @@ -54,7 +54,11 @@ export class EVMExternalWalletSigner implements Signer { throw new Error("No signer provider or viem account provided"); } + async signMessage(message: string) { + return await this.sign(message); + } + async signTransaction(transaction: string) { - return await this.signMessage(transaction); + return await this.sign(transaction); } } diff --git a/packages/wallets/src/signers/non-custodial/ncs-evm-signer.ts b/packages/wallets/src/signers/non-custodial/ncs-evm-signer.ts index ecb5ab480..7dcd48131 100644 --- a/packages/wallets/src/signers/non-custodial/ncs-evm-signer.ts +++ b/packages/wallets/src/signers/non-custodial/ncs-evm-signer.ts @@ -8,7 +8,13 @@ export class EVMNonCustodialSigner extends NonCustodialSigner { super(config); } - async signMessage(message: string) { + async signMessage(message: string, raw?: boolean) { + if (raw && message) { + if (!isHex(message)) { + throw new Error("Invalid hex string in signMessage raw argument"); + } + return await this.sign(message); + } const messageRaw = isHex(message) ? (message as Hex) : toHex(message); const messageToSign = PersonalMessage.getSignPayload(messageRaw); return await this.sign(messageToSign); @@ -18,11 +24,11 @@ export class EVMNonCustodialSigner extends NonCustodialSigner { return await this.sign(transaction); } - private async sign(raw: string): Promise<{ signature: string }> { + async sign(payload: string): Promise<{ signature: string }> { await this.handleAuthRequired(); const jwt = this.getJwtOrThrow(); - const hexString = raw.replace("0x", ""); + const hexString = payload.replace("0x", ""); const res = await this.config.clientTEEConnection?.sendAction({ event: "request:sign", diff --git a/packages/wallets/src/signers/non-custodial/ncs-signer.ts b/packages/wallets/src/signers/non-custodial/ncs-signer.ts index d1b27e42b..c60257778 100644 --- a/packages/wallets/src/signers/non-custodial/ncs-signer.ts +++ b/packages/wallets/src/signers/non-custodial/ncs-signer.ts @@ -26,6 +26,7 @@ export abstract class NonCustodialSigner implements Signer { return this.config.address; } + abstract sign(payload: string): Promise; abstract signMessage(message: string): Promise; private async initialize() { diff --git a/packages/wallets/src/signers/non-custodial/ncs-solana-signer.ts b/packages/wallets/src/signers/non-custodial/ncs-solana-signer.ts index ddf96fa4d..ee99da8b3 100644 --- a/packages/wallets/src/signers/non-custodial/ncs-solana-signer.ts +++ b/packages/wallets/src/signers/non-custodial/ncs-solana-signer.ts @@ -9,16 +9,20 @@ export class SolanaNonCustodialSigner extends NonCustodialSigner { } async signMessage() { - return await Promise.reject(new Error("signMessage method not implemented for email signer")); + return await Promise.reject(new Error("signMessage method not implemented for Solana email signer")); } async signTransaction(transaction: string): Promise<{ signature: string }> { - await this.handleAuthRequired(); - const jwt = this.getJwtOrThrow(); - const transactionBytes = base58.decode(transaction); const deserializedTransaction = VersionedTransaction.deserialize(transactionBytes); - const messageData = deserializedTransaction.message.serialize(); + const messageData = base58.encode(deserializedTransaction.message.serialize()); + + return await this.sign(messageData); + } + + async sign(payload: string): Promise<{ signature: string }> { + await this.handleAuthRequired(); + const jwt = this.getJwtOrThrow(); const res = await this.config.clientTEEConnection?.sendAction({ event: "request:sign", @@ -30,7 +34,7 @@ export class SolanaNonCustodialSigner extends NonCustodialSigner { }, data: { keyType: "ed25519", - bytes: base58.encode(messageData), + bytes: payload, encoding: "base58", }, }, @@ -42,7 +46,7 @@ export class SolanaNonCustodialSigner extends NonCustodialSigner { } if (res?.signature == null) { - throw new Error("Failed to sign transaction"); + throw new Error("Failed to sign payload"); } SolanaNonCustodialSigner.verifyPublicKeyFormat(res.publicKey); return { signature: res.signature.bytes }; diff --git a/packages/wallets/src/signers/non-custodial/ncs-stellar-signer.ts b/packages/wallets/src/signers/non-custodial/ncs-stellar-signer.ts index dc0660b98..3d23d91f5 100644 --- a/packages/wallets/src/signers/non-custodial/ncs-stellar-signer.ts +++ b/packages/wallets/src/signers/non-custodial/ncs-stellar-signer.ts @@ -6,6 +6,10 @@ export class StellarNonCustodialSigner extends NonCustodialSigner { super(config); } + async sign() { + return Promise.reject(new Error("sign method not implemented for stellar signer")); + } + async signMessage() { return await Promise.reject(new Error("signMessage method not implemented for stellar signer")); } diff --git a/packages/wallets/src/signers/passkey.ts b/packages/wallets/src/signers/passkey.ts index 1c47df6b8..fce8d4b12 100644 --- a/packages/wallets/src/signers/passkey.ts +++ b/packages/wallets/src/signers/passkey.ts @@ -13,13 +13,13 @@ export class PasskeySigner implements Signer { return this.config.locator; } - async signMessage(message: string): Promise { + async sign(payload: string): Promise { if (this.config.onSignWithPasskey) { - return await this.config.onSignWithPasskey(message); + return await this.config.onSignWithPasskey(payload); } const { signature, metadata } = await WebAuthnP256.sign({ credentialId: this.id, - challenge: message as `0x${string}`, + challenge: payload as `0x${string}`, }); return { @@ -31,7 +31,11 @@ export class PasskeySigner implements Signer { }; } + async signMessage(message: string): Promise { + return await this.sign(message); + } + async signTransaction(transaction: string) { - return await this.signMessage(transaction); + return await this.sign(transaction); } } diff --git a/packages/wallets/src/signers/solana-api-key.ts b/packages/wallets/src/signers/solana-api-key.ts index fa30b3cdc..e6ca63846 100644 --- a/packages/wallets/src/signers/solana-api-key.ts +++ b/packages/wallets/src/signers/solana-api-key.ts @@ -9,6 +9,10 @@ export class SolanaApiKeySigner implements Signer { return this.config.locator; } + async sign(payload: string) { + return await Promise.reject(new Error("sign method not implemented for solana api key signer")); + } + async signMessage() { return await Promise.reject( new Error( diff --git a/packages/wallets/src/signers/solana-external-wallet.ts b/packages/wallets/src/signers/solana-external-wallet.ts index 5a65af5f1..a8bba996f 100644 --- a/packages/wallets/src/signers/solana-external-wallet.ts +++ b/packages/wallets/src/signers/solana-external-wallet.ts @@ -25,6 +25,10 @@ export class SolanaExternalWalletSigner implements Signer { return this.config.locator; } + async sign(payload: string) { + return await Promise.reject(new Error("sign method not implemented for solana external wallet signer")); + } + async signMessage() { return await Promise.reject(new Error("signMessage method not implemented for solana external wallet signer")); } diff --git a/packages/wallets/src/signers/stellar-external-wallet.ts b/packages/wallets/src/signers/stellar-external-wallet.ts index 4484cea71..bcdc83e86 100644 --- a/packages/wallets/src/signers/stellar-external-wallet.ts +++ b/packages/wallets/src/signers/stellar-external-wallet.ts @@ -22,6 +22,10 @@ export class StellarExternalWalletSigner implements Signer { return this.config.locator; } + async sign(payload: string) { + return await Promise.reject(new Error("signMessage method not implemented for stellar external wallet signer")); + } + async signMessage() { return await Promise.reject(new Error("signMessage method not implemented for stellar external wallet signer")); } diff --git a/packages/wallets/src/signers/types.ts b/packages/wallets/src/signers/types.ts index 0d7720018..eb464b027 100644 --- a/packages/wallets/src/signers/types.ts +++ b/packages/wallets/src/signers/types.ts @@ -138,6 +138,7 @@ export interface Signer { type: T; locator(): string; address?(): string; + sign(payload: string): Promise; signMessage(message: string): Promise; signTransaction(transaction: string): Promise; } diff --git a/packages/wallets/src/wallets/wallet.ts b/packages/wallets/src/wallets/wallet.ts index ff47a3fb6..033f265eb 100644 --- a/packages/wallets/src/wallets/wallet.ts +++ b/packages/wallets/src/wallets/wallet.ts @@ -388,10 +388,14 @@ export class Wallet { } } - protected get isSolanaWallet(): boolean { + protected isSolanaWallet(): boolean { return this.chain === "solana"; } + protected isStellarWallet(): boolean { + return this.chain === "stellar"; + } + protected async approveTransactionAndWait(transactionId: string, options?: ApproveOptions) { await this.approveTransactionInternal(transactionId, options); await this.sleep(1_000); // Rule of thumb: tx won't be confirmed in less than 1 second @@ -405,7 +409,7 @@ export class Wallet { } protected async approveSignatureInternal(signatureId: string, options?: ApproveOptions) { - if (this.isSolanaWallet) { + if (this.isSolanaWallet() || this.isStellarWallet()) { throw new Error("Approving signatures is only supported for EVM smart wallets"); } @@ -442,7 +446,7 @@ export class Wallet { throw new InvalidSignerError(`Signer ${pendingApproval.signer} not found in pending approvals`); } - return signer.signMessage(pendingApproval.message); + return signer.sign(pendingApproval.message); }) );