Skip to content

Commit 4179c67

Browse files
fix(sdk-coin-vet): invalid id for vet validation regn txn
Ticket: SC-4409
1 parent 8626186 commit 4179c67

File tree

3 files changed

+80
-2
lines changed

3 files changed

+80
-2
lines changed

modules/sdk-coin-vet/src/lib/transaction/transaction.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,8 @@ export class Transaction extends BaseTransaction {
393393
this.type === TransactionType.StakingDelegate ||
394394
this.type === TransactionType.StakingUnlock ||
395395
this.type === TransactionType.StakingWithdraw ||
396-
this.type === TransactionType.StakingClaim
396+
this.type === TransactionType.StakingClaim ||
397+
this.type === TransactionType.StakingLock
397398
) {
398399
transactionBody.reserved = {
399400
features: 1, // mark transaction as delegated i.e. will use gas payer

modules/sdk-coin-vet/test/resources/vet.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export const CLAIM_REWARDS_TRANSACTION =
3535
export const STAKING_LEVEL_ID = 8;
3636
export const STAKING_AUTORENEW = true;
3737
export const STAKING_CONTRACT_ADDRESS = '0x1e02b2953adefec225cf0ec49805b1146a4429c1';
38+
export const BUILT_IN_STAKER_CONTRACT_ADDRESS = '0x00000000000000000000000000005374616B6572';
3839

3940
export const VALID_TOKEN_SIGNABLE_PAYLOAD =
4041
'f8762788014ead140e77bbc140f85ef85c940000000000000000000000000000456e6572677980b844a9059cbb000000000000000000000000e59f1cea4e0fef511e3d0f4eec44adf19c4cbeec000000000000000000000000000000000000000000000000016345785d8a000081808252088082faf8c101';

modules/sdk-coin-vet/test/unit/stakingFlowE2E.ts

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import should from 'should';
22
import { coins } from '@bitgo/statics';
33
import { TransactionType } from '@bitgo/sdk-core';
4-
import { TransactionBuilderFactory, StakeClauseTransaction } from '../../src/lib';
4+
import { TransactionBuilderFactory, StakeClauseTransaction, ValidatorRegistrationTransaction } from '../../src/lib';
55
import * as testData from '../resources/vet';
66

77
describe('VET Staking Flow - End-to-End Test', function () {
@@ -10,7 +10,9 @@ describe('VET Staking Flow - End-to-End Test', function () {
1010

1111
// Test data
1212
const stakingContractAddress = testData.STAKING_CONTRACT_ADDRESS;
13+
const builtInStakerContractAddress = testData.BUILT_IN_STAKER_CONTRACT_ADDRESS;
1314
const amountToStake = '1000000000000000000'; // 1 VET in wei
15+
const stakingPeriod = 60480;
1416
const levelId = testData.STAKING_LEVEL_ID;
1517
const senderAddress = '0x9378c12BD7502A11F770a5C1F223c959B2805dA9';
1618
const feePayerAddress = '0xdc9fef0b84a0ccf3f1bd4b84e41743e3e051a083';
@@ -99,6 +101,80 @@ describe('VET Staking Flow - End-to-End Test', function () {
99101
jsonOutput.should.have.property('levelId', levelId);
100102
});
101103

104+
it('should build, sign, and serialize a complete validator registration transaction with fee delegation', async function () {
105+
// Step 1: Build the staking transaction
106+
const validatorRegistrationBuilder = factory.getValidatorRegistrationBuilder();
107+
108+
validatorRegistrationBuilder
109+
.stakingContractAddress(builtInStakerContractAddress)
110+
.stakingPeriod(60480)
111+
.sender(senderAddress)
112+
.chainTag(0x27) // Testnet chain tag
113+
.blockRef('0x014ead140e77bbc1')
114+
.expiration(64)
115+
.gas(100000)
116+
.gasPriceCoef(128)
117+
.nonce('12345');
118+
119+
validatorRegistrationBuilder.addFeePayerAddress(feePayerAddress);
120+
121+
const unsignedTx = await validatorRegistrationBuilder.build();
122+
should.exist(unsignedTx);
123+
unsignedTx.should.be.instanceof(ValidatorRegistrationTransaction);
124+
125+
const validatorRegistrationTx = unsignedTx as ValidatorRegistrationTransaction;
126+
127+
// Verify transaction structure
128+
validatorRegistrationTx.type.should.equal(TransactionType.StakingLock);
129+
validatorRegistrationTx.stakingContractAddress.should.equal(stakingContractAddress);
130+
validatorRegistrationTx.stakingPeriod.should.equal(stakingPeriod);
131+
132+
should.exist(validatorRegistrationTx.rawTransaction);
133+
should.exist(validatorRegistrationTx.rawTransaction.body);
134+
135+
// This is the critical test - ensure reserved.features = 1 for ContractCall type
136+
should.exist(validatorRegistrationTx.rawTransaction.body.reserved);
137+
validatorRegistrationTx.rawTransaction.body.reserved!.should.have.property('features', 1);
138+
139+
// Step 3: Add sender signature
140+
validatorRegistrationTx.addSenderSignature(mockSenderSignature);
141+
should.exist(validatorRegistrationTx.senderSignature);
142+
Buffer.from(validatorRegistrationTx.senderSignature!).should.eql(mockSenderSignature);
143+
144+
// Step 4: Add fee payer signature
145+
validatorRegistrationTx.addFeePayerSignature(mockFeePayerSignature);
146+
should.exist(validatorRegistrationTx.feePayerSignature);
147+
Buffer.from(validatorRegistrationTx.feePayerSignature!).should.eql(mockFeePayerSignature);
148+
149+
// Step 5: Generate transaction ID
150+
151+
// This should NOT throw "not signed transaction: id unavailable" error anymore
152+
const transactionId = validatorRegistrationTx.id;
153+
should.exist(transactionId);
154+
transactionId.should.not.equal('UNAVAILABLE');
155+
156+
// Step 6: Serialize the fully signed transaction
157+
const serializedTx = validatorRegistrationTx.toBroadcastFormat();
158+
should.exist(serializedTx);
159+
serializedTx.should.be.type('string');
160+
serializedTx.should.startWith('0x');
161+
162+
// Step 7: Verify transaction can be deserialized
163+
const deserializedBuilder = factory.from(serializedTx);
164+
const deserializedTx = deserializedBuilder.transaction as ValidatorRegistrationTransaction;
165+
166+
deserializedTx.should.be.instanceof(ValidatorRegistrationTransaction);
167+
deserializedTx.stakingContractAddress.should.equal(stakingContractAddress);
168+
deserializedTx.stakingPeriod.should.equal(stakingPeriod);
169+
170+
// Step 8: Verify toJson output
171+
const jsonOutput = validatorRegistrationTx.toJson();
172+
should.exist(jsonOutput);
173+
jsonOutput.should.have.property('id', transactionId);
174+
jsonOutput.should.have.property('stakingContractAddress', stakingContractAddress);
175+
jsonOutput.should.have.property('stakingPeriod', stakingPeriod);
176+
});
177+
102178
it('should handle signature combination in the correct order', async function () {
103179
// This test specifically validates the signature combination flow that was failing
104180
const stakingBuilder = factory.getStakingActivateBuilder();

0 commit comments

Comments
 (0)