Skip to content

Commit 110dd33

Browse files
Merge pull request #7803 from BitGo/fix-id-for-val-reg-txn
fix(sdk-coin-vet): invalid id for vet validation regn txn
2 parents 2145271 + 93ff3b5 commit 110dd33

File tree

6 files changed

+171
-9
lines changed

6 files changed

+171
-9
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/src/lib/transaction/validatorRegistrationTransaction.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ import EthereumAbi from 'ethereumjs-abi';
77
import utils from '../utils';
88
import BigNumber from 'bignumber.js';
99
import { addHexPrefix, BN } from 'ethereumjs-util';
10-
import { ZERO_VALUE_AMOUNT } from '../constants';
1110

1211
export class ValidatorRegistrationTransaction extends Transaction {
1312
private _stakingContractAddress: string;
1413
private _validator: string;
1514
private _stakingPeriod: number;
15+
private _amountToStake: string;
1616

1717
constructor(_coinConfig: Readonly<CoinConfig>) {
1818
super(_coinConfig);
@@ -35,6 +35,14 @@ export class ValidatorRegistrationTransaction extends Transaction {
3535
this._stakingPeriod = period;
3636
}
3737

38+
get amountToStake(): string {
39+
return this._amountToStake;
40+
}
41+
42+
set amountToStake(amount: string) {
43+
this._amountToStake = amount;
44+
}
45+
3846
get stakingContractAddress(): string {
3947
return this._stakingContractAddress;
4048
}
@@ -63,7 +71,7 @@ export class ValidatorRegistrationTransaction extends Transaction {
6371
this._clauses = [
6472
{
6573
to: this.stakingContractAddress,
66-
value: ZERO_VALUE_AMOUNT,
74+
value: this.amountToStake,
6775
data: addValidationData,
6876
},
6977
];
@@ -72,7 +80,7 @@ export class ValidatorRegistrationTransaction extends Transaction {
7280
this._recipients = [
7381
{
7482
address: this.stakingContractAddress,
75-
amount: ZERO_VALUE_AMOUNT,
83+
amount: this.amountToStake,
7684
},
7785
];
7886
}
@@ -107,11 +115,11 @@ locking their VET into the built-in staker contract. Allowed values are 60480 (7
107115
dependsOn: this.dependsOn,
108116
nonce: this.nonce,
109117
data: this.transactionData,
110-
value: ZERO_VALUE_AMOUNT,
118+
value: this.amountToStake,
111119
sender: this.sender,
112120
to: this.stakingContractAddress,
113121
stakingContractAddress: this.stakingContractAddress,
114-
amountToStake: ZERO_VALUE_AMOUNT,
122+
amountToStake: this.amountToStake,
115123
validatorAddress: this.validator,
116124
stakingPeriod: this.stakingPeriod,
117125
};
@@ -147,6 +155,10 @@ locking their VET into the built-in staker contract. Allowed values are 60480 (7
147155
this.stakingContractAddress = addValidationClause.to;
148156
}
149157

158+
if (addValidationClause.value) {
159+
this.amountToStake = new BigNumber(addValidationClause.value).toFixed();
160+
}
161+
150162
// Extract validator and period from addValidation data
151163
if (addValidationClause.data) {
152164
this.transactionData = addValidationClause.data;

modules/sdk-coin-vet/src/lib/transactionBuilder/validatorRegistrationBuilder.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import assert from 'assert';
22
import { BaseCoin as CoinConfig } from '@bitgo/statics';
33
import { TransactionType } from '@bitgo/sdk-core';
44
import { TransactionClause } from '@vechain/sdk-core';
5+
import BigNumber from 'bignumber.js';
56

67
import { TransactionBuilder } from './transactionBuilder';
78
import { Transaction } from '../transaction/transaction';
@@ -96,6 +97,17 @@ export class ValidatorRegistrationBuilder extends TransactionBuilder {
9697
return this;
9798
}
9899

100+
/**
101+
* Sets the amount to stake for this validator registration tx (VET amount being sent).
102+
*
103+
* @param {string} amount - The amount to stake in wei
104+
* @returns {ValidatorRegistrationBuilder} This transaction builder
105+
*/
106+
amountToStake(amount: string): this {
107+
this.validatorRegistrationTransaction.amountToStake = amount;
108+
return this;
109+
}
110+
99111
/**
100112
* Sets the validator address for this validator registration tx.
101113
* @param {string} address - The validator address
@@ -127,9 +139,16 @@ export class ValidatorRegistrationBuilder extends TransactionBuilder {
127139
throw new Error('transaction not defined');
128140
}
129141
assert(transaction.stakingContractAddress, 'Staking contract address is required');
130-
131142
assert(transaction.stakingPeriod, 'Staking period is required');
132143
assert(transaction.validator, 'Validator address is required');
144+
assert(transaction.amountToStake, 'Staking amount is required');
145+
146+
// Validate staking amount is within allowed range
147+
const amountInVET = new BigNumber(transaction.amountToStake).dividedBy(new BigNumber(10).pow(18));
148+
if (amountInVET.isLessThan(25_000_000) || amountInVET.isGreaterThan(600_000_000)) {
149+
throw new Error('Staking amount must be between 25M and 600M VET');
150+
}
151+
133152
this.validateAddress({ address: transaction.stakingContractAddress });
134153
}
135154

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export const DELEGATION_TRANSACTION =
2121
'0xf9010327880166f0952a071e2a820190f85ef85c941e02b2953adefec225cf0ec49805b1146a4429c180b84408bbb8240000000000000000000000000000000000000000000000000000000000003d4500000000000000000000000000000021cbe0de65ea10f7658effeea70727154a81808303b46c8088f341b4c6b5ff5294c101b8829f5d674b8b043e95907b544b16a2c399bc04c7ebfcb9fa49956e050c59bbd5a510c57c6c135a3f03b12fe388409216809124a06d3c4ce797b5d97c5cd899d73d01dc4b66e63aade59b67639e44caedd5783a8e4d4f3c224f911acc5f43c387b54d22b2332172363a48e186d3bd52abec67d84e3d9e8c9696b241d29810a4e14e5801';
2222

2323
export const VALIDATOR_REGISTRATION_TRANSACTION =
24-
'0xf8fb2788016754d8d0e8099340f85ef85c9400000000000000000000000000005374616b657280b844c3c4b13800000000000000000000000059b67d37be55997c96ea6f1890f08f825a41203c000000000000000000000000000000000000000000000000000000000000ec40818082b4ae808301bc4ec101b882ad3cef39b277cdb926f50ac04cbf11a68cf4a30b13311605978d57d92e92ee171a8bb734676cad0f7cdcdd935cf78b71b02e2193390ab752b032a6219131bf230119acb7f53ca1cf868a05f5c7b841e7052c8d779f876e6a6a6e5aa3daf0cd82dc6842d5fa276d4abc950b686e3d685261cae290dd20a13223a832e1b88be9ff0500';
24+
'0xf90106278801690812847d899f40f869f8679400000000000000000000000000005374616b65728b14adf4b7320334b9000000b844c3c4b13800000000000000000000000059b67d37be55997c96ea6f1890f08f825a41203c000000000000000000000000000000000000000000000000000000000000ec408180826b84808303576bc101b8825600996530a8204d10944b52b933e1ce57744793eaaa93922d6b6cfbf53759ce6bd8c55bdafd06ef8c30b9549747008c5d4caad226d712710825d88271164acf00b6519806de49deacbf8079c8fd8698216289946988ea6c1bf86cf73740e1a8b620c75392c2d8cb5b9e608301303435d7174e70f627e37cd59d94644e35468cca01';
2525

2626
export const EXIT_DELEGATION_TRANSACTION =
2727
'0xf8db278801640bf461bc7e1840f83df83b941e02b2953adefec225cf0ec49805b1146a4429c180a469e79b7d0000000000000000000000000000000000000000000000000000000000003d2d81808303525f808305f65ac101b8820cb393317793011b0a205973c77761f5c5c8652c21fe0115f527d2e2f2c1b5fc72a048107b263764312e9323f2ace9f30ce0beed873d7ef7f5432943330d2d5000a4a5f6439503f235ac6a5e17b47ac26c9e0c9e3be9dbd4cec3266fea324eb9bf5f806cedca59ff4144deb0ca18c41d9d6d600a86bf3d4e7b930bcec9b04c2e7301';
@@ -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';
@@ -227,6 +228,7 @@ export const DELEGATE_TOKEN_ID = '15685';
227228
export const STAKING_PERIOD = 259200;
228229
export const DELEGATE_VALIDATOR = '0xae99cb89767a09d53e589a40cb4016974aba4b94';
229230
export const VALIDATOR_REGISTRATION_VALIDATOR = '0x59b67d37be55997c96ea6f1890f08f825a41203c';
231+
export const VALIDATOR_REGISTRATION_AMOUNT = '25000000000000000000000000';
230232

231233
export const SIGNED_DELEGATE_RAW_HEX =
232234
'0xf8fa278801671187de8af70440f85ef85c941e02b2953adefec225cf0ec49805b1146a4429c180b84408bbb8240000000000000000000000000000000000000000000000000000000000003d2d00000000000000000000000000563ec3cafbbe7e60b04b3190e6eca66579706d818082cb5680820190c101b882313e783169eae670b1210e65f59b7c30cfd6c140c377257413fef378f70549f738a22a172ccc4ac7854ebc9952845fa90f7a676e5e9d9e277724ef3968e32e8a00f05ddf913b2b8fb884dbd5d5133217666ec4a68d077dce1537d270f25caf440e0f11232ecc4a5859ab49b2442cc0b0c0c1488302556e6323eec0498f1a42e17301';

modules/sdk-coin-vet/test/transactionBuilder/validatorRegistrationTxnBuilder.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ describe('VET Validator Registration Transaction', function () {
1414
const factory = new TransactionBuilderFactory(coins.get('tvet'));
1515
const stakingPeriod = 60480;
1616
const validatorAddress = '0x9a7aFCACc88c106f3bbD6B213CD0821D9224d945';
17+
const amountToStake = '25000000000000000000000000'; // 25000000 VET
18+
const amountLessThanMinStake = '24000000000000000000000000'; // 24000000 VET
19+
const amountGreaterThanMaxStake = '650000000000000000000000000'; // 650000000 VET
1720

1821
// Helper function to create a basic transaction builder with common properties
1922
const createBasicTxBuilder = () => {
@@ -32,6 +35,7 @@ describe('VET Validator Registration Transaction', function () {
3235
const txBuilder = factory.getValidatorRegistrationBuilder();
3336
txBuilder.stakingContractAddress(VALIDATOR_REGISTRATION_STAKER_CONTRACT_ADDRESS_TESTNET);
3437
txBuilder.stakingPeriod(stakingPeriod);
38+
txBuilder.amountToStake(amountToStake);
3539
txBuilder.sender('0x9378c12BD7502A11F770a5C1F223c959B2805dA9');
3640
txBuilder.chainTag(0x27); // Testnet chain tag
3741
txBuilder.blockRef('0x0000000000000000');
@@ -52,13 +56,16 @@ describe('VET Validator Registration Transaction', function () {
5256
);
5357
validatorRegistrationTransaction.stakingPeriod.should.equal(stakingPeriod);
5458
validatorRegistrationTransaction.validator.should.equal(validatorAddress);
59+
validatorRegistrationTransaction.amountToStake.should.equal(amountToStake);
5560

5661
// Verify clauses
5762
validatorRegistrationTransaction.clauses.length.should.equal(1);
5863
should.exist(validatorRegistrationTransaction.clauses[0].to);
64+
should.exist(validatorRegistrationTransaction.clauses[0].value);
5965
validatorRegistrationTransaction.clauses[0].to?.should.equal(
6066
VALIDATOR_REGISTRATION_STAKER_CONTRACT_ADDRESS_TESTNET
6167
);
68+
validatorRegistrationTransaction.clauses[0].value?.should.equal(amountToStake);
6269

6370
// Verify transaction data is correctly encoded using ethereumABI
6471
should.exist(validatorRegistrationTransaction.clauses[0].data);
@@ -88,6 +95,7 @@ describe('VET Validator Registration Transaction', function () {
8895
const txBuilder = createBasicTxBuilder();
8996
txBuilder.stakingPeriod(stakingPeriod);
9097
txBuilder.validator(validatorAddress);
98+
txBuilder.amountToStake(amountToStake);
9199

92100
await txBuilder.build().should.be.rejectedWith('Staking contract address is required');
93101
});
@@ -96,6 +104,7 @@ describe('VET Validator Registration Transaction', function () {
96104
const txBuilder = createBasicTxBuilder();
97105
txBuilder.stakingContractAddress(VALIDATOR_REGISTRATION_STAKER_CONTRACT_ADDRESS_TESTNET);
98106
txBuilder.validator(validatorAddress);
107+
txBuilder.amountToStake(amountToStake);
99108

100109
await txBuilder.build().should.be.rejectedWith('Staking period is required');
101110
});
@@ -104,10 +113,40 @@ describe('VET Validator Registration Transaction', function () {
104113
const txBuilder = createBasicTxBuilder();
105114
txBuilder.stakingContractAddress(VALIDATOR_REGISTRATION_STAKER_CONTRACT_ADDRESS_TESTNET);
106115
txBuilder.stakingPeriod(stakingPeriod);
116+
txBuilder.amountToStake(amountToStake);
107117

108118
await txBuilder.build().should.be.rejectedWith('Validator address is required');
109119
});
110120

121+
it('should throw error when amount is missing', async function () {
122+
const txBuilder = createBasicTxBuilder();
123+
txBuilder.stakingContractAddress(VALIDATOR_REGISTRATION_STAKER_CONTRACT_ADDRESS_TESTNET);
124+
txBuilder.stakingPeriod(stakingPeriod);
125+
txBuilder.validator(validatorAddress);
126+
127+
await txBuilder.build().should.be.rejectedWith('Staking amount is required');
128+
});
129+
130+
it('should throw error when amount is less than minimum stake', async function () {
131+
const txBuilder = createBasicTxBuilder();
132+
txBuilder.stakingContractAddress(VALIDATOR_REGISTRATION_STAKER_CONTRACT_ADDRESS_TESTNET);
133+
txBuilder.stakingPeriod(stakingPeriod);
134+
txBuilder.validator(validatorAddress);
135+
txBuilder.amountToStake(amountLessThanMinStake);
136+
137+
await txBuilder.build().should.be.rejectedWith('Staking amount must be between 25M and 600M VET');
138+
});
139+
140+
it('should throw error when amount is greater than maximum stake', async function () {
141+
const txBuilder = createBasicTxBuilder();
142+
txBuilder.stakingContractAddress(VALIDATOR_REGISTRATION_STAKER_CONTRACT_ADDRESS_TESTNET);
143+
txBuilder.stakingPeriod(stakingPeriod);
144+
txBuilder.validator(validatorAddress);
145+
txBuilder.amountToStake(amountGreaterThanMaxStake);
146+
147+
await txBuilder.build().should.be.rejectedWith('Staking amount must be between 25M and 600M VET');
148+
});
149+
111150
it('should throw error when stakingContractAddress is invalid', async function () {
112151
const txBuilder = createBasicTxBuilder();
113152

@@ -121,6 +160,7 @@ describe('VET Validator Registration Transaction', function () {
121160
const txBuilder = factory.getValidatorRegistrationBuilder();
122161
txBuilder.stakingContractAddress(VALIDATOR_REGISTRATION_STAKER_CONTRACT_ADDRESS_TESTNET);
123162
txBuilder.stakingPeriod(stakingPeriod);
163+
txBuilder.amountToStake(amountToStake);
124164
txBuilder.chainTag(0x27);
125165
txBuilder.blockRef('0x0000000000000000');
126166
txBuilder.expiration(64);
@@ -151,6 +191,7 @@ describe('VET Validator Registration Transaction', function () {
151191
txBuilder.stakingPeriod(stakingPeriod);
152192
// Not setting chainTag
153193
txBuilder.blockRef('0x0000000000000000');
194+
txBuilder.amountToStake(amountToStake);
154195
txBuilder.expiration(64);
155196
txBuilder.gas(100000);
156197
txBuilder.gasPriceCoef(0);
@@ -184,6 +225,7 @@ describe('VET Validator Registration Transaction', function () {
184225
tx.stakingContractAddress.should.equal(testData.VALIDATOR_REGISTRATION_STAKER_CONTRACT);
185226
tx.stakingPeriod.should.equal(testData.VALIDATOR_REGISTRATION_STAKING_PERIOD);
186227
tx.validator.should.equal(testData.VALIDATOR_REGISTRATION_VALIDATOR);
228+
tx.amountToStake.should.equal(testData.VALIDATOR_REGISTRATION_AMOUNT);
187229
tx.validator.should.startWith('0x');
188230
tx.validator.should.equal(tx.validator.toLowerCase());
189231
should.exist(tx.inputs);

0 commit comments

Comments
 (0)