Skip to content

Instantly share code, notes, and snippets.

@sudoaza
Created November 19, 2019 17:00
Show Gist options
  • Save sudoaza/1803abb81ba54492852e540f1e70b718 to your computer and use it in GitHub Desktop.
Save sudoaza/1803abb81ba54492852e540f1e70b718 to your computer and use it in GitHub Desktop.
const {
BaseTransaction,
TransactionError,
utils
} = require('@liskhq/lisk-transactions');
/**
* Send tokens to multiple recipients.
*/
class MultiSendTransaction extends BaseTransaction {
static get TYPE () {
return 42;
}
static get FEE () {
return `${2*10**6}`;
};
async prepare(store) {
let accounts = [{ address: this.senderId }];
accounts.push(...this.asset.recipients);
await store.account.cache(accounts);
}
validateAsset() {
const errors = [];
// Check we have necesary parameters
if (!this.asset.recipients || !this.asset.recipients.length || !this.asset.amounts || !this.asset.amounts.length) {
errors.push(
new TransactionError(
'A valid transaction should have a list of recipients and a list of amounts',
this.id,
'.recipients',
this.asset.recipients,
'.amounts',
this.asset.amounts
)
);
return errors;
}
// Check recipient count is valid
if (this.asset.recipients.length < 2 || this.asset.recipients.length > 10) {
errors.push(
new TransactionError(
'Recipients should have between 2 and 10 entries',
this.id,
'.recipients',
this.asset.recipients
)
);
}
// Check no duplicate recipient
if ((new Set(this.asset.recipients)).size != this.asset.recipients.length) {
errors.push(
new TransactionError(
'Recipients cannot have duplicate entries',
this.id,
'.recipients',
this.asset.recipients
)
);
}
// Check sender not in recipients list
if (this.asset.recipients.includes(this.senderId)) {
errors.push(
new TransactionError(
'Sender cannot be among recipients',
this.id,
'.recipients',
this.asset.recipients
)
);
}
// Check amounts count is valid
if (this.asset.amounts.length < 2 || this.asset.amounts.length > 10) {
errors.push(
new TransactionError(
'Amounts should have between 2 and 10 entries',
this.id,
'.amounts',
this.asset.amounts
)
);
}
// Check same amount of balances as recipients
if (this.asset.recipients.length != this.asset.amounts.length) {
errors.push(
new TransactionError(
'Recipients length doesn\'t match amounts length',
this.id,
'.recipients',
this.asset.recipients
)
);
}
// All recipientId should be string
this.asset.recipients.forEach((recipientId, idx) => {
if (!recipientId || typeof recipientId !== 'string') {
errors.push(
new TransactionError(
'Invalid "recipientId" defined on transaction',
this.id,
'.recipients[]',
recipientId
)
);
}
});
// All amounts should be numeric and above 0
this.asset.amounts.forEach((amount, idx) => {
if (!amount || typeof amount !== 'number' || new utils.BigNum(amount) <= 0) {
errors.push(
new TransactionError(
'Invalid "amount" defined on transaction, should be numeric and greater than 0',
this.id,
'.amounts[]',
amount
)
);
}
});
return errors;
}
applyAsset(store) {
const errors = [];
const balance = new utils.BigNum(sender.balance);
const sentAmount = this.asset.amounts.reduce((accumulator, currValue) =>{
return accumulator.add(new utils.BigNum(currValue));
}, new utils.BigNum(0));
const updatedSenderBalance = balance.sub(sentAmount);
if (updatedSenderBalance < 0) {
errors.push(
new TransactionError(
'Not enough funds for transaction',
this.id,
'total amount',
sent_amount
)
);
return errors;
}
// Update sender balance
const sender = store.account.get(this.senderId);
const updatedSender = {
...sender,
balance: updatedSenderBalance.toString(),
};
store.account.set(sender.address, updatedSender);
// Update recipients balances
this.asset.amounts.forEach((amount, idx) => {
this.sendTokens(recipients[idx], amount);
});
return errors;
}
undoAsset(store) {
const errors = [];
return errors;
}
sendTokens(recipientId, amount) {
const recipient = store.account.get(recipientId);
const updatedRecipientBalance = new utils.BigNum(recipient.balance).add(new utils.BigNum(amount));
const updatedRecipient = {
...recipient,
balance: updatedRecipientBalance.toString(),
};
store.account.set(recipient.address, updatedRecipient);
}
}
module.exports = MultiSendTransaction;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment