Skip to content

Commit 22be163

Browse files
fix(sdk-coin-vet): fix exit delegation + burn NFT for hayabusa upgrade
Ticket: SC-3990
1 parent 7c79047 commit 22be163

File tree

7 files changed

+106
-91
lines changed

7 files changed

+106
-91
lines changed

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

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import utils from '../utils';
1010

1111
export class BurnNftTransaction extends Transaction {
1212
private _tokenId: string;
13+
private _stakingContractAddress: string;
1314

1415
constructor(_coinConfig: Readonly<CoinConfig>) {
1516
super(_coinConfig);
@@ -24,6 +25,14 @@ export class BurnNftTransaction extends Transaction {
2425
this._tokenId = id;
2526
}
2627

28+
get stakingContractAddress(): string {
29+
return this._stakingContractAddress;
30+
}
31+
32+
set stakingContractAddress(address: string) {
33+
this._stakingContractAddress = address;
34+
}
35+
2736
/** @inheritdoc */
2837
async build(): Promise<void> {
2938
this.buildClauses();
@@ -34,23 +43,23 @@ export class BurnNftTransaction extends Transaction {
3443

3544
/** @inheritdoc */
3645
buildClauses(): void {
37-
if (!this._contract || !this._tokenId) {
46+
if (!this._stakingContractAddress || !this._tokenId) {
3847
throw new InvalidTransactionError('Missing required burn NFT parameters');
3948
}
4049

41-
utils.validateStakingContractAddress(this._contract, this._coinConfig);
50+
utils.validateStakingContractAddress(this._stakingContractAddress, this._coinConfig);
4251

4352
this._clauses = [
4453
{
45-
to: this._contract,
54+
to: this._stakingContractAddress,
4655
value: '0x0',
4756
data: this._transactionData || this.getBurnNftData(),
4857
},
4958
];
5059

5160
this._recipients = [
5261
{
53-
address: this._contract,
62+
address: this._stakingContractAddress,
5463
amount: '0',
5564
},
5665
];
@@ -87,7 +96,8 @@ export class BurnNftTransaction extends Transaction {
8796
data: this.transactionData || this.getBurnNftData(),
8897
value: '0',
8998
sender: this.sender,
90-
to: this.contract,
99+
to: this.stakingContractAddress,
100+
tokenId: this.tokenId,
91101
};
92102
return json;
93103
}
@@ -114,7 +124,7 @@ export class BurnNftTransaction extends Transaction {
114124
this.nonce = String(body.nonce);
115125

116126
// Set data from clauses
117-
this.contract = body.clauses[0]?.to || '0x0';
127+
this.stakingContractAddress = body.clauses[0]?.to || '0x0';
118128
this.transactionData = body.clauses[0]?.data || '0x0';
119129
this.type = TransactionType.StakingWithdraw;
120130

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

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import BigNumber from 'bignumber.js';
1111

1212
export class ExitDelegationTransaction extends Transaction {
1313
private _tokenId: string;
14+
private _stakingContractAddress: string;
1415

1516
constructor(_coinConfig: Readonly<CoinConfig>) {
1617
super(_coinConfig);
@@ -25,6 +26,14 @@ export class ExitDelegationTransaction extends Transaction {
2526
this._tokenId = id;
2627
}
2728

29+
get stakingContractAddress(): string {
30+
return this._stakingContractAddress;
31+
}
32+
33+
set stakingContractAddress(address: string) {
34+
this._stakingContractAddress = address;
35+
}
36+
2837
/** @inheritdoc */
2938
async build(): Promise<void> {
3039
this.buildClauses();
@@ -35,23 +44,23 @@ export class ExitDelegationTransaction extends Transaction {
3544

3645
/** @inheritdoc */
3746
buildClauses(): void {
38-
if (!this._contract || !this._tokenId) {
47+
if (!this._stakingContractAddress || !this._tokenId) {
3948
throw new InvalidTransactionError('Missing required unstaking parameters');
4049
}
4150

42-
utils.validateDelegationContractAddress(this._contract, this._coinConfig);
51+
utils.validateStakingContractAddress(this._stakingContractAddress, this._coinConfig);
4352

4453
this._clauses = [
4554
{
46-
to: this._contract,
55+
to: this._stakingContractAddress,
4756
value: '0x0',
4857
data: this._transactionData || this.getExitDelegationData(),
4958
},
5059
];
5160

5261
this._recipients = [
5362
{
54-
address: this._contract,
63+
address: this._stakingContractAddress,
5564
amount: '0',
5665
},
5766
];
@@ -88,7 +97,8 @@ export class ExitDelegationTransaction extends Transaction {
8897
data: this.transactionData || this.getExitDelegationData(),
8998
value: '0',
9099
sender: this.sender,
91-
to: this.contract,
100+
to: this.stakingContractAddress,
101+
tokenId: this.tokenId,
92102
};
93103
return json;
94104
}
@@ -115,7 +125,7 @@ export class ExitDelegationTransaction extends Transaction {
115125
this.nonce = String(body.nonce);
116126

117127
// Set data from clauses
118-
this.contract = body.clauses[0]?.to || '0x0';
128+
this.stakingContractAddress = body.clauses[0]?.to || '0x0';
119129
this.transactionData = body.clauses[0]?.data || '0x0';
120130
this.type = TransactionType.StakingUnlock;
121131

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,19 +92,19 @@ export class BurnNftBuilder extends TransactionBuilder {
9292
}
9393

9494
/**
95-
* Sets the NFT contract address for this burn NFT transaction.
95+
* Sets the staking contract address for this staking tx.
9696
* The address must be explicitly provided to ensure the correct contract is used.
9797
*
98-
* @param {string} address - The NFT contract address (required)
99-
* @returns {BurnNftBuilder} This transaction builder
98+
* @param {string} address - The staking contract address (required)
99+
* @returns {StakingBuilder} This transaction builder
100100
* @throws {Error} If no address is provided
101101
*/
102-
nftContract(address: string): this {
102+
stakingContractAddress(address: string): this {
103103
if (!address) {
104-
throw new Error('NFT contract address is required and must be explicitly provided');
104+
throw new Error('Staking contract address is required');
105105
}
106106
this.validateAddress({ address });
107-
this.burnNftTransaction.contract = address;
107+
this.burnNftTransaction.stakingContractAddress = address;
108108
return this;
109109
}
110110

@@ -113,10 +113,10 @@ export class BurnNftBuilder extends TransactionBuilder {
113113
if (!transaction) {
114114
throw new Error('transaction not defined');
115115
}
116-
assert(transaction.contract, 'NFT contract address is required');
116+
assert(transaction.stakingContractAddress, 'Staking contract address is required');
117117
assert(transaction.tokenId, 'Token ID is required');
118118

119-
this.validateAddress({ address: transaction.contract });
119+
this.validateAddress({ address: transaction.stakingContractAddress });
120120
}
121121

122122
/** @inheritdoc */

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

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export class ExitDelegationBuilder extends TransactionBuilder {
4848
}
4949

5050
/**
51-
* Validates the transaction clauses for unstaking.
51+
* Validates the transaction clauses for exit delegation.
5252
* @param {TransactionClause[]} clauses - The transaction clauses to validate.
5353
* @returns {boolean} - Returns true if the clauses are valid, false otherwise.
5454
*/
@@ -92,16 +92,19 @@ export class ExitDelegationBuilder extends TransactionBuilder {
9292
}
9393

9494
/**
95-
* Sets the delegation contract address for this unstaking transaction.
96-
* If not provided, uses the network-appropriate default address.
95+
* Sets the staking contract address for this staking tx.
96+
* The address must be explicitly provided to ensure the correct contract is used.
9797
*
98-
* @param {string} address - The delegation contract address
99-
* @returns {ExitDelegationBuilder} This transaction builder
98+
* @param {string} address - The staking contract address (required)
99+
* @returns {StakingBuilder} This transaction builder
100+
* @throws {Error} If no address is provided
100101
*/
101-
delegationContract(address?: string): this {
102-
const contractAddress = address || utils.getDefaultDelegationAddress(this._coinConfig);
103-
this.validateAddress({ address: contractAddress });
104-
this.exitDelegationTransaction.contract = contractAddress;
102+
stakingContractAddress(address: string): this {
103+
if (!address) {
104+
throw new Error('Staking contract address is required');
105+
}
106+
this.validateAddress({ address });
107+
this.exitDelegationTransaction.stakingContractAddress = address;
105108
return this;
106109
}
107110

@@ -110,10 +113,10 @@ export class ExitDelegationBuilder extends TransactionBuilder {
110113
if (!transaction) {
111114
throw new Error('transaction not defined');
112115
}
113-
assert(transaction.contract, 'Delegation contract address is required');
116+
assert(transaction.stakingContractAddress, 'Staking contract address is required');
114117
assert(transaction.tokenId, 'Token ID is required');
115118

116-
this.validateAddress({ address: transaction.contract });
119+
this.validateAddress({ address: transaction.stakingContractAddress });
117120
}
118121

119122
/** @inheritdoc */

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ export const STAKE_CLAUSE_TRANSACTION =
2020
export const DELEGATION_TRANSACTION =
2121
'0xf8fc278801640639091a26ce40f85ef85c941e02b2953adefec225cf0ec49805b1146a4429c180b84408bbb8240000000000000000000000000000000000000000000000000000000000003d2e00000000000000000000000000563ec3cafbbe7e60b04b3190e6eca66579706d8180830464b080830d8b05c101b8821a3cca8e8339456c6055ef796e5d716dda00de45f4cd9431bedf2119ae5de01b1f0a7268690784ba8f5c22b3043d0530ece5303a813ffdd9c0a5ae0ae85deee400b04543d6874f30eca88b3efb927c44934e9eb64a6f2327cce44a0a94faaca13615d153e804ba3fdd02bf5f8e1b6bc8e0f6149a1c7694803ed4fbb549bb79066101';
2222

23+
export const EXIT_DELEGATION_TRANSACTION =
24+
'0xf8db278801640bf461bc7e1840f83df83b941e02b2953adefec225cf0ec49805b1146a4429c180a469e79b7d0000000000000000000000000000000000000000000000000000000000003d2d81808303525f808305f65ac101b8820cb393317793011b0a205973c77761f5c5c8652c21fe0115f527d2e2f2c1b5fc72a048107b263764312e9323f2ace9f30ce0beed873d7ef7f5432943330d2d5000a4a5f6439503f235ac6a5e17b47ac26c9e0c9e3be9dbd4cec3266fea324eb9bf5f806cedca59ff4144deb0ca18c41d9d6d600a86bf3d4e7b930bcec9b04c2e7301';
25+
26+
export const BURN_NFT_TRANSACTION =
27+
'0xf8db278801640bfe6c1ee3e640f83df83b941e02b2953adefec225cf0ec49805b1146a4429c180a42e17de780000000000000000000000000000000000000000000000000000000000003d2d81808305548c808304fe38c101b882044933b92e0fc5517d58205b46211a5ad2403103c8c217ce9682ebe2457e374f655fc6be307c7dfd59f0f4eda2aab7e3a1ac9219923086cde52e6405c34de2d801d692df740f95dd4ac6dbae7eb6e91a712a1e456e1a80e3a2f501ea1e6ed12c4308e65a8a98b0142190812d4484f54121bbc95b6048ae09de5946304affbfba1400';
28+
2329
export const STAKING_LEVEL_ID = 8;
2430
export const STAKING_AUTORENEW = true;
2531
export const STAKING_CONTRACT_ADDRESS = '0x1e02b2953adefec225cf0ec49805b1146a4429c1';

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

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { BURN_NFT_METHOD_ID, STARGATE_CONTRACT_ADDRESS_TESTNET } from '../../src
88

99
describe('Vet Burn NFT Transaction', () => {
1010
const factory = new TransactionBuilderFactory(coins.get('tvet'));
11+
const stakingContractAddress = STARGATE_CONTRACT_ADDRESS_TESTNET;
1112

1213
describe('Build and Sign', () => {
1314
it('should build a burn NFT transaction', async function () {
@@ -16,7 +17,7 @@ describe('Vet Burn NFT Transaction', () => {
1617

1718
txBuilder.sender(testData.addresses.validAddresses[0]);
1819
txBuilder.tokenId(tokenId);
19-
txBuilder.nftContract(STARGATE_CONTRACT_ADDRESS_TESTNET);
20+
txBuilder.stakingContractAddress(stakingContractAddress);
2021
txBuilder.gas(21000);
2122
txBuilder.nonce('64248');
2223
txBuilder.blockRef('0x014ead140e77bbc1');
@@ -27,7 +28,7 @@ describe('Vet Burn NFT Transaction', () => {
2728

2829
should.equal(tx.sender, testData.addresses.validAddresses[0]);
2930
should.equal(tx.tokenId, tokenId);
30-
should.equal(tx.contract, STARGATE_CONTRACT_ADDRESS_TESTNET);
31+
should.equal(tx.stakingContractAddress, STARGATE_CONTRACT_ADDRESS_TESTNET);
3132
should.equal(tx.gas, 21000);
3233
should.equal(tx.nonce, '64248');
3334
should.equal(tx.expiration, 64);
@@ -56,36 +57,14 @@ describe('Vet Burn NFT Transaction', () => {
5657
should.equal(tx.outputs[0].coin, 'tvet');
5758
});
5859

59-
it('should build a burn NFT transaction with custom contract address', async function () {
60-
const tokenId = '123456';
61-
const customContractAddress = STARGATE_CONTRACT_ADDRESS_TESTNET; // Use the valid testnet NFT address
62-
const txBuilder = factory.getBurnNftBuilder();
63-
64-
txBuilder.sender(testData.addresses.validAddresses[0]);
65-
txBuilder.tokenId(tokenId);
66-
txBuilder.nftContract(customContractAddress);
67-
txBuilder.gas(21000);
68-
txBuilder.nonce('64248');
69-
txBuilder.blockRef('0x014ead140e77bbc1');
70-
txBuilder.expiration(64);
71-
txBuilder.gasPriceCoef(128);
72-
73-
const tx = (await txBuilder.build()) as BurnNftTransaction;
74-
75-
should.equal(tx.contract, customContractAddress);
76-
should.exist(tx.clauses[0]);
77-
should.exist(tx.clauses[0].to);
78-
tx.clauses[0]?.to?.should.equal(customContractAddress);
79-
});
80-
8160
it('should deserialize and reserialize a signed burn NFT transaction', async function () {
8261
// Create a mock serialized transaction for burn NFT
8362
const tokenId = '123456';
8463
const txBuilder = factory.getBurnNftBuilder();
8564

8665
txBuilder.sender(testData.addresses.validAddresses[0]);
8766
txBuilder.tokenId(tokenId);
88-
txBuilder.nftContract(STARGATE_CONTRACT_ADDRESS_TESTNET);
67+
txBuilder.stakingContractAddress(stakingContractAddress);
8968
txBuilder.gas(21000);
9069
txBuilder.nonce('64248');
9170
txBuilder.blockRef('0x014ead140e77bbc1');
@@ -101,17 +80,17 @@ describe('Vet Burn NFT Transaction', () => {
10180

10281
should.equal(deserializedTx.type, TransactionType.StakingWithdraw);
10382
should.equal(deserializedTx.tokenId, tokenId);
104-
should.equal(deserializedTx.contract, STARGATE_CONTRACT_ADDRESS_TESTNET);
83+
should.equal(deserializedTx.stakingContractAddress, STARGATE_CONTRACT_ADDRESS_TESTNET);
10584
});
10685

10786
it('should validate the transaction data structure', async function () {
10887
const txBuilder = factory.getBurnNftBuilder();
10988

11089
// Should throw error when building without required fields
111-
await should(txBuilder.build()).be.rejectedWith('NFT contract address is required');
90+
await should(txBuilder.build()).be.rejectedWith('Staking contract address is required');
11291

11392
txBuilder.sender(testData.addresses.validAddresses[0]);
114-
txBuilder.nftContract(STARGATE_CONTRACT_ADDRESS_TESTNET);
93+
txBuilder.stakingContractAddress(stakingContractAddress);
11594
await should(txBuilder.build()).be.rejectedWith('Token ID is required');
11695

11796
// Now add the token ID and it should build successfully
@@ -123,18 +102,32 @@ describe('Vet Burn NFT Transaction', () => {
123102
const tx = await txBuilder.build();
124103
should.exist(tx);
125104
});
105+
106+
it('should build from raw signed tx', async function () {
107+
const txBuilder = factory.from(testData.BURN_NFT_TRANSACTION);
108+
const tx = txBuilder.transaction as BurnNftTransaction;
109+
const toJson = tx.toJson();
110+
toJson.id.should.equal('0xf5e074f2d127fa3ef014873ec193b76823efab51891d43861092bd52b122563e');
111+
toJson.stakingContractAddress?.should.equal('0x1e02b2953adefec225cf0ec49805b1146a4429c1');
112+
toJson.nonce.should.equal('327224');
113+
toJson.gas.should.equal(349324);
114+
toJson.gasPriceCoef.should.equal(128);
115+
toJson.expiration.should.equal(64);
116+
toJson.chainTag.should.equal(39);
117+
toJson.tokenId?.should.equal('15661');
118+
});
126119
});
127120

128121
describe('Validation', () => {
129122
it('should fail with invalid contract address', function () {
130123
const txBuilder = factory.getBurnNftBuilder();
131-
should(() => txBuilder.nftContract('invalid-address')).throwError('Invalid address invalid-address');
124+
should(() => txBuilder.stakingContractAddress('invalid-address')).throwError('Invalid address invalid-address');
132125
});
133126

134127
it('should fail with invalid token ID', async function () {
135128
const txBuilder = factory.getBurnNftBuilder();
136129
txBuilder.sender(testData.addresses.validAddresses[0]);
137-
txBuilder.nftContract(STARGATE_CONTRACT_ADDRESS_TESTNET);
130+
txBuilder.stakingContractAddress(stakingContractAddress);
138131
txBuilder.tokenId('');
139132

140133
await should(txBuilder.build()).be.rejectedWith('Token ID is required');

0 commit comments

Comments
 (0)