-
Notifications
You must be signed in to change notification settings - Fork 339
enhancement: Change signature of ClientOption.signTransaction to be able to pass KeyPair #1063 #1127
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
base: master
Are you sure you want to change the base?
Conversation
chadoh
left a comment
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.
This looks pretty good! Please update at least some of the e2e tests to show that it works. If it's easiest, you can change just test/e2e/src/util.ts to pass the keypair instead of using basicNodeSigner, which will update all the tests. But then we will need one new test using basicNodeSigner to ensure that both approaches continue to work.
|
@chadoh changes implemented. |
|
Hi @chadoh , please review, change has been implemented. |
|
Hi @chadoh , please review |
silence48
left a comment
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 not like to see the signTransaction get modified to be a signTransaction or a keypair... rather add keypair as an optional parameter to clientoptions, then update the sign and sign and send functions in the assembled_transaction file. I tried to leave comments and suggestions on how to fix. you'll need to also solve the tests tho.
| // Check if signTransaction is a Keypair | ||
| let signFunction: SignTransaction | undefined; | ||
|
|
||
| if (signTransaction instanceof Keypair) { | ||
| const keypair = signTransaction; | ||
| signFunction = basicNodeSigner(keypair, this.options.networkPassphrase).signTransaction; | ||
| } else if (typeof signTransaction === 'function') { | ||
| signFunction = signTransaction; | ||
| } | ||
|
|
||
| if (!signFunction) { |
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.
This could be less verbose, and arguably safer...
signFunction doesn't need to be a let it can be a const
| // Check if signTransaction is a Keypair | |
| let signFunction: SignTransaction | undefined; | |
| if (signTransaction instanceof Keypair) { | |
| const keypair = signTransaction; | |
| signFunction = basicNodeSigner(keypair, this.options.networkPassphrase).signTransaction; | |
| } else if (typeof signTransaction === 'function') { | |
| signFunction = signTransaction; | |
| } | |
| if (!signFunction) { | |
| if (!signTransaction && !keyPair) { | |
| throw new AssembledTransaction.Errors.NoSigner( | |
| "You must provide a signTransaction function, or a keypair either when calling " + | |
| "`signAndSend` or when initializing your Client" | |
| ); | |
| }; | |
| const signFunction = signTransaction ? signTransaction : basicNodeSigner(keypair, this.options.networkPassphrase).signTransaction |
However you'll also need to remove lines 699-703 also.
Further, you shouldn't modify the type SignTransaction you should just add keypair to clientoptions as an optional and update the sign function here around line 664... you also need to look at the signandsend function for consistency and update that correctly.
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.
you might be wondering what !keyPair is yet later in this review i suggest modifying the sign function to accept either the function or the keypair, then narrow it. There's a bunch of ways to do this but there's no easy way for me to show exactly how i would do it without making a whole new pr which i am not gonna do. Anyways if you have questions about my review feel free to reach out. thanks.
| // const signOpts: Parameters<NonNullable<ClientOptions['signTransaction']>>[1] = { | ||
| // networkPassphrase: this.options.networkPassphrase, | ||
| // }; | ||
| const signOpts: Parameters<SignTransaction>[1] = { |
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 think there's a better way to do this whole thing than modifying the signTransaction type which is supposed to match the function signature from freighter. Instead, modify the sign function to just either take a signTransaction OR a Keypair, then check if signTransaction is falsey you should build it using that simple node signer...
| // const signOpts: Parameters<NonNullable<ClientOptions['signTransaction']>>[1] = { | |
| // networkPassphrase: this.options.networkPassphrase, | |
| // }; | |
| const signOpts: Parameters<SignTransaction>[1] = { | |
| const signOpts: Parameters<SignTransaction>[1] = { |
it's fine to remove NonNullable here since it no longer is, but basically it needs to include EITHER signTransaction as a SignTransaction type or a keyPair as a KeyPair type...
| * Matches signature of `signTransaction` from Freighter. | ||
| */ | ||
| signTransaction?: SignTransaction; | ||
| signTransaction?: SignTransaction | Keypair; |
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.
| signTransaction?: SignTransaction | Keypair; | |
| signTransaction?: SignTransaction; | |
| keyPair?: Keypair; |
please, let's avoid overloading signTransaction with a Keypair. Keep Freighter’s SignTransaction type intact and handle a Keypair as a separate field. Then in sign, pick whichever one is provided—if we have a Keypair, wrap it with basicNodeSigner; if not, use signTransaction. That way, the code stays clean and you don’t break the original type. For example:
sign = async ({
force = false,
signTransaction = this.options.signTransaction,
keypair = this.options.keypair,
}: {
force?: boolean;
signTransaction?: SignTransaction;
keypair?: Keypair;
} = {}): Promise<void> => {
if (!this.built) throw new Error("Transaction has not been simulated yet.");
if (!force && this.isReadCall) {
throw new AssembledTransaction.Errors.NoSignatureNeeded("Read call; no signature needed unless `force: true`.");
}
let fn = signTransaction;
if (keypair) {
fn = basicNodeSigner(keypair, this.options.networkPassphrase).signTransaction;
}
if (!fn) {
throw new AssembledTransaction.Errors.NoSigner("Provide either a `signTransaction` function or a `keypair`.");
}
// Prepare signing options
const signOpts: Parameters<SignTransaction>[1] = {
networkPassphrase: this.options.networkPassphrase,
address: this.options.address,
submit: this.options.submit,
submitUrl: this.options.submitUrl,
};
const { signedTxXdr, error } = await fn(this.built.toXDR(), signOpts);
this.handleWalletError(error);
this.signed = TransactionBuilder.fromXDR(signedTxXdr, this.options.networkPassphrase);
};That’s it. You either provide a regular signTransaction method or a Keypair, never both in the same field, and you don’t tangle up the types.
|
|
||
| it("signs transaction using Keypair", async function () { | ||
| const result = await this.context.tx.sign({ | ||
| signTransaction: this.context.keypair, |
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.
signTransaction should be the function not a keypair.
Change signature of ClientOption.signTransaction to be able to pass KeyPair #1063
Closes #1063
Pull Request Description
Summary
This pull request modifies the
ClientOptionstype to allow thesignTransactionproperty to accept aKeypairin addition to a function. This change simplifies the process of signing transactions, especially for testing and simple applications, by allowing users to directly use aKeypairwithout needing to implement a custom signing function.Changes Made
signTransactionproperty to accept either aSignTransactionfunction or aKeypair.signmethod to handle the case wheresignTransactionis aKeypair.Keypairis provided, it uses thebasicNodeSignerto create a signing function.