From af463b0b082d380cb47b9770a67be5e161090daf Mon Sep 17 00:00:00 2001 From: janniks Date: Tue, 23 Jan 2024 01:43:42 +0100 Subject: [PATCH] fix: update rosetta to use signer-key --- .../rosetta-construction-options.schema.json | 4 ++++ src/api/routes/rosetta/construction.ts | 18 +++++++++--------- src/rosetta/rosetta-helpers.ts | 9 ++++++++- src/test-utils/test-helpers.ts | 2 ++ src/tests-2.5/pox-4-burnchain-delegate-stx.ts | 2 +- src/tests-2.5/pox-4-burnchain-stack-stx.ts | 4 ++-- src/tests-2.5/pox-4-rosetta-btc-addr-types.ts | 3 +++ src/tests-2.5/pox-4-rosetta-cycle-phases.ts | 3 +++ src/tests-2.5/pox-4-rosetta-segwit.ts | 4 ++++ 9 files changed, 36 insertions(+), 13 deletions(-) diff --git a/docs/entities/rosetta/rosetta-construction-options.schema.json b/docs/entities/rosetta/rosetta-construction-options.schema.json index 1617f00837..7d539ff25e 100644 --- a/docs/entities/rosetta/rosetta-construction-options.schema.json +++ b/docs/entities/rosetta/rosetta-construction-options.schema.json @@ -83,6 +83,10 @@ "pox_addr": { "type": "string", "description": "The reward address for stacking transaction. It should be a valid Bitcoin address" + }, + "signer_key": { + "type": "string", + "description": "The hex-encoded signer key (buff 33) for PoX." } } } diff --git a/src/api/routes/rosetta/construction.ts b/src/api/routes/rosetta/construction.ts index 011f2ee13d..f8f680411b 100644 --- a/src/api/routes/rosetta/construction.ts +++ b/src/api/routes/rosetta/construction.ts @@ -83,6 +83,7 @@ import { } from '../../../rosetta/rosetta-helpers'; import { makeRosettaError, rosettaValidateRequest, ValidSchema } from './../../rosetta-validate'; import { has0xPrefix, hexToBuffer } from '@hirosystems/api-toolkit'; +import { hexToBytes } from '@stacks/common'; export function createRosettaConstructionRouter(db: PgStore, chainId: ChainID): express.Router { const router = express.Router(); @@ -215,13 +216,12 @@ export function createRosettaConstructionRouter(db: PgStore, chainId: ChainID): break; case RosettaOperationType.StackStx: { const poxAddr = options.pox_addr; - if (!options.number_of_cycles || !poxAddr) { + if (!options.number_of_cycles || !options.signer_key || !poxAddr) { res.status(400).json(RosettaErrors[RosettaErrorsTypes.invalidOperation]); return; } if (doesThrow(() => decodeBtcAddress(poxAddr))) { - // todo: add error type specifically for this? res.status(400).json(RosettaErrors[RosettaErrorsTypes.invalidOperation]); return; } @@ -241,6 +241,7 @@ export function createRosettaConstructionRouter(db: PgStore, chainId: ChainID): poxAddressToTuple(poxAddr), uintCV(0), uintCV(options.number_of_cycles), + bufferCV(hexToBytes(options.signer_key)), ], validateWithAbi: false, network: getStacksNetwork(), @@ -252,11 +253,7 @@ export function createRosettaConstructionRouter(db: PgStore, chainId: ChainID): break; } case RosettaOperationType.DelegateStx: { - if (!options.amount) { - res.status(400).json(RosettaErrors[RosettaErrorsTypes.invalidOperation]); - return; - } - if (!options.delegate_to) { + if (!options.amount || !options.delegate_to || !options.signer_key) { res.status(400).json(RosettaErrors[RosettaErrorsTypes.invalidOperation]); return; } @@ -276,6 +273,7 @@ export function createRosettaConstructionRouter(db: PgStore, chainId: ChainID): standardPrincipalCV(options.delegate_to), noneCV(), poxAddrOptionalCV, + bufferCV(hexToBytes(options.signer_key)), ], validateWithAbi: false, network: getStacksNetwork(), @@ -656,7 +654,7 @@ export function createRosettaConstructionRouter(db: PgStore, chainId: ChainID): res.status(400).json(RosettaErrors[RosettaErrorsTypes.invalidOperation]); return; } - if (!options.number_of_cycles || !options.amount) { + if (!options.number_of_cycles || !options.amount || !options.signer_key) { res.status(400).json(RosettaErrors[RosettaErrorsTypes.invalidOperation]); return; } @@ -671,6 +669,7 @@ export function createRosettaConstructionRouter(db: PgStore, chainId: ChainID): poxAddressCV, uintCV(req.body.metadata.burn_block_height), uintCV(options.number_of_cycles), + bufferCV(hexToBytes(options.signer_key)), ], fee: txFee, nonce: nonce, @@ -712,7 +711,7 @@ export function createRosettaConstructionRouter(db: PgStore, chainId: ChainID): if (typeof burn_block_height !== 'number' || typeof burn_block_height !== 'string') expire_burn_block_heightCV = someCV(uintCV(burn_block_height)); } - if (!options.delegate_to || !options.amount) { + if (!options.delegate_to || !options.amount || !options.signer_key) { res.status(400).json(RosettaErrors[RosettaErrorsTypes.invalidOperation]); return; } @@ -727,6 +726,7 @@ export function createRosettaConstructionRouter(db: PgStore, chainId: ChainID): standardPrincipalCV(options.delegate_to), expire_burn_block_heightCV, poxAddressCV, + bufferCV(hexToBytes(options.signer_key)), ], fee: txFee, nonce: nonce, diff --git a/src/rosetta/rosetta-helpers.ts b/src/rosetta/rosetta-helpers.ts index 3ad4cc3553..c3a5b7fa4f 100644 --- a/src/rosetta/rosetta-helpers.ts +++ b/src/rosetta/rosetta-helpers.ts @@ -774,10 +774,13 @@ export function getOptionsFromOperations(operations: RosettaOperation[]): Rosett if (!operation.metadata || typeof operation.metadata.number_of_cycles !== 'number') { return null; } - + if (!operation.metadata || typeof operation.metadata.signer_key !== 'string') { + return null; + } options.sender_address = operation.account?.address; options.type = operation.type; options.number_of_cycles = operation.metadata.number_of_cycles; + options.signer_key = operation.metadata.signer_key; options.amount = operation.amount?.value.replace('-', ''); options.symbol = operation.amount?.currency.symbol; options.decimals = operation.amount?.currency.decimals; @@ -790,6 +793,9 @@ export function getOptionsFromOperations(operations: RosettaOperation[]): Rosett if (!operation.metadata || typeof operation.metadata.delegate_to !== 'string') { return null; } + if (!operation.metadata || typeof operation.metadata.signer_key !== 'string') { + return null; + } options.sender_address = operation.account?.address; options.type = operation.type; options.delegate_to = operation.metadata?.delegate_to; @@ -797,6 +803,7 @@ export function getOptionsFromOperations(operations: RosettaOperation[]): Rosett options.symbol = operation.amount?.currency.symbol; options.decimals = operation.amount?.currency.decimals; options.pox_addr = operation.metadata?.pox_addr as string; + options.signer_key = operation.metadata.signer_key; break; default: return null; diff --git a/src/test-utils/test-helpers.ts b/src/test-utils/test-helpers.ts index 05a1ef8163..737d58becf 100644 --- a/src/test-utils/test-helpers.ts +++ b/src/test-utils/test-helpers.ts @@ -515,6 +515,7 @@ export async function stackStxWithRosetta(opts: { privateKey: string; cycleCount: number; ustxAmount: bigint; + signerKey: string; }) { const rosettaNetwork: NetworkIdentifier = { blockchain: RosettaConstants.blockchain, @@ -535,6 +536,7 @@ export async function stackStxWithRosetta(opts: { metadata: { number_of_cycles: opts.cycleCount, pox_addr: opts.btcAddr, + signer_key: opts.signerKey, }, }, { diff --git a/src/tests-2.5/pox-4-burnchain-delegate-stx.ts b/src/tests-2.5/pox-4-burnchain-delegate-stx.ts index d0dea1fd74..486ae393a1 100644 --- a/src/tests-2.5/pox-4-burnchain-delegate-stx.ts +++ b/src/tests-2.5/pox-4-burnchain-delegate-stx.ts @@ -174,7 +174,7 @@ async function createPox2DelegateStx(args: { }; } -describe('PoX-4 - Stack using Bitcoin-chain ops', () => { +describe('PoX-4 - Stack using Bitcoin-chain delegate ops', () => { const seedAccount = testnetKeys[0]; let db: PgWriteStore; diff --git a/src/tests-2.5/pox-4-burnchain-stack-stx.ts b/src/tests-2.5/pox-4-burnchain-stack-stx.ts index 1667d4a00a..ee55033d52 100644 --- a/src/tests-2.5/pox-4-burnchain-stack-stx.ts +++ b/src/tests-2.5/pox-4-burnchain-stack-stx.ts @@ -134,7 +134,7 @@ async function createPox2StackStx(args: { }; } -describe('PoX-4 - Stack using Bitcoin-chain ops', () => { +describe('PoX-4 - Stack using Bitcoin-chain stack ops', () => { const seedAccount = testnetKeys[0]; let db: PgWriteStore; @@ -186,7 +186,7 @@ describe('PoX-4 - Stack using Bitcoin-chain ops', () => { // transfer pox "min_amount_ustx" from seed to test account const poxInfo = await client.getPox(); - testAccountBalance = BigInt(Math.round(Number(poxInfo.min_amount_ustx) * 2.1).toString()); + testAccountBalance = BigInt(poxInfo.min_amount_ustx) * 2n; const stxXfer1 = await makeSTXTokenTransfer({ senderKey: seedAccount.secretKey, recipient: account.stxAddr, diff --git a/src/tests-2.5/pox-4-rosetta-btc-addr-types.ts b/src/tests-2.5/pox-4-rosetta-btc-addr-types.ts index ffa65abe7e..cd29a330e2 100644 --- a/src/tests-2.5/pox-4-rosetta-btc-addr-types.ts +++ b/src/tests-2.5/pox-4-rosetta-btc-addr-types.ts @@ -9,6 +9,8 @@ import { import { CoreRpcPoxInfo } from '../core-rpc/client'; import { DbTxStatus } from '../datastore/common'; import { BurnchainRewardSlotHolderListResponse } from '@stacks/stacks-blockchain-api-types'; +import { bytesToHex } from '@stacks/common'; +import { randomBytes } from '@stacks/transactions'; const BTC_ADDRESS_CASES = [ { addressFormat: 'p2pkh' }, @@ -55,6 +57,7 @@ describe.each(BTC_ADDRESS_CASES)( privateKey: account.secretKey, cycleCount, ustxAmount, + signerKey: bytesToHex(randomBytes(33)), }); expect(rosettaStackStx.tx.status).toBe(DbTxStatus.Success); expect(rosettaStackStx.constructionMetadata.metadata.contract_name).toBe('pox-4'); diff --git a/src/tests-2.5/pox-4-rosetta-cycle-phases.ts b/src/tests-2.5/pox-4-rosetta-cycle-phases.ts index c117f031f1..aaac1e542f 100644 --- a/src/tests-2.5/pox-4-rosetta-cycle-phases.ts +++ b/src/tests-2.5/pox-4-rosetta-cycle-phases.ts @@ -1,3 +1,5 @@ +import { bytesToHex } from '@stacks/common'; +import { randomBytes } from '@stacks/transactions'; import { testnetKeys } from '../api/routes/debug'; import { stackStxWithRosetta, standByUntilBurnBlock, testEnv } from '../test-utils/test-helpers'; @@ -41,6 +43,7 @@ describe.each(BLOCK_SHIFT_COUNT)( cycleCount: 1, ustxAmount, btcAddr, + signerKey: bytesToHex(randomBytes(33)), }); }); diff --git a/src/tests-2.5/pox-4-rosetta-segwit.ts b/src/tests-2.5/pox-4-rosetta-segwit.ts index c7f155cf5a..b9c63ac60e 100644 --- a/src/tests-2.5/pox-4-rosetta-segwit.ts +++ b/src/tests-2.5/pox-4-rosetta-segwit.ts @@ -7,6 +7,7 @@ import { AnchorMode, getAddressFromPrivateKey, makeSTXTokenTransfer, + randomBytes, TransactionVersion, } from '@stacks/transactions'; import bignumber from 'bignumber.js'; @@ -26,6 +27,7 @@ import { testEnv, } from '../test-utils/test-helpers'; import { hexToBuffer } from '@hirosystems/api-toolkit'; +import { bytesToHex } from '@stacks/common'; describe('PoX-4 - Rosetta - Stacking with segwit', () => { let btcAddr: string; @@ -129,6 +131,7 @@ describe('PoX-4 - Rosetta - Stacking with segwit', () => { privateKey: account.secretKey, cycleCount: cycleCount, ustxAmount: ustxAmount, + signerKey: bytesToHex(randomBytes(33)), }); expect(stackingResult.constructionMetadata.metadata.contract_name).toBe('pox-4'); @@ -247,6 +250,7 @@ describe('PoX-4 - Rosetta - Stacking with segwit', () => { privateKey: account.secretKey, cycleCount, ustxAmount, + signerKey: bytesToHex(randomBytes(33)), }); expect(rosettaStackStx.constructionMetadata.metadata.contract_name).toBe('pox-4');