Skip to content

Commit aa73382

Browse files
asimm241zone117x
authored andcommitted
refactor: removed support for multi-sig from combine and payloads
1 parent 46af37a commit aa73382

File tree

3 files changed

+75
-110
lines changed

3 files changed

+75
-110
lines changed

src/api/rosetta-constants.ts

+10
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,16 @@ export const RosettaErrors: Record<string, RosettaError> = {
222222
message: 'Signature(s) not verified with this public key(s)',
223223
retriable: false,
224224
},
225+
needOnePublicKey: {
226+
code: 636,
227+
message: 'Need one public key for single signature',
228+
retriable: false,
229+
},
230+
needOnlyOneSignature: {
231+
code: 637,
232+
message: 'Need only one signature',
233+
retriable: false,
234+
},
225235
};
226236

227237
// All request types, used to validate input.

src/api/routes/rosetta/construction.ts

+33-46
Original file line numberDiff line numberDiff line change
@@ -384,12 +384,6 @@ export function createRosettaConstructionRouter(db: DataStore): RouterWithAsync
384384
res.status(400).json(RosettaErrors.emptyPublicKey);
385385
return;
386386
}
387-
for (const key of publicKeys) {
388-
if (key.curve_type !== 'secp256k1') {
389-
res.status(400).json(RosettaErrors.invalidCurveType);
390-
return;
391-
}
392-
}
393387

