Skip to content

Commit

Permalink
cmd: Add support for paratime transfers fees
Browse files Browse the repository at this point in the history
  • Loading branch information
matevz committed Oct 21, 2024
1 parent 4ed32ca commit cfe754d
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 47 deletions.
26 changes: 18 additions & 8 deletions cmd/account/transfer.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ var transferCmd = &cobra.Command{
var sigTx, meta interface{}
switch npa.ParaTime {
case nil:
// Consensus layer transfer.
common.CheckForceErr(common.CheckAddressIsConsensusCapable(cfg, toAddr.String()))
if toEthAddr != nil {
common.CheckForceErr(common.CheckAddressIsConsensusCapable(cfg, toEthAddr.Hex()))
Expand All @@ -69,23 +70,22 @@ var transferCmd = &cobra.Command{
cobra.CheckErr("consensus layer only supports the native denomination")
}

// Consensus layer transfer.
amount, err := helpers.ParseConsensusDenomination(npa.Network, amount)
amountBaseUnits, err := helpers.ParseConsensusDenomination(npa.Network, amount)
cobra.CheckErr(err)

// Prepare transaction.
innerTx := staking.Transfer{
To: toAddr.ConsensusAddress(),
Amount: *amount,
Amount: *amountBaseUnits,
}
tx := staking.NewTransferTx(0, nil, &innerTx)

if subtractFee {
_, _, fee, err := common.ComputeConsensusGasInfo(ctx, npa, acc.ConsensusSigner(), conn, tx)
_, _, fee, err := common.ComputeConsensusGas(ctx, npa, acc.ConsensusSigner(), conn, tx)

Check failure on line 84 in cmd/account/transfer.go

View workflow job for this annotation

GitHub Actions / lint

shadow: declaration of "err" shadows declaration at line 73 (govet)
cobra.CheckErr(err)
err = amount.Sub(fee)
err = amountBaseUnits.Sub(fee)
cobra.CheckErr(err)
innerTx.Amount = *amount
innerTx.Amount = *amountBaseUnits
tx = staking.NewTransferTx(0, nil, &innerTx)
}

Expand All @@ -97,10 +97,20 @@ var transferCmd = &cobra.Command{
cobra.CheckErr(err)

// Prepare transaction.
tx := accounts.NewTransferTx(nil, &accounts.Transfer{
innerTx := accounts.Transfer{
To: *toAddr,
Amount: *amountBaseUnits,
})
}
tx := accounts.NewTransferTx(nil, &innerTx)

if subtractFee {
_, _, fee, _, err := common.ComputeParaTimeGas(ctx, npa, acc.Signer(), conn, tx)

Check failure on line 107 in cmd/account/transfer.go

View workflow job for this annotation

GitHub Actions / lint

shadow: declaration of "err" shadows declaration at line 96 (govet)
cobra.CheckErr(err)
err = amountBaseUnits.Amount.Sub(fee)
cobra.CheckErr(err)
innerTx.Amount = *amountBaseUnits
tx = accounts.NewTransferTx(nil, &innerTx)
}

txDetails := sdkSignature.TxDetails{OrigTo: toEthAddr}
sigTx, meta, err = common.SignParaTimeTransaction(ctx, npa, acc, conn, tx, &txDetails)
Expand Down
88 changes: 49 additions & 39 deletions cmd/common/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ func SignConsensusTransaction(
return nil, fmt.Errorf("consensus layer only supports the native denomination for paying fees")
}

_, gas, fee, err := ComputeConsensusGasInfo(ctx, npa, signer, conn, tx)
// TODO: Should be moved under !txOffline
_, gas, fee, err := ComputeConsensusGas(ctx, npa, signer, conn, tx)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -168,8 +169,10 @@ func SignConsensusTransaction(
return &consensusTx.SignedTransaction{Signed: *signed}, nil
}

// ComputeConsensusGasInfo estimates and returns the gas limit, gas price and derived fee amount. It assumes CLI parameters and the existing transaction properties.
func ComputeConsensusGasInfo(ctx context.Context, npa *NPASelection, signer coreSignature.Signer, conn connection.Connection, tx *consensusTx.Transaction) (gasPrice *quantity.Quantity, gas consensusTx.Gas, fee *quantity.Quantity, err error) {
// ComputeConsensusGas estimates gas for the given consensus transaction.
//
// Returns the gas price, gas limit and total fee amount.
func ComputeConsensusGas(ctx context.Context, npa *NPASelection, signer coreSignature.Signer, conn connection.Connection, tx *consensusTx.Transaction) (gasPrice *quantity.Quantity, gas consensusTx.Gas, fee *quantity.Quantity, err error) {
gasPrice = quantity.NewQuantity()
if txGasPrice != "" {
gasPrice, err = helpers.ParseConsensusDenomination(npa.Network, txGasPrice)
Expand All @@ -195,6 +198,44 @@ func ComputeConsensusGasInfo(ctx context.Context, npa *NPASelection, signer core
return
}

// ComputeParaTimeGas estimates gas for the given ParaTime transaction.
//
// Returns the gas price, gas limit and total fee amount.
func ComputeParaTimeGas(ctx context.Context, npa *NPASelection, signer signature.Signer, conn connection.Connection, tx *types.Transaction) (gasPrice *types.BaseUnits, gas consensusTx.Gas, fee *quantity.Quantity, feeDenom types.Denomination, err error) {

Check failure on line 204 in cmd/common/transaction.go

View workflow job for this annotation

GitHub Actions / lint

unused-parameter: parameter 'signer' seems to be unused, consider removing or renaming it as _ (revive)
feeDenom = types.Denomination(txFeeDenom)
if txGasPrice != "" {
var err error
gasPrice, err = helpers.ParseParaTimeDenomination(npa.ParaTime, txGasPrice, feeDenom)
if err != nil {
return nil, 0, nil, "", fmt.Errorf("bad gas price: %w", err)
}
}
if tx.AuthInfo.Fee.Gas == invalidGasLimit {
var err error
tx.AuthInfo.Fee.Gas, err = conn.Runtime(npa.ParaTime).Core.EstimateGas(ctx, client.RoundLatest, tx, false)
if err != nil {
return nil, 0, nil, "", fmt.Errorf("failed to estimate gas: %w", err)
}
}

// Gas price determination if not specified.
if txGasPrice == "" {
mgp, err := conn.Runtime(npa.ParaTime).Core.MinGasPrice(ctx)
if err != nil {
return nil, 0, nil, "", fmt.Errorf("failed to query minimum gas price: %w", err)
}

*gasPrice = types.NewBaseUnits(mgp[feeDenom], feeDenom)
}
fee = gasPrice.Amount.Clone()

// Compute fee amount based on gas price.
if err := fee.Mul(quantity.NewFromUint64(tx.AuthInfo.Fee.Gas)); err != nil {
return nil, 0, nil, "", err
}
return

Check failure on line 236 in cmd/common/transaction.go

View workflow job for this annotation

GitHub Actions / lint

naked return in func `ComputeParaTimeGas` with 33 lines of code (nakedret)
}

// SignParaTimeTransaction signs a ParaTime transaction.
//
// Returns the signed transaction and call format-specific metadata for result decoding.
Expand Down Expand Up @@ -229,17 +270,6 @@ func SignParaTimeTransaction(
tx.AuthInfo.Fee.Gas = txGasLimit
}

feeDenom := types.Denomination(txFeeDenom)

gasPrice := &types.BaseUnits{}
if txGasPrice != "" {
var err error
gasPrice, err = helpers.ParseParaTimeDenomination(npa.ParaTime, txGasPrice, feeDenom)
if err != nil {
return nil, nil, fmt.Errorf("bad gas price: %w", err)
}
}

if !hasSignerInfo {
nonce := txNonce

Expand All @@ -260,38 +290,18 @@ func SignParaTimeTransaction(
tx.AppendAuthSignature(account.SignatureAddressSpec(), nonce)
}

if !txOffline { //nolint: nestif
// Gas estimation if not specified.
if tx.AuthInfo.Fee.Gas == invalidGasLimit {
var err error
tx.AuthInfo.Fee.Gas, err = conn.Runtime(npa.ParaTime).Core.EstimateGas(ctx, client.RoundLatest, tx, false)
if err != nil {
return nil, nil, fmt.Errorf("failed to estimate gas: %w", err)
}
}

// Gas price determination if not specified.
if txGasPrice == "" {
mgp, err := conn.Runtime(npa.ParaTime).Core.MinGasPrice(ctx)
if err != nil {
return nil, nil, fmt.Errorf("failed to query minimum gas price: %w", err)
}

*gasPrice = types.NewBaseUnits(mgp[feeDenom], feeDenom)
}
_, _, fee, feeDenom, err := ComputeParaTimeGas(ctx, npa, account.Signer(), conn, tx)
if err != nil {
return nil, nil, err
}

// If we are using offline mode and gas limit is not specified, abort.
if tx.AuthInfo.Fee.Gas == invalidGasLimit {
return nil, nil, fmt.Errorf("gas limit must be specified in offline mode")
}

// Compute fee amount based on gas price.
if err := gasPrice.Amount.Mul(quantity.NewFromUint64(tx.AuthInfo.Fee.Gas)); err != nil {
return nil, nil, err
}
tx.AuthInfo.Fee.Amount.Amount = gasPrice.Amount
tx.AuthInfo.Fee.Amount.Denomination = gasPrice.Denomination
tx.AuthInfo.Fee.Amount.Amount = *fee
tx.AuthInfo.Fee.Amount.Denomination = feeDenom

// Handle confidential transactions.
var meta interface{}
Expand Down

0 comments on commit cfe754d

Please sign in to comment.