Skip to content

Commit b287b7b

Browse files
committed
fix(rosetta): use /v2/fees/transaction for fee estimation
1 parent 07339c0 commit b287b7b

File tree

4 files changed

+105
-42
lines changed

4 files changed

+105
-42
lines changed

package-lock.json

Lines changed: 30 additions & 30 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,10 @@
9191
"@promster/types": "3.2.3",
9292
"@scure/base": "1.1.1",
9393
"@sinclair/typebox": "0.31.28",
94-
"@stacks/common": "6.8.1",
95-
"@stacks/network": "6.8.1",
96-
"@stacks/stacking": "6.9.0",
97-
"@stacks/transactions": "6.9.0",
94+
"@stacks/common": "6.10.0",
95+
"@stacks/network": "6.11.3",
96+
"@stacks/stacking": "6.11.3",
97+
"@stacks/transactions": "6.11.3",
9898
"@types/express-list-endpoints": "4.0.1",
9999
"@types/lru-cache": "5.1.1",
100100
"@types/ws": "7.4.7",

src/api/routes/rosetta/construction.ts

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import {
3737
MessageSignature,
3838
noneCV,
3939
OptionalCV,
40+
principalCV,
4041
someCV,
4142
StacksTransaction,
4243
standardPrincipalCV,
@@ -310,6 +311,8 @@ export function createRosettaConstructionRouter(db: PgStore, chainId: ChainID):
310311
const request: RosettaConstructionMetadataRequest = req.body;
311312
const options: RosettaOptions = request.options;
312313

314+
let dummyTransaction: StacksTransaction;
315+
313316
if (options?.sender_address && !isValidC32Address(options.sender_address)) {
314317
res.status(400).json(RosettaErrors[RosettaErrorsTypes.invalidSender]);
315318
return;
@@ -337,6 +340,20 @@ export function createRosettaConstructionRouter(db: PgStore, chainId: ChainID):
337340
res.status(400).json(RosettaErrors[RosettaErrorsTypes.invalidRecipient]);
338341
return;
339342
}
343+
344+
// dummy transaction to calculate fee
345+
const dummyTokenTransferTx: UnsignedTokenTransferOptions = {
346+
recipient: recipientAddress,
347+
amount: 1n, // placeholder
348+
publicKey: '000000000000000000000000000000000000000000000000000000000000000000', // placeholder
349+
network: getStacksNetwork(),
350+
nonce: 0, // placeholder
351+
memo: '123456', // placeholder
352+
anchorMode: AnchorMode.Any,
353+
};
354+
// Do not set fee so that the fee is calculated
355+
dummyTransaction = await makeUnsignedSTXTokenTransfer(dummyTokenTransferTx);
356+
340357
break;
341358
case RosettaOperationType.StackStx: {
342359
// Getting PoX info
@@ -353,6 +370,27 @@ export function createRosettaConstructionRouter(db: PgStore, chainId: ChainID):
353370
options.contract_address = contractAddress;
354371
options.contract_name = contractName;
355372
options.burn_block_height = burnBlockHeight;
373+
374+
// dummy transaction to calculate fee
375+
const dummyStackingTx: UnsignedContractCallOptions = {
376+
publicKey: '000000000000000000000000000000000000000000000000000000000000000000',
377+
contractAddress: contractAddress,
378+
contractName: contractName,
379+
functionName: 'stack-stx',
380+
functionArgs: [
381+
uintCV(0),
382+
poxAddressToTuple('bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'), // placeholder
383+
uintCV(0),
384+
uintCV(1),
385+
],
386+
validateWithAbi: false,
387+
network: getStacksNetwork(),
388+
nonce: 0,
389+
anchorMode: AnchorMode.Any,
390+
};
391+
// Do not set fee so that the fee is calculated
392+
dummyTransaction = await makeUnsignedContractCall(dummyStackingTx);
393+
356394
break;
357395
}
358396
case RosettaOperationType.DelegateStx: {
@@ -361,6 +399,27 @@ export function createRosettaConstructionRouter(db: PgStore, chainId: ChainID):
361399
const [contractAddress, contractName] = contract.split('.');
362400
options.contract_address = contractAddress;
363401
options.contract_name = contractName;
402+
403+
// dummy transaction to calculate fee
404+
const dummyDelegateStxTx: UnsignedContractCallOptions = {
405+
publicKey: '000000000000000000000000000000000000000000000000000000000000000000',
406+
contractAddress: 'ST000000000000000000002AMW42H',
407+
contractName: 'pox',
408+
functionName: 'delegate-stx',
409+
functionArgs: [
410+
uintCV(1), // placeholder
411+
principalCV('SP3FGQ8Z7JY9BWYZ5WM53E0M9NK7WHJF0691NZ159.some-contract-name-v1-2-3-4'), // placeholder,
412+
someCV(uintCV(1)), // placeholder
413+
someCV(poxAddressToTuple('bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4')), // placeholder
414+
],
415+
validateWithAbi: false,
416+
network: getStacksNetwork(),
417+
nonce: 0,
418+
anchorMode: AnchorMode.Any,
419+
};
420+
// Do not set fee so that the fee is calculated
421+
dummyTransaction = await makeUnsignedContractCall(dummyDelegateStxTx);
422+
364423
break;
365424
}
366425
default:
@@ -392,8 +451,8 @@ export function createRosettaConstructionRouter(db: PgStore, chainId: ChainID):
392451
};
393452