394388
const recipientAddress = options.token_transfer_recipient_address;
395389
if (!recipientAddress) {
@@ -407,21 +401,15 @@ export function createRosettaConstructionRouter(db: DataStore): RouterWithAsync
407401

408402
let tokenTransferOptions: UnsignedTokenTransferOptions | UnsignedMultiSigTokenTransferOptions;
409403

410-
if (publicKeys.length > 1) {
411-
//multi signature
412-
const publicKeysStrings = publicKeys.map(key => {
413-
return key.hex_bytes;
414-
});
415-
tokenTransferOptions = {
416-
recipient: recipientAddress,
417-
amount: new BN(amount),
418-
fee: new BN(fees),
419-
publicKeys: publicKeysStrings,
420-
numSignatures: publicKeys.length,
421-
network: GetStacksTestnetNetwork(),
422-
nonce: accountInfo.nonce ? new BN(accountInfo.nonce) : new BN(0),
423-
};
404+
if (publicKeys.length !== 1) {
405+
//TODO support multi-sig in the future.
406+
res.status(400).json(RosettaErrors.needOnePublicKey);
407+
return;
424408
} else {
409+
if (publicKeys[0].curve_type !== 'secp256k1') {
410+
res.status(400).json(RosettaErrors.invalidCurveType);
411+
return;
412+
}
425413
// signel signature
426414
tokenTransferOptions = {
427415
recipient: recipientAddress,
@@ -481,36 +469,35 @@ export function createRosettaConstructionRouter(db: DataStore): RouterWithAsync
481469
return;
482470
}
483471

484-
for (const signature of signatures) {
485-
if (signature.public_key.curve_type !== 'secp256k1') {
486-
res.status(400).json(RosettaErrors.invalidCurveType);
487-
return;
488-
}
489-
const preSignHash = makePresignHash(transaction);
490-
if (!preSignHash) {
491-
res.status(400).json(RosettaErrors.invalidTransactionString);
492-
return;
493-
}
472+
if (signatures.length !== 1) res.status(400).json(RosettaErrors.needOnlyOneSignature);
494473

495-
let newSignature: MessageSignature;
474+
if (signatures[0].public_key.curve_type !== 'secp256k1') {
475+
res.status(400).json(RosettaErrors.invalidCurveType);
476+
return;
477+
}
478+
const preSignHash = makePresignHash(transaction);
479+
if (!preSignHash) {
480+
res.status(400).json(RosettaErrors.invalidTransactionString);
481+
return;
482+
}
496483

497-
try {
498-
newSignature = createMessageSignature(signature.signing_payload.hex_bytes);
499-
} catch (error) {
500-
res.status(400).json(RosettaErrors.invalidSignature);
501-
return;
502-
}
484+
let newSignature: MessageSignature;
503485

504-
if (!verifySignature(preSignHash, signature.public_key.hex_bytes, newSignature)) {
505-
res.status(400).json(RosettaErrors.signatureNotVerified);
506-
}
486+
try {
487+
newSignature = createMessageSignature(signatures[0].signing_payload.hex_bytes);
488+
} catch (error) {
489+
res.status(400).json(RosettaErrors.invalidSignature);
490+
return;
491+
}
507492

508-
if (transaction.auth.spendingCondition && isSingleSig(transaction.auth.spendingCondition)) {
509-
transaction.auth.spendingCondition.signature = newSignature;
510-
} else {
511-
const authField = createTransactionAuthField(newSignature);
512-
transaction.auth.spendingCondition?.fields.push(authField);
513-
}
493+
if (!verifySignature(preSignHash, signatures[0].public_key.hex_bytes, newSignature)) {
494+
res.status(400).json(RosettaErrors.signatureNotVerified);
495+
}
496+
497+
if (transaction.auth.spendingCondition && isSingleSig(transaction.auth.spendingCondition)) {
498+
transaction.auth.spendingCondition.signature = newSignature;
499+
} else {
500+
//support multi-sig
514501
}
515502

516503
const serializedTx = transaction.serialize().toString('hex');

src/tests-rosetta/api.ts

+32-64
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import {
4141
import { RosettaConstants, RosettaErrors } from '../api/rosetta-constants';
4242
import { GetStacksTestnetNetwork, testnetKeys } from '../api/routes/debug';
4343
import { getOptionsFromOperations, getSignature } from '../rosetta-helpers';
44+
import { MessageSignature } from '@blockstack/stacks-transactions/lib/authorization';
4445

4546
describe('Rosetta API', () => {
4647
let db: PgDataStore;
@@ -135,6 +136,8 @@ describe('Rosetta API', () => {
135136
message: 'Signature(s) not verified with this public key(s)',
136137
retriable: false,
137138
},
139+
{ code: 636, message: 'Need one public key for single signature', retriable: false },
140+
{ code: 637, message: 'Need only one signature', retriable: false },
138141
],
139142
historical_balance_lookup: true,
140143
},
@@ -1255,7 +1258,7 @@ describe('Rosetta API', () => {
12551258
expect(JSON.parse(result.text)).toEqual(expectedResponse);
12561259
});
12571260

1258-
test('payloads multi sign success', async () => {
1261+
test('payloads multi sig', async () => {
12591262
const publicKey1 = publicKeyToString(pubKeyfromPrivKey(testnetKeys[0].secretKey));
12601263
const publicKey2 = publicKeyToString(pubKeyfromPrivKey(testnetKeys[1].secretKey));
12611264

@@ -1345,39 +1348,14 @@ describe('Rosetta API', () => {
13451348
],
13461349
};
13471350

1348-
const accountInfo = await new StacksCoreRpcClient().getAccount(sender);
1349-
1350-
const tokenTransferOptions: UnsignedMultiSigTokenTransferOptions = {
1351-
recipient: recipient,
1352-
amount: new BN('500000'),
1353-
fee: new BN(fee),
1354-
publicKeys: [publicKey1, publicKey2],
1355-
numSignatures: 2,
1356-
network: GetStacksTestnetNetwork(),
1357-
nonce: accountInfo.nonce ? new BN(accountInfo.nonce) : new BN(0),
1358-
};
1359-
1360-
const transaction = await makeUnsignedSTXTokenTransfer(tokenTransferOptions);
1361-
const unsignedTransaction = transaction.serialize();
1362-
const hexBytes = digestSha512_256(unsignedTransaction).toString('hex');
1363-
13641351
const result = await supertest(api.server)
13651352
.post(`/rosetta/v1/construction/payloads`)
13661353
.send(request);
13671354

1368-
expect(result.status).toBe(200);
1355+
expect(result.status).toBe(400);
13691356
expect(result.type).toBe('application/json');
13701357

1371-
const expectedResponse = {
1372-
unsigned_transaction: unsignedTransaction.toString('hex'),
1373-
payloads: [
1374-
{
1375-
address: sender,
1376-
hex_bytes: '0x' + hexBytes,
1377-
signature_type: 'ecdsa',
1378-
},
1379-
],
1380-
};
1358+
const expectedResponse = RosettaErrors.needOnePublicKey;
13811359

13821360
expect(JSON.parse(result.text)).toEqual(expectedResponse);
13831361
});
@@ -1578,8 +1556,7 @@ describe('Rosetta API', () => {
15781556
signer.signOrigin(createStacksPrivateKey(testnetKeys[0].secretKey));
15791557
const signedSerializedTx = unsignedTransaction.serialize().toString('hex');
15801558

1581-
const signature = getSignature(unsignedTransaction);
1582-
if (!signature) return;
1559+
const signature: MessageSignature = getSignature(unsignedTransaction) as MessageSignature;
15831560

15841561
const request: RosettaConstructionCombineRequest = {
15851562
network_identifier: {
@@ -1617,49 +1594,42 @@ describe('Rosetta API', () => {
16171594
expect(JSON.parse(result.text)).toEqual(expectedResponse);
16181595
});
16191596

1620-
test('combine multi sign success', async () => {
1621-
const publicKey1 = publicKeyToString(pubKeyfromPrivKey(testnetKeys[0].secretKey));
1622-
const publicKey2 = publicKeyToString(pubKeyfromPrivKey(testnetKeys[1].secretKey));
1623-
1624-
const txOptions: UnsignedMultiSigTokenTransferOptions = {
1625-
publicKeys: [publicKey1, publicKey2],
1626-
numSignatures: 2,
1627-
recipient: standardPrincipalCV(testnetKeys[1].stacksAddress),
1628-
amount: new BigNum(12345),
1629-
network: GetStacksTestnetNetwork(),
1630-
memo: 'test memo',
1631-
nonce: new BigNum(0),
1632-
fee: new BigNum(200),
1633-
};
1634-
1635-
const unsignedTransaction = await makeUnsignedSTXTokenTransfer(txOptions);
1636-
const unsignedSerializedTx = unsignedTransaction.serialize().toString('hex');
1637-
1638-
const signer = new TransactionSigner(unsignedTransaction);
1639-
signer.signOrigin(createStacksPrivateKey(testnetKeys[0].secretKey));
1640-
const signedSerializedTx = unsignedTransaction.serialize().toString('hex');
1641-
1642-
const signature = getSignature(unsignedTransaction);
1643-
if (!signature) return;
1644-
1597+
test('combine multi sig', async () => {
16451598
const request: RosettaConstructionCombineRequest = {
16461599
network_identifier: {
16471600
blockchain: 'stacks',
16481601
network: 'testnet',
16491602
},
1650-
unsigned_transaction: unsignedSerializedTx,
1603+
unsigned_transaction:
1604+
'00000000010400539886f96611ba3ba6cef9618f8c78118b37c5be0000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003020000000000051ab71a091b4b8b7661a661c620966ab6573bc2dcd3000000000007a12074657374207472616e73616374696f6e000000000000000000000000000000000000',
16511605
signatures: [
16521606
{
16531607
signing_payload: {
1654-
hex_bytes: signature.data,
1608+
hex_bytes:
1609+
'017c7fc676effda9d905440a052d304b5d9705c30625e654f5b3c9ed461337cdec695d14e5f24091d61f8409f2ab703102ca840dbf5ef752ec534fe1f418552201',
16551610
signature_type: 'ecdsa',
16561611
},
16571612
public_key: {
1658-
hex_bytes: publicKey1,
1613+
hex_bytes: '025c13b2fc2261956d8a4ad07d481b1a3b2cbf93a24f992249a61c3a1c4de79c51',
16591614
curve_type: 'secp256k1',
16601615
},
16611616
signature_type: 'ecdsa',
1662-
hex_bytes: signature.data,
1617+
hex_bytes:
1618+
'017c7fc676effda9d905440a052d304b5d9705c30625e654f5b3c9ed461337cdec695d14e5f24091d61f8409f2ab703102ca840dbf5ef752ec534fe1f418552201',
1619+
},
1620+
{
1621+
signing_payload: {
1622+
hex_bytes:
1623+
'017c7fc676effda9d905440a052d304b5d9705c30625e654f5b3c9ed461337cdec695d14e5f24091d61f8409f2ab703102ca840dbf5ef752ec534fe1f418552201',
1624+
signature_type: 'ecdsa',
1625+
},
1626+
public_key: {
1627+
hex_bytes: '025c13b2fc2261956d8a4ad07d481b1a3b2cbf93a24f992249a61c3a1c4de79c51',
1628+
curve_type: 'secp256k1',
1629+
},
1630+
signature_type: 'ecdsa',
1631+
hex_bytes:
1632+
'017c7fc676effda9d905440a052d304b5d9705c30625e654f5b3c9ed461337cdec695d14e5f24091d61f8409f2ab703102ca840dbf5ef752ec534fe1f418552201',
16631633
},
16641634
],
16651635
};
@@ -1668,12 +1638,10 @@ describe('Rosetta API', () => {
16681638
.post(`/rosetta/v1/construction/combine`)
16691639
.send(request);
16701640

1671-
expect(result.status).toBe(200);
1641+
expect(result.status).toBe(400);
16721642
expect(result.type).toBe('application/json');
16731643

1674-
const expectedResponse: RosettaConstructionCombineResponse = {
1675-
signed_transaction: signedSerializedTx,
1676-
};
1644+
const expectedResponse = RosettaErrors.needOnlyOneSignature;
16771645

16781646
expect(JSON.parse(result.text)).toEqual(expectedResponse);
16791647
});
@@ -1772,7 +1740,7 @@ describe('Rosetta API', () => {
17721740
signer.signOrigin(createStacksPrivateKey(testnetKeys[1].secretKey)); // use different secret key to sign
17731741

17741742
const signature = getSignature(unsignedTransaction);
1775-
if (!signature) return;
1743+
if (!signature) throw Error('Signature undefined');
17761744

17771745
const request: RosettaConstructionCombineRequest = {
17781746
network_identifier: {

0 commit comments

Comments
 (0)