Skip to content

Commit 753bb94

Browse files
committed
feat(abstract-cosmos,sdk-coin-hash): add fee granter support and group policy addresses
Ticket: WIN-8811 - Add feeGranter field to FeeData and method to TransactionBuilder - Support group policy addresses (58 chars) in Hash coin validation - Add tests for both features
1 parent 4cfcfb0 commit 753bb94

7 files changed

Lines changed: 46 additions & 4 deletions

File tree

modules/abstract-cosmos/src/lib/iface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ export interface MessageData<CustomMessage = never> {
8484
export interface FeeData {
8585
amount: Coin[];
8686
gasLimit: number;
87+
feeGranter?: string;
8788
}
8889

8990
export interface GasAmountDetails {

modules/abstract-cosmos/src/lib/transactionBuilder.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,21 @@ export abstract class CosmosTransactionBuilder<CustomMessage = never> extends Ba
143143
return this;
144144
}
145145

146+
/**
147+
* Sets the fee granter address for this transaction.
148+
* The fee granter is the address that will pay the transaction fees on behalf of the signer.
149+
* @param {string} address - The address that will pay the transaction fees
150+
* @returns {TransactionBuilder} this transaction builder
151+
*/
152+
feeGranter(address: string): this {
153+
this.validateAddress({ address });
154+
if (!this._gasBudget) {
155+
throw new BuildTransactionError('Gas budget must be set before setting fee granter');
156+
}
157+
this._gasBudget.feeGranter = address;
158+
return this;
159+
}
160+
146161
/**
147162
* Initialize the transaction builder fields using the decoded transaction data
148163
* @param {CosmosTransaction} tx the transaction data

modules/abstract-cosmos/src/lib/utils.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,10 +179,14 @@ export class CosmosUtils<CustomMessage = never> implements BaseUtils {
179179
* @returns {FeeData} fee data
180180
*/
181181
getGasBudgetFromDecodedTx(decodedTx: DecodedTxRaw): FeeData {
182-
return {
182+
const feeData: FeeData = {
183183
amount: decodedTx.authInfo.fee?.amount as Coin[],
184184
gasLimit: Number(decodedTx.authInfo.fee?.gasLimit),
185185
};
186+
if (decodedTx.authInfo.fee?.granter) {
187+
feeData.feeGranter = decodedTx.authInfo.fee.granter;
188+
}
189+
return feeData;
186190
}
187191

188192
/**
@@ -419,7 +423,7 @@ export class CosmosUtils<CustomMessage = never> implements BaseUtils {
419423
[{ pubkey: encodedPublicKey, sequence }],
420424
cosmosLikeTransaction.gasBudget.amount,
421425
cosmosLikeTransaction.gasBudget.gasLimit,
422-
undefined,
426+
cosmosLikeTransaction.gasBudget.feeGranter || undefined,
423427
undefined,
424428
undefined
425429
);

modules/sdk-coin-hash/src/lib/constants.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ import { CosmosUtils } from '@bitgo/abstract-cosmos';
22

33
const cosmosUtils = new CosmosUtils();
44
export const validDenoms = ['nhash', 'uhash', 'mhash', 'hash', ...cosmosUtils.getTokenDenomsUsingCoinFamily('hash')];
5-
export const mainnetAccountAddressRegex = /^(pb)1(['qpzry9x8gf2tvdw0s3jn54khce6mua7l]{38})$/;
5+
export const mainnetAccountAddressRegex = /^(pb)1(['qpzry9x8gf2tvdw0s3jn54khce6mua7l]{38,58})$/;
66
export const mainnetValidatorAddressRegex = /^(pbvaloper)1(['qpzry9x8gf2tvdw0s3jn54khce6mua7l]{38})$/;
77
export const mainnetContractAddressRegex = /^(pb)1(['qpzry9x8gf2tvdw0s3jn54khce6mua7l]+)$/;
88
export const MAINNET_ADDRESS_PREFIX = 'pb';
99

10-
export const testnetAccountAddressRegex = /^(tp)1(['qpzry9x8gf2tvdw0s3jn54khce6mua7l]{38})$/;
10+
export const testnetAccountAddressRegex = /^(tp)1(['qpzry9x8gf2tvdw0s3jn54khce6mua7l]{38,58})$/;
1111
export const testnetValidatorAddressRegex = /^(tpvaloper)1(['qpzry9x8gf2tvdw0s3jn54khce6mua7l]{38})$/;
1212
export const testnetContractAddressRegex = /^(tp)1(['qpzry9x8gf2tvdw0s3jn54khce6mua7l]+)$/;
1313
export const TESTNET_ADDRESS_PREFIX = 'tp';

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ export const mainnetAddress = {
271271
address2: 'pb16vmp7sz28pnvgz6f3zm6q93y39jsd33aazwg4u',
272272
address3: 'pb2xvd4k9jg5h0d4dhzr4z0txtwe9p5zxf58xcmxd',
273273
address4: 'pb1fmxzuzx5c4ja50vu94nt0aessnuedzmppde8qq',
274+
groupPolicyAddress: 'pb1tazefwk2e372fy2jq08w6lztg9yrrvc490r2gp4vt8d0fchlrfqqt58ltq',
274275
validatorAddress1: 'pbvaloper13905qnf0mc8f8h3dawsq0894ded0ct83f66l56',
275276
validatorAddress2: 'pbvaloper1d7yum2cxwkhmmuxa096prlv5gawjxw0gc2sykq',
276277
validatorAddress3: 'pbvaloder17yx96jtu0r24jp8gyxc8y8pj0lgvcz964w2gyg',
@@ -286,6 +287,7 @@ export const testnetAddress = {
286287
address2: 'tp1ytxha7lg002rzd4jxmahrdjzkd62mx99klgjcc',
287288
address3: 'txp1x96r8u4a48k6khknrhzd6c8cm3c64ewxy5prj',
288289
address4: 'tp1umned7wx7le70ttvrcem3fsyhn343asr2k2pww',
290+
groupPolicyAddress: 'tp1tazefwk2e372fy2jq08w6lztg9yrrvc490r2gp4vt8d0fchlrfqqyahg0u',
289291
validatorAddress1: 'tpvaloper1tgq6cpu6hmsrvkvdu82j99tsxxw7qqajn843fe',
290292
validatorAddress2: 'tpvaloper1tgq6cpu6hmsrvkvdu82j99tsxxw7qqajn843fe',
291293
validatorAddress3: 'txvaloper1xxxxcpu6hmsrvkvdu82j99tsxxw7qqajn843fe',

modules/sdk-coin-hash/test/unit/hash.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ describe('HASH', function () {
104104
should.equal(mainnetUtils.isValidAddress(''), false);
105105
should.equal(mainnetUtils.isValidAddress(mainnetAddress.validMemoIdAddress), true);
106106
should.equal(mainnetUtils.isValidAddress(mainnetAddress.multipleMemoIdAddress), false);
107+
should.equal(mainnetUtils.isValidAddress(mainnetAddress.groupPolicyAddress), true);
107108

108109
should.equal(testnetUtils.isValidAddress(testnetAddress.address1), true);
109110
should.equal(testnetUtils.isValidAddress(testnetAddress.address2), true);
@@ -114,6 +115,7 @@ describe('HASH', function () {
114115
should.equal(testnetUtils.isValidAddress(''), false);
115116
should.equal(testnetUtils.isValidAddress(testnetAddress.validMemoIdAddress), true);
116117
should.equal(testnetUtils.isValidAddress(testnetAddress.multipleMemoIdAddress), false);
118+
should.equal(testnetUtils.isValidAddress(testnetAddress.groupPolicyAddress), true);
117119
});
118120

119121
it('should validate validator addresses correctly', () => {

modules/sdk-coin-hash/test/unit/transactionBuilder/transferBuilder.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,4 +310,22 @@ describe('Hash Token Transfer Builder', () => {
310310
},
311311
]);
312312
});
313+
314+
it('should build a Transfer tx with fee granter', async function () {
315+
const feeGranterAddress = testData.testnetAddress.address2;
316+
const txBuilder = factory.getTransferBuilder();
317+
txBuilder.sequence(testTx.sequence);
318+
txBuilder.gasBudget(testTx.gasBudget);
319+
txBuilder.feeGranter(feeGranterAddress);
320+
txBuilder.messages([testTx.sendMessage.value]);
321+
txBuilder.publicKey(toHex(fromBase64(testTx.pubKey)));
322+
323+
const tx = await txBuilder.build();
324+
const json = await (await txBuilder.build()).toJson();
325+
should.equal(tx.type, TransactionType.Send);
326+
should.deepEqual(json.gasBudget.amount, testTx.gasBudget.amount);
327+
should.deepEqual(json.gasBudget.gasLimit, testTx.gasBudget.gasLimit);
328+
should.equal(json.gasBudget.feeGranter, feeGranterAddress);
329+
should.deepEqual(json.sendMessages, [testTx.sendMessage]);
330+
});
313331
});

0 commit comments

Comments
 (0)