Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions client.js
Original file line number Diff line number Diff line change
Expand Up @@ -1027,6 +1027,7 @@ vorpal.command('transfer', 'transfers tokens to another account').action(async f
chatId: calculateChatId(to, USER.address),
memo: answers.memo ? answers.memo : null,
timestamp: Date.now(),
// deductTxFeeFromAmount: true,
//test: false
}
signTransaction(tx)
Expand Down
12 changes: 7 additions & 5 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ Transfers tokens between accounts.
"from": string, // Source account ID
"to": string, // Target account ID
"amount": bigint, // Amount to transfer (must be > 0)
"deductTxFeeFromAmount": boolean, // Optional, defaults to false. Supported from version 2.4.9.
"timestamp": number,
"sign": {
"owner": string // Must match 'from' field
Expand All @@ -499,15 +500,16 @@ Requirements:
- Amount must be greater than 0
- Source account must have sufficient balance to cover:
- Transfer amount
- Transaction fee
- Maintenance amount
- Transaction fee, unless `deductTxFeeFromAmount` is `true`
- If `deductTxFeeFromAmount` is `true`, the transfer amount must be greater than the transaction fee
- Must be signed by the source account
- Signature must be cryptographically valid

The transaction will:
1. Deduct amount + fees from source account
2. Add amount to target account
3. Update timestamps for both accounts
1. Deduct amount from source account
2. Add amount to target account, minus transaction fee when `deductTxFeeFromAmount` is `true`
3. Deduct transaction fee from source account when `deductTxFeeFromAmount` is false or omitted
4. Update timestamps for both accounts

#### `email` ⚠️ DEPRECATED
**Deprecated in version 2.5.0** - This transaction type is deprecated and will be removed in a future version. New transactions of this type will be rejected when network version >= 2.5.0.
Expand Down
1 change: 1 addition & 0 deletions src/@types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,7 @@ export namespace Tx {
}
chatId: string
fee?: bigint // Optional fee for the transfer
deductTxFeeFromAmount?: boolean // Optional, defaults to false. If true, tx fee is deducted from the transfer amount.
}

export interface Verify extends BaseLiberdusTx {
Expand Down
2 changes: 2 additions & 0 deletions src/@types/transactionSchemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ export const schemaTransferTX = {
amount: { isBigInt: true },
memo: { type: ['string', 'null'] },
chatId: { type: 'string' },
fee: { isBigInt: true },
deductTxFeeFromAmount: { type: 'boolean' },
},
required: [...baseTxRequired, 'from', 'to', 'amount', 'chatId'],
additionalProperties: false,
Expand Down
2 changes: 2 additions & 0 deletions src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ interface LiberdusFlags {
weiToLibStringFormat: boolean
includeTxToKeyInReadTx: boolean
updateTollRequiredTxInChatHistory: boolean
supportDeductTxFeeFromAmount: boolean
}
}

Expand Down Expand Up @@ -298,6 +299,7 @@ export const LiberdusFlags: LiberdusFlags = {
weiToLibStringFormat: true, // turn on by 2.4.8
includeTxToKeyInReadTx: true, // turn on by 2.4.8
updateTollRequiredTxInChatHistory: false, // turn on by 2.4.9
supportDeductTxFeeFromAmount: false, // turn on by 2.4.9
},
}

