|
| 1 | +import { getBitcoinAddressFromKey } from '../ec-helpers'; |
| 2 | +import { testnetKeys } from '../api/routes/debug'; |
| 3 | +import { |
| 4 | + fetchGet, |
| 5 | + stackStxWithRosetta, |
| 6 | + standByUntilBurnBlock, |
| 7 | + testEnv, |
| 8 | +} from '../test-utils/test-helpers'; |
| 9 | +import { CoreRpcPoxInfo } from '../core-rpc/client'; |
| 10 | +import { DbTxStatus } from '../datastore/common'; |
| 11 | +import { BurnchainRewardSlotHolderListResponse } from '@stacks/stacks-blockchain-api-types'; |
| 12 | + |
| 13 | +const BTC_ADDRESS_CASES = [ |
| 14 | + { addressFormat: 'p2pkh' }, |
| 15 | + { addressFormat: 'p2sh' }, |
| 16 | + { addressFormat: 'p2sh-p2wpkh' }, |
| 17 | + { addressFormat: 'p2sh-p2wsh' }, |
| 18 | + { addressFormat: 'p2wpkh' }, |
| 19 | + { addressFormat: 'p2wsh' }, |
| 20 | + { addressFormat: 'p2tr' }, |
| 21 | +] as const; |
| 22 | + |
| 23 | +describe.each(BTC_ADDRESS_CASES)( |
| 24 | + 'PoX-2 - Rosetta - Stack with BTC address format $addressFormat', |
| 25 | + ({ addressFormat }) => { |
| 26 | + let poxInfo: CoreRpcPoxInfo; |
| 27 | + const account = testnetKeys[1]; |
| 28 | + let bitcoinAddress: string; |
| 29 | + |
| 30 | + beforeAll(() => { |
| 31 | + bitcoinAddress = getBitcoinAddressFromKey({ |
| 32 | + privateKey: account.secretKey, |
| 33 | + network: 'testnet', |
| 34 | + addressFormat, |
| 35 | + }); |
| 36 | + }); |
| 37 | + |
| 38 | + test('Standby for next cycle', async () => { |
| 39 | + poxInfo = await testEnv.client.getPox(); |
| 40 | + await standByUntilBurnBlock(poxInfo.next_cycle.reward_phase_start_block_height); // a good time to stack |
| 41 | + // await standByForPoxCycle(); DON'T USE THIS!!! <cycle>.id is lying to you! |
| 42 | + }); |
| 43 | + |
| 44 | + test('Perform stack-stx using Rosetta', async () => { |
| 45 | + poxInfo = await testEnv.client.getPox(); |
| 46 | + expect(poxInfo.next_cycle.blocks_until_reward_phase).toBe(poxInfo.reward_cycle_length); // cycle just started |
| 47 | + |
| 48 | + const ustxAmount = BigInt(Math.round(Number(poxInfo.min_amount_ustx) * 1.1).toString()); |
| 49 | + const cycleCount = 1; |
| 50 | + |
| 51 | + const rosettaStackStx = await stackStxWithRosetta({ |
| 52 | + btcAddr: bitcoinAddress, |
| 53 | + stacksAddress: account.stacksAddress, |
| 54 | + pubKey: account.pubKey, |
| 55 | + privateKey: account.secretKey, |
| 56 | + cycleCount, |
| 57 | + ustxAmount, |
| 58 | + }); |
| 59 | + expect(rosettaStackStx.tx.status).toBe(DbTxStatus.Success); |
| 60 | + expect(rosettaStackStx.constructionMetadata.metadata.contract_name).toBe('pox-2'); |
| 61 | + }); |
| 62 | + |
| 63 | + test('Validate reward set received', async () => { |
| 64 | + // todo: is it correct that the reward set is only available after/in the 2nd block of a reward phase? |
| 65 | + await standByUntilBurnBlock(poxInfo.next_cycle.reward_phase_start_block_height + 1); // time to check reward sets |
| 66 | + |
| 67 | + poxInfo = await testEnv.client.getPox(); |
| 68 | + const rewardSlotHolders = await fetchGet<BurnchainRewardSlotHolderListResponse>( |
| 69 | + `/extended/v1/burnchain/reward_slot_holders/${bitcoinAddress}` |
| 70 | + ); |
| 71 | + expect(rewardSlotHolders.total).toBe(1); |
| 72 | + expect(rewardSlotHolders.results[0].address).toBe(bitcoinAddress); |
| 73 | + expect(rewardSlotHolders.results[0].burn_block_height).toBe( |
| 74 | + poxInfo.current_burnchain_block_height |
| 75 | + ); |
| 76 | + expect(poxInfo.next_cycle.blocks_until_reward_phase).toBe( |
| 77 | + poxInfo.reward_cycle_length - (2 - 1) // aka 2nd / nth block of reward phase (zero-indexed) |
| 78 | + ); |
| 79 | + }); |
| 80 | + } |
| 81 | +); |
0 commit comments