Skip to content

Commit 59f91c3

Browse files
Shapticovercat
andauthored
Extend SigningCallback form to allow returning an object (#783)
* Add a way to return object from authorizeEntry callback Co-authored-by: Jun Luo <[email protected]>
1 parent 68b8bae commit 59f91c3

File tree

4 files changed

+55
-16
lines changed

4 files changed

+55
-16
lines changed

CHANGELOG.md

+11
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22

33
## Unreleased
44

5+
### Added
6+
* Within `authorizeEntry`, the `SigningCallback` callback function should now return an object containing both the signature and the identity of the signer. In multi-signature situations, it isn't necessarily the case that the address within the authorization entry is the one that actually signs that entry. Thus, the callback now takes the following form, where the original `Promise<BufferLike>` option is preserved for backwards compatibility and should be considered deprecated ([]()):
7+
```typescript
8+
export type SigningCallback = (
9+
preimage: xdr.HashIdPreimage
10+
) => Promise<
11+
BufferLike |
12+
{ signature: BufferLike, publicKey: string }
13+
>;
14+
```
15+
516

617
## [`v13.0.1`](https://github.com/stellar/js-stellar-base/compare/v13.0.0...v13.0.1)
718

src/auth.js

+28-11
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,14 @@ import { nativeToScVal } from './scval';
1717
* whose hash you should sign, so that you can inspect the entire structure
1818
* if necessary (rather than blindly signing a hash)
1919
*
20-
* @returns {Promise<Uint8Array>} the signature of the raw payload (which is
21-
* the sha256 hash of the preimage bytes, so `hash(preimage.toXDR())`) signed
20+
* @returns {
21+
* Promise<Uint8Array> |
22+
* Promise<{signature: Uint8Array, publicKey: string}
23+
* } the signature of the raw payload (which is the sha256 hash of the preimage
24+
* bytes, so `hash(preimage.toXDR())`) either naked, implying it is signed
2225
* by the key corresponding to the public key in the entry you pass to
2326
* {@link authorizeEntry} (decipherable from its
24-
* `credentials().address().address()`)
27+
* `credentials().address().address()`), or alongside an explicit `publicKey`.
2528
*/
2629

2730
/**
@@ -43,10 +46,17 @@ import { nativeToScVal } from './scval';
4346
*
4447
* @param {xdr.SorobanAuthorizationEntry} entry an unsigned authorization entr
4548
* @param {Keypair | SigningCallback} signer either a {@link Keypair} instance
46-
* or a function which takes a payload (a
47-
* {@link xdr.HashIdPreimageSorobanAuthorization} instance) input and returns
48-
* the signature of the hash of the raw payload bytes (where the signing key
49-
* should correspond to the address in the `entry`)
49+
* or a function which takes a {@link xdr.HashIdPreimageSorobanAuthorization}
50+
* input payload and returns EITHER
51+
*
52+
* (a) an object containing a `signature` of the hash of the raw payload bytes
53+
* as a Buffer-like and a `publicKey` string representing who just
54+
* created this signature, or
55+
* (b) just the naked signature of the hash of the raw payload bytes (where
56+
* the signing key is implied to be the address in the `entry`).
57+
*
58+
* The latter option (b) is JUST for backwards compatibility and will be
59+
* removed in the future.
5060
* @param {number} validUntilLedgerSeq the (exclusive) future ledger sequence
5161
* number until which this authorization entry should be valid (if
5262
* `currentLedgerSeq==validUntil`, this is expired))
@@ -58,8 +68,8 @@ import { nativeToScVal } from './scval';
5868
* {@link Operation.invokeHostFunction}
5969
*
6070
* @note If using the `SigningCallback` variation, the signer is assumed to be
61-
* the entry's credential address. If you need a different key to sign the
62-
* entry, you will need to use different method (e.g., fork this code).
71+
* the entry's credential address unless you use the variant that returns
72+
* the object.
6373
*
6474
* @see authorizeInvocation
6575
* @example
@@ -137,8 +147,15 @@ export async function authorizeEntry(
137147
let signature;
138148
let publicKey;
139149
if (typeof signer === 'function') {
140-
signature = Buffer.from(await signer(preimage));
141-
publicKey = Address.fromScAddress(addrAuth.address()).toString();
150+
const sigResult = await signer(preimage);
151+
if (sigResult?.signature) {
152+
signature = Buffer.from(sigResult.signature);
153+
publicKey = sigResult.publicKey;
154+
} else {
155+
// if using the deprecated form, assume it's for the entry
156+
signature = Buffer.from(sigResult);
157+
publicKey = Address.fromScAddress(addrAuth.address()).toString();
158+
}
142159
} else {
143160
signature = Buffer.from(signer.sign(payload));
144161
publicKey = signer.publicKey();

test/unit/auth_test.js

+11-4
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,16 @@ describe('building authorization entries', function () {
3535

3636
[
3737
[kp, 'Keypair'],
38-
[(preimage) => kp.sign(StellarBase.hash(preimage.toXDR())), 'callback']
38+
[(preimage) => kp.sign(StellarBase.hash(preimage.toXDR())), 'callback'],
39+
[
40+
(preimage) => {
41+
return {
42+
signature: kp.sign(StellarBase.hash(preimage.toXDR())),
43+
publicKey: kp.publicKey()
44+
};
45+
},
46+
'callback w/ obj'
47+
]
3948
].forEach(([signer, methodName]) => {
4049
it(`signs the entry correctly (${methodName})`, function (done) {
4150
StellarBase.authorizeEntry(authEntry, signer, 10)
@@ -87,9 +96,7 @@ describe('building authorization entries', function () {
8796

8897
it('can build from scratch', function (done) {
8998
StellarBase.authorizeInvocation(kp, 10, authEntry.rootInvocation())
90-
.then((signedEntry) => {
91-
done();
92-
})
99+
.then((signedEntry) => done())
93100
.catch((err) => done(err));
94101
});
95102
});

types/index.d.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -1214,9 +1214,13 @@ export class SorobanDataBuilder {
12141214
build(): xdr.SorobanTransactionData;
12151215
}
12161216

1217+
type BufferLike = Buffer | Uint8Array | ArrayBuffer;
12171218
export type SigningCallback = (
12181219
preimage: xdr.HashIdPreimage
1219-
) => Promise<Buffer | Uint8Array | ArrayBuffer /* Buffer-like */>;
1220+
) => Promise<
1221+
BufferLike |
1222+
{ signature: BufferLike, publicKey: string }
1223+
>;
12201224

12211225
export function authorizeInvocation(
12221226
signer: Keypair | SigningCallback,

0 commit comments

Comments
 (0)