Expand Down
57 changes: 50 additions & 7 deletions src/transactions/transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,19 @@ export const validate_fields = (tx: Tx.Transfer, response: ShardusTypes.Incoming
response.reason = `tx "memo" size must be less than ${config.LiberdusFlags.transferMemoLimit} characters.`
return response
}
if (config.LiberdusFlags.versionFlags.supportDeductTxFeeFromAmount === true) {
if (tx.deductTxFeeFromAmount !== undefined && typeof tx.deductTxFeeFromAmount !== 'boolean') {
response.reason = 'tx "deductTxFeeFromAmount" field must be a boolean.'
return response
}
if (tx.deductTxFeeFromAmount === true) {
const transactionFee = utils.getTransactionFeeWei(AccountsStorage.cachedNetworkAccount)
if (tx.amount <= transactionFee) {
response.reason = 'transfer amount must be greater than the transaction fee when deductTxFeeFromAmount is true'
return response
}
}
}
if (!tx.sign || !tx.sign.owner || !tx.sign.sig || tx.sign.owner !== tx.from) {
response.reason = 'not signed by from account'
return response
Expand Down Expand Up @@ -89,10 +102,25 @@ export const validate = (
return response
}

if (from.data.balance < tx.amount + utils.getTransactionFeeWei(AccountsStorage.cachedNetworkAccount)) {
const transactionFee = utils.getTransactionFeeWei(AccountsStorage.cachedNetworkAccount)
const deductTxFeeFromAmount =
config.LiberdusFlags.versionFlags.supportDeductTxFeeFromAmount === true &&
tx.deductTxFeeFromAmount === true

if (deductTxFeeFromAmount === false && from.data.balance < tx.amount + transactionFee) {
response.reason = "from account doesn't have sufficient balance to cover the transaction"
return response
}
if (deductTxFeeFromAmount === true) {
if (from.data.balance < tx.amount) {
response.reason = "from account doesn't have sufficient balance to cover the transfer amount"
return response
}
if (tx.amount <= transactionFee) {
response.reason = 'transfer amount must be greater than the transaction fee when deductTxFeeFromAmount is true'
return response
}
}
// if there is a memo, check if the amount is larger than the Toll required for the chat
if (config.LiberdusFlags.versionFlags.minTransferAmountCheck) {
const hasMemo = (tx.memo && tx.memo.length > 0) || (tx.xmemo && tx.xmemo.message && tx.xmemo.message.length > 0)
Expand Down Expand Up @@ -160,10 +188,19 @@ export const apply = (
// update balances
const transactionFee = utils.getTransactionFeeWei(AccountsStorage.cachedNetworkAccount)
const maintenanceFee = utils.maintenanceAmount(txTimestamp, from, network)
from.data.balance = SafeBigIntMath.subtract(from.data.balance, transactionFee)
const deductTxFeeFromAmount =
config.LiberdusFlags.versionFlags.supportDeductTxFeeFromAmount === true &&
tx.deductTxFeeFromAmount === true
if (deductTxFeeFromAmount === false) {
from.data.balance = SafeBigIntMath.subtract(from.data.balance, transactionFee)
}
from.data.balance = SafeBigIntMath.subtract(from.data.balance, maintenanceFee)
from.data.balance = SafeBigIntMath.subtract(from.data.balance, tx.amount)
to.data.balance = SafeBigIntMath.add(to.data.balance, tx.amount)
let amountReceived = tx.amount
if (deductTxFeeFromAmount === true) {
amountReceived = SafeBigIntMath.subtract(tx.amount, transactionFee)
}
to.data.balance = SafeBigIntMath.add(to.data.balance, amountReceived)

// store transfer data in chat
if (!from.data.chats[tx.to]) {
Expand All @@ -184,6 +221,15 @@ export const apply = (
to.timestamp = txTimestamp
chat.timestamp = txTimestamp

const additionalInfo: { amount: bigint; maintenanceFee: bigint } = {
amount: tx.amount,
maintenanceFee,
}
if (deductTxFeeFromAmount === true) {
// amount reflects the net amount received by the recipient.
additionalInfo.amount = amountReceived
}

const appReceiptData: AppReceiptData = {
txId,
timestamp: txTimestamp,
Expand All @@ -192,10 +238,7 @@ export const apply = (
to: tx.to,
type: tx.type,
transactionFee,
additionalInfo: {
amount: tx.amount,
maintenanceFee,
},
additionalInfo,
}
const appReceiptDataHash = crypto.hashObj(appReceiptData)
dapp.applyResponseAddReceiptData(applyResponse, appReceiptData, appReceiptDataHash)
Expand Down
1 change: 1 addition & 0 deletions src/versioning/migrations/2.4.9.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export const migrate: Migration = async () => {
nestedCountersInstance.countEvent('migrate', 'calling migrate 2.4.9')

LiberdusFlags.versionFlags.updateTollRequiredTxInChatHistory = true
LiberdusFlags.versionFlags.supportDeductTxFeeFromAmount = true
}