Token Fee
ACS8 - Transaction Resource Token Fee Standard#
ACS8 is a transaction fee standard similar to ACS1, but it charges the called contract rather than the user. The fee charged includes four specified tokens: WRITE, READ, NET, and TRAFFIC.
When a contract inherits from ACS8, each transaction within this contract incurs charges in these four resource tokens.
Interface#
The acs8.proto file defines the following method:
Methods#
Method Name | Request Type | Response Type | Description |
---|---|---|---|
BuyResourceToken | acs8.BuyResourceTokenInput | google.protobuf.Empty | Buys one of the four resource tokens. Consumes ELF balance in the contract account. |
Types#
acs8.BuyResourceTokenInput
Field | Type | Description | Label |
---|---|---|---|
symbol | string | The symbol of the token to buy. | |
amount | int64 | The amount of token to buy. | |
pay_limit | int64 | Limit of cost; buying is abandoned if exceeded. 0 means no limit. |
Usage#
Contracts inheriting ACS1 use a pre-plugin transaction called ChargeTransactionFees for transaction fee charging. ACS8 introduces a similar post-plugin transaction called ChargeResourceToken, which charges resource tokens based on actual transaction consumption.
The ChargeResourceToken implementation involves calculating token amounts using polynomial coefficients stored in CalculateFeeCoefficients defined in token_contract.proto. Each resource token has a polynomial for fee calculation, which determines the cost based on transaction consumption.
1public override Empty ChargeResourceToken(ChargeResourceTokenInput input)2{3Context.LogDebug(() => string.Format("Start executing ChargeResourceToken.{0}", input));4if (input.Equals(new ChargeResourceTokenInput()))5{6return new Empty();7}8var bill = new TransactionFeeBill();9foreach (var pair in input.CostDic)10{11Context.LogDebug(() => string.Format("Charging {0} {1} tokens.", pair.Value, pair.Key));12var existingBalance = GetBalance(Context.Sender, pair.Key);13Assert(existingBalance >= pair.Value,14string.Format("Insufficient resource of {0}. Need balance: {1}; Current balance: {2}.", pair.Key, pair.Value, existingBalance));15bill.FeesMap.Add(pair.Key, pair.Value);16}17foreach (var pair in bill.FeesMap)18{19Context.Fire(new ResourceTokenCharged20{21Symbol = pair.Key,22Amount = pair.Value,23ContractAddress = Context.Sender24});25if (pair.Value == 0)26{27Context.LogDebug(() => string.Format("Maybe incorrect charged resource fee of {0}: it's 0.", pair.Key));28}29}30return new Empty();31}
Additionally, contracts cannot execute methods if they lack sufficient resource token balance. To enforce this, a pre-plugin transaction CheckResourceToken, similar to ACS5, verifies the contract's resource token balance before method execution.
1public override Empty CheckResourceToken(Empty input)2{3foreach (var symbol in Context.Variables.GetStringArray(TokenContractConstants.PayTxFeeSymbolListName))4{5var balance = GetBalance(Context.Sender, symbol);6var owningBalance = State.OwningResourceToken[Context.Sender][symbol];7Assert(balance > owningBalance,8string.Format("Contract balance of {0} token is not enough. Owning {1}.", symbol, owningBalance));9}10return new Empty();11}
Edited on: 15 July 2024 05:52:51 GMT+0