Skip to content

Commit

Permalink
Merge pull request #277 from cdc-Hitesh/#272/bugfix-authInfo
Browse files Browse the repository at this point in the history
Problem: Support Multiple AuthInfo Fee Amount
  • Loading branch information
calvinaco authored Jun 23, 2021
2 parents 1adbd77 + 67ab8f1 commit 4a3b227
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 25 deletions.
53 changes: 53 additions & 0 deletions lib/e2e/transaction.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// @ts-nocheck
/* eslint-disable */
import 'mocha';
import Big from 'big.js';
Expand Down Expand Up @@ -189,6 +190,58 @@ describe('e2e test suite', function () {
const { transactionHash } = broadcastResult;
expect(transactionHash).to.match(/^[0-9A-F]{64}$/);
});
it('[BANK] creates a MsgSend Type Transaction with `Fee` amount and Broadcasts it.', async function () {
const hdKey = HDKey.fromMnemonic(env.mnemonic.communityAccount);
const hdKey2 = HDKey.fromMnemonic(env.mnemonic.reserveAccount);
const hdKey3 = HDKey.fromMnemonic(env.mnemonic.randomEmptyAccount);
const privKey = hdKey.derivePrivKey(`m/44'/${customNetwork.bip44Path.coinType}'/0'/0/0`);
const privKey2 = hdKey2.derivePrivKey(`m/44'/${customNetwork.bip44Path.coinType}'/0'/0/0`);
const randomPrivKey = hdKey3.derivePrivKey(`m/44'/${customNetwork.bip44Path.coinType}'/0'/0/0`);
const keyPair = Secp256k1KeyPair.fromPrivKey(privKey);
const keyPair2 = Secp256k1KeyPair.fromPrivKey(privKey2);
const randomKeyPair = Secp256k1KeyPair.fromPrivKey(randomPrivKey);

const cro = CroSDK({ network: customNetwork });
const rawTx = new cro.RawTransaction();
const address1 = new cro.Address(keyPair.getPubKey());
const address2 = new cro.Address(keyPair2.getPubKey());
const randomAddress = new cro.Address(randomKeyPair.getPubKey());
const client = await cro.CroClient.connect();

const msgSend1 = new cro.bank.MsgSend({
fromAddress: address1.account(),
toAddress: randomAddress.account(),
amount: new cro.Coin('100000', Units.BASE),
});

const account1 = await client.getAccount(address1.account());
const account2 = await client.getAccount(address2.account());

expect(account1).to.be.not.null;
expect(account2).to.be.not.null;

const signableTx = rawTx
.appendMessage(msgSend1)
.addSigner({
publicKey: keyPair.getPubKey(),
accountNumber: new Big(account1!.accountNumber),
accountSequence: new Big(account1!.sequence),
})
.setFee(cro.Coin.fromCRO("0.002"))
.toSignable();

const signedTx = signableTx
.setSignature(0, keyPair.sign(signableTx.toSignDocumentHash(0)))
.toSigned();

expect(msgSend1.fromAddress).to.eq(account1!.address);
expect(msgSend1.toAddress).to.eq(randomAddress.account());
const broadcastResult = await client.broadcastTx(signedTx.encode().toUint8Array());
assertIsBroadcastTxSuccess(broadcastResult);

const { transactionHash } = broadcastResult;
expect(transactionHash).to.match(/^[0-9A-F]{64}$/);
});

