Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 30 additions & 14 deletions src/event-stream/reader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ import {
TxSpendingConditionSingleSigHashMode,
decodeClarityValueList,
} from 'stacks-encoding-native-js';
import { DbMicroblockPartial, DbPox2DelegateStxEvent, DbPox2EventData } from '../datastore/common';
import {
DbMicroblockPartial,
DbPox2DelegateStxEvent,
DbPox2StackStxEvent,
} from '../datastore/common';
import { NotImplementedError } from '../errors';
import {
getEnumDescription,
Expand Down Expand Up @@ -79,7 +83,8 @@ function createTransactionFromCoreBtcStxLockEvent(
event: StxLockEvent,
burnBlockHeight: number,
txResult: string,
txId: string
txId: string,
stxStacksPox2Event: DbPox2StackStxEvent | undefined
): DecodedTxResult {
const resultCv = decodeClarityValue<
ClarityValueResponse<
Expand Down Expand Up @@ -108,9 +113,14 @@ function createTransactionFromCoreBtcStxLockEvent(

const contractName = event.stx_lock_event.contract_identifier?.split('.')?.[1] ?? 'pox';

// If a pox-2 event is available then use its pox_addr, otherwise fallback to the stacker address
const poxAddrArg = stxStacksPox2Event?.pox_addr
? poxAddressToTuple(stxStacksPox2Event.pox_addr)
: poxAddressToTuple(c32ToB58(stacker.address));

const legacyClarityVals = [
uintCV(lockAmount.value), // amount-ustx
poxAddressToTuple(c32ToB58(stacker.address)), // pox-addr
poxAddrArg, // pox-addr
uintCV(burnBlockHeight), // start-burn-height
uintCV(lockPeriod), // lock-period
];
Expand Down Expand Up @@ -363,13 +373,15 @@ export function parseMessageTransaction(
(e): e is StxLockEvent => e.type === CoreNodeEventType.StxLockEvent
);

const pox2Event = events.map(e => {
if (
e.type === CoreNodeEventType.ContractEvent &&
e.contract_event.topic === 'print' &&
(e.contract_event.contract_identifier === Pox2ContractIdentifer.mainnet ||
e.contract_event.contract_identifier === Pox2ContractIdentifer.testnet)
) {
const pox2Event = events
.filter(
(e): e is SmartContractEvent =>
e.type === CoreNodeEventType.ContractEvent &&
e.contract_event.topic === 'print' &&
(e.contract_event.contract_identifier === Pox2ContractIdentifer.mainnet ||
e.contract_event.contract_identifier === Pox2ContractIdentifer.testnet)
)
.map(e => {
const network = chainId === ChainID.Mainnet ? 'mainnet' : 'testnet';
const decodedEvent = decodePox2PrintEvent(e.contract_event.raw_value, network);
if (decodedEvent) {
Expand All @@ -378,20 +390,24 @@ export function parseMessageTransaction(
decodedEvent,
};
}
}
return null;
})[0];
})
.find(e => !!e);

if (stxTransferEvent) {
rawTx = createTransactionFromCoreBtcTxEvent(chainId, stxTransferEvent, coreTx.txid);
txSender = stxTransferEvent.stx_transfer_event.sender;
} else if (stxLockEvent) {
const stxStacksPox2Event =
pox2Event?.decodedEvent.name === Pox2EventName.StackStx
? pox2Event.decodedEvent
: undefined;
rawTx = createTransactionFromCoreBtcStxLockEvent(
chainId,
stxLockEvent,
blockData.burn_block_height,
coreTx.raw_result,
coreTx.txid
coreTx.txid,
stxStacksPox2Event
);
txSender = stxLockEvent.stx_lock_event.locked_address;
} else if (pox2Event && pox2Event.decodedEvent.name === Pox2EventName.DelegateStx) {
Expand Down
22 changes: 18 additions & 4 deletions src/tests-2.1/pox-2-burnchain-stack-stx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { RPCClient } from 'rpc-bitcoin';
import * as supertest from 'supertest';
import { Pox2ContractIdentifer } from '../pox-helpers';
import { ClarityValueUInt, decodeClarityValue } from 'stacks-encoding-native-js';
import { decodeBtcAddress } from '@stacks/stacking';

// Perform Stack-STX operation on Bitcoin.
// See https://github.com/stacksgov/sips/blob/0da29c6911c49c45e4125dbeaed58069854591eb/sips/sip-007/sip-007-stacking-consensus.md#stx-operations-on-bitcoin
Expand All @@ -39,6 +40,7 @@ async function createPox2StackStx(args: {
cycleCount: number;
stackerAddress: string;
bitcoinWif: string;
poxAddrPayout: string;
}) {
const btcAccount = ECPair.fromWIF(args.bitcoinWif, btc.networks.regtest);
const feeAmount = 0.0001;
Expand Down Expand Up @@ -116,7 +118,7 @@ async function createPox2StackStx(args: {
})
// The second Bitcoin output will be used as the reward address for any stacking rewards.
.addOutput({
address: c32ToB58(args.stackerAddress),
address: args.poxAddrPayout,
value: Math.round(outAmount1 - feeAmount * sats),
})
.signInput(0, btcAccount)
Expand Down Expand Up @@ -145,6 +147,11 @@ describe('PoX-2 - Stack using Bitcoin-chain ops', () => {
const accountKey = '72e8e3725324514c38c2931ed337ab9ab8d8abaae83ed2275456790194b1fd3101';
let account: Account;

// testnet btc addr: tb1pf4x64urhdsdmadxxhv2wwjv6e3evy59auu2xaauu3vz3adxtskfschm453
// regtest btc addr: bcrt1pf4x64urhdsdmadxxhv2wwjv6e3evy59auu2xaauu3vz3adxtskfs4w3npt
const poxAddrPayoutKey = 'c71700b07d520a8c9731e4d0f095aa6efb91e16e25fb27ce2b72e7b698f8127a01';
let poxAddrPayoutAccount: Account;

let testAccountBalance: bigint;
const testAccountBtcBalance = 5;
let testStackAmount: bigint;
Expand All @@ -159,6 +166,7 @@ describe('PoX-2 - Stack using Bitcoin-chain ops', () => {
({ db, api, client, stacksNetwork, bitcoinRpcClient } = testEnv);

account = accountFromKey(accountKey);
poxAddrPayoutAccount = accountFromKey(poxAddrPayoutKey, 'p2tr');

const poxInfo = await client.getPox();
const [contractAddress, contractName] = poxInfo.contract_id.split('.');
Expand Down Expand Up @@ -246,6 +254,7 @@ describe('PoX-2 - Stack using Bitcoin-chain ops', () => {
stxOpBtcTxs = await createPox2StackStx({
bitcoinWif: account.wif,
stackerAddress: account.stxAddr,
poxAddrPayout: poxAddrPayoutAccount.btcAddr,
stxAmount: testStackAmount,
cycleCount: 6,
});
Expand Down Expand Up @@ -298,11 +307,16 @@ describe('PoX-2 - Stack using Bitcoin-chain ops', () => {
expect(callArg1.name).toBe('amount-ustx');
expect(BigInt(decodeClarityValue<ClarityValueUInt>(callArg1.hex).value)).toBe(testStackAmount);

const expectedPoxPayoutAddr = decodeBtcAddress(poxAddrPayoutAccount.btcTestnetAddr);
const expectedPoxPayoutAddrRepr = `(tuple (hashbytes 0x${Buffer.from(
expectedPoxPayoutAddr.data
).toString('hex')}) (version 0x${Buffer.from([expectedPoxPayoutAddr.version]).toString(
'hex'
)}))`;
const callArg2 = txObj.contract_call.function_args![1];
expect(callArg2.name).toBe('pox-addr');
const callArg2Addr = decodePoxAddrArg(callArg2.hex);
expect(callArg2Addr.stxAddr).toBe(account.stxAddr);
expect(callArg2Addr.btcAddr).toBe(account.btcAddr);
expect(callArg2.type).toBe('(tuple (hashbytes (buff 32)) (version (buff 1)))');
expect(callArg2.repr).toBe(expectedPoxPayoutAddrRepr);
});

// TODO: this is very flaky
Expand Down