394453
// Getting fee info if not operation fee was given in /preprocess
395-
const feeInfo = await new StacksCoreRpcClient().getEstimatedTransferFee();
396-
if (feeInfo === undefined || feeInfo === '0') {
454+
const feeValue = dummyTransaction.auth.spendingCondition.fee.toString();
455+
if (feeValue === undefined || feeValue === '0') {
397456
res.status(400).json(RosettaErrors[RosettaErrorsTypes.invalidFee]);
398457
return;
399458
}
@@ -402,7 +461,7 @@ export function createRosettaConstructionRouter(db: PgStore, chainId: ChainID):
402461
res.status(400).json(RosettaErrorsTypes.missingTransactionSize);
403462
return;
404463
}
405-
const feeValue = Math.round(Number(feeInfo) * Number(options.size) * 1.5).toString();
464+
406465
const currency: RosettaCurrency = {
407466
symbol: RosettaConstants.symbol,
408467
decimals: RosettaConstants.decimals,

src/tests-rosetta-construction/construction.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ describe('Rosetta Construction', () => {
349349
expect(result.type).toBe('application/json');
350350
expect(JSON.parse(result.text)).toHaveProperty('metadata');
351351
expect(JSON.parse(result.text)).toHaveProperty('suggested_fee');
352-
expect(JSON.parse(result.text).suggested_fee[0].value).toBe('270');
352+
expect(parseInt(JSON.parse(result.text).suggested_fee[0].value)).toBeGreaterThan(100);
353353
expect(JSON.parse(result.text).metadata.memo).toBe('SAMPLE MEMO');
354354
});
355355

@@ -1584,7 +1584,7 @@ describe('Rosetta Construction', () => {
15841584
expect(JSON.parse(result.text).metadata).toHaveProperty('contract_address');
15851585
expect(JSON.parse(result.text).metadata).toHaveProperty('contract_name');
15861586
expect(JSON.parse(result.text).metadata).toHaveProperty('burn_block_height');
1587-
expect(JSON.parse(result.text).suggested_fee[0].value).toBe('390');
1587+
expect(parseInt(JSON.parse(result.text).suggested_fee[0].value)).toBeGreaterThan(100);
15881588
});
15891589

15901590
test('construction/metadata - delegate_stacking', async () => {
@@ -1638,7 +1638,9 @@ describe('Rosetta Construction', () => {
16381638
account_sequence: nonce,
16391639
recent_block_hash: '0x969e494d5aee0166016836f97bbeb3d9473bea8427e477e9de253f78d3212354',
16401640
},
1641-
suggested_fee: [{ value: '390', currency: { symbol: 'STX', decimals: 6 } }],
1641+
suggested_fee: [
1642+
{ value: expect.stringMatching(/^\d+$/), currency: { symbol: 'STX', decimals: 6 } },
1643+
],
16421644
};
16431645

16441646
expect(result.body).toHaveProperty('metadata');
@@ -1808,7 +1810,7 @@ describe('Rosetta Construction', () => {
18081810
expect(JSON.parse(resultMetadata.text).metadata).toHaveProperty('contract_address');
18091811
expect(JSON.parse(resultMetadata.text).metadata).toHaveProperty('contract_name');
18101812
expect(JSON.parse(resultMetadata.text).metadata).toHaveProperty('burn_block_height');
1811-
expect(JSON.parse(resultMetadata.text).suggested_fee[0].value).toBe('390');
1813+
expect(parseInt(JSON.parse(resultMetadata.text).suggested_fee[0].value)).toBeGreaterThan(100);
18121814

18131815
//payloads
18141816
const contract_address = resultMetadata.body.metadata.contract_address;
@@ -2255,7 +2257,9 @@ describe('Rosetta Construction', () => {
22552257
account_sequence: nonce,
22562258
recent_block_hash: '0x969e494d5aee0166016836f97bbeb3d9473bea8427e477e9de253f78d3212354',
22572259
},
2258-
suggested_fee: [{ value: '380', currency: { symbol: 'STX', decimals: 6 } }],
2260+
suggested_fee: [
2261+
{ value: expect.stringMatching(/^\d+$/), currency: { symbol: 'STX', decimals: 6 } },
2262+
],
22592263
};
22602264
expect(resultMetadata.body).toHaveProperty('metadata');
22612265
expect(resultMetadata.body.suggested_fee).toStrictEqual(metadataResponse.suggested_fee);

0 commit comments

Comments
 (0)