it('[STAKING] Creates, signs and broadcasts a `MsgDelegate` Tx', async function () {
const hdKey = HDKey.fromMnemonic(env.mnemonic.ecosystemAccount);
Expand Down
2 changes: 1 addition & 1 deletion lib/src/cosmos/v1beta1/types/tx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export type TxBody = {
export type AuthInfo = {
signerInfos: SignerInfo[];
fee: {
amount?: ICoin;
amount?: ICoin[];
gasLimit?: Big;
payer?: string;
granter?: string;
Expand Down
27 changes: 27 additions & 0 deletions lib/src/transaction/raw.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,33 @@ describe('Transaction', function () {
expect(actualSignerInfos[1].sequence).to.deep.eq(anotherSigner.accountSequence);
});

it('should set a single fee `amount` to AuthInfo', function () {
const tx = anyTransaction();
tx.setFee(cro.Coin.fromBaseUnit('10000'));

expect(tx.getAuthInfo().fee.amount).to.have.length(1);
expect(tx.getAuthInfo().fee!.amount![0].toCosmosCoin()).to.deep.eq({
amount: '10000',
denom: 'basetcro',
});
});

it('should append fee `amount` to AuthInfo', function () {
const tx = anyTransaction();
tx.appendFeeAmount(cro.Coin.fromBaseUnit('88888'));
tx.appendFeeAmount(cro.Coin.fromBaseUnit('99999'));

expect(tx.getAuthInfo().fee.amount).to.have.length(2);
expect(tx.getAuthInfo().fee!.amount![0].toCosmosCoin()).to.deep.eq({
amount: '88888',
denom: 'basetcro',
});
expect(tx.getAuthInfo().fee!.amount![1].toCosmosCoin()).to.deep.eq({
amount: '99999',
denom: 'basetcro',
});
});

it('should append signer to signerAccountNumbers', function () {
const anySigner = TransactionSignerFactory.build();

Expand Down
27 changes: 22 additions & 5 deletions lib/src/transaction/raw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,19 +160,36 @@ export const rawTransaction = function (config: InitConfigurations) {
}

/**
* Set fee to the raw tx
* @param {ICoin} fee to be set to the raw tx body
* Sets a `single` only fee amount to the raw tx
* @param {ICoin} feeAmount amount to be set to the raw tx body
* @returns {RawTransaction}
* @throws {Error} when fee set is invalid
* @memberof Transaction
* @deprecated
*/
public setFee(fee: ICoin): RawTransaction {
ow(fee, 'fee', owCoin());
this.authInfo.fee.amount = fee;
public setFee(feeAmount: ICoin): RawTransaction {
ow(feeAmount, 'fee', owCoin());
this.authInfo.fee.amount = [feeAmount];

return this;
}

/**
* Appends an `Amount` to the AuthInfo Fee Amount List
* @param {ICoin} feeAmount to be set to the raw tx body
* @returns {RawTransaction}
* @throws {Error} when fee set is invalid
* @memberof Transaction
*/
public appendFeeAmount(feeAmount: ICoin): RawTransaction {
ow(feeAmount, 'feeAmount', owCoin());
if (typeof this.authInfo.fee.amount === 'undefined') {
this.authInfo.fee.amount = [];
}
this.authInfo.fee.amount.push(feeAmount);
return this;
}

/**
* Set a timeout param to tx body
* @param {string} timeoutHeight to best to the broad-casted tx
Expand Down
31 changes: 13 additions & 18 deletions lib/src/transaction/signable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,9 @@ export class SignableTransaction {
txBody.value.messages.push(nativeMsg);
});

// TODO: structure integrity check
if (typeof cosmosObj.auth_info === 'undefined') {
throw new Error('Decoded Tx does not have a valid `authInfo`');
}
const cosmosAuthInfo = cosmosObj.auth_info;
const cosmosSignerInfos = cosmosAuthInfo.signer_infos;
const signerInfos: SignerInfo[] = [];
Expand Down Expand Up @@ -145,28 +147,21 @@ export class SignableTransaction {
});
});

if (cosmosAuthInfo.fee.amount.length > 1) {
// TODO: Multi-coin support
throw new Error(`More than one fee amount in transaction is not supported`);
}

let feeAmount;
let feeAmountCoin;
// Todo: handle multiple fee amounts
if (cosmosAuthInfo.fee.amount.length === 1) {
[feeAmount] = cosmosAuthInfo.fee.amount;
if (typeof cosmosAuthInfo.fee === 'undefined' || typeof cosmosAuthInfo.fee.amount === 'undefined') {
throw new Error('Decoded Tx AuthInfo does not have a valid `fee`');
}

if (feeAmount) {
const feeAmountString = feeAmount.amount!;
const feeAmountList: ICoin[] = cosmosAuthInfo.fee.amount.map((feeAmount) => {
const feeAmountString = feeAmount.amount;
const feeAmountDenom = feeAmount.denom;
feeAmountCoin = croSdk.Coin.fromCustomAmountDenom(feeAmountString, feeAmountDenom);
}
const feeAmountCoin = croSdk.Coin.fromCustomAmountDenom(feeAmountString, feeAmountDenom);
return feeAmountCoin;
});

const authInfo: AuthInfo = {
signerInfos,
fee: {
amount: feeAmountCoin || undefined,
amount: feeAmountList || undefined,
gasLimit: new Big(cosmosAuthInfo.fee.gas_limit || DEFAULT_GAS_LIMIT),
payer: cosmosAuthInfo.fee.payer,
granter: cosmosAuthInfo.fee.granter,
Expand Down Expand Up @@ -435,9 +430,9 @@ const legacyEncodeMsgs = (msgs: CosmosMsg[]): legacyAmino.Msg[] => {
return msgs.map((msg) => msg.toRawAminoMsg());
};

const legacyEncodeStdFee = (fee: ICoin | undefined, gas: Big | undefined): legacyAmino.StdFee => {
const legacyEncodeStdFee = (feeAmountList: ICoin[] | undefined, gas: Big | undefined): legacyAmino.StdFee => {
return {
amount: fee ? fee.toCosmosCoins() : [],
amount: feeAmountList ? feeAmountList.map((feeAmount) => feeAmount.toCosmosCoin()) : [],
gas: gas ? gas.toString() : DEFAULT_GAS_LIMIT.toString(),
};
};
Expand Down
5 changes: 4 additions & 1 deletion lib/src/utils/protoBuf/encoder/authInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ export const protoEncodeAuthInfo = (authInfo: AuthInfo): Bytes => {
}),
),
fee: {
amount: authInfo.fee.amount !== undefined ? [authInfo.fee.amount.toCosmosCoin()] : [],
amount:
authInfo.fee.amount !== undefined
? authInfo.fee.amount.map((feeAmount) => feeAmount.toCosmosCoin())
: [],
gasLimit: protoEncodeGasLimitOrDefault(authInfo),
},
};
Expand Down

0 comments on commit 4a3b227

Please sign in to comment.