swapable
Version:
Swapable: Automated Liquidity Pools
154 lines (153 loc) • 6.36 kB
JavaScript
;
/**
* This file is part of Swapable shared under AGPL-3.0
* Copyright (C) 2021 Using Blockchain Ltd, Reg No.: 12658136, United Kingdom
*
* @package Swapable
* @author Grégory Saive for Using Blockchain Ltd <greg@ubc.digital>
* @license AGPL-3.0
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Executable = void 0;
const symbol_uri_scheme_1 = require("symbol-uri-scheme");
const symbol_sdk_1 = require("symbol-sdk");
// internal dependencies
const index_1 = require("../../index");
const FailureEmptyContract_1 = require("../errors/FailureEmptyContract");
/**
* @abstract
* @class Swapable.Executable
* @package Swapable
* @subpackage Commands
* @since v1.0.0
* @description Abstract class that describes a pool command
* for assets compliant with the automated pool
* standard as defined in this package. This is
* the base layer for the execution of commands.
*/
class Executable extends index_1.BaseCommand {
/**
* Construct an executable command object around \a context
* and an \a identifier of automated pool shares.
*
* @access public
* @param {Context} context The execution context.
* @param {AssetIdentifier} identifier The automated pool shares asset identifier.
*/
constructor(
/**
* @readonly
* @access public
* @description The execution context.
*/
context,
/**
* @readonly
* @access public
* @description The automated pool shares asset identifier.
*/
identifier) {
super(context);
this.context = context;
this.identifier = identifier;
/**
* @access public
* @description The list of **required** arguments to execute
* an automated pool command.
*/
this.arguments = [];
this.target = this.identifier.target;
}
// end-region abstract methods
/**
* Verifies **allowance** of \a actor to execute a command
* with arguments \a argv. By default, this method returns
* true *only* if the actor is the automated pool's target
* account.
*
* This method asserts the presence of mandatory arguments.
*
* @access public
* @param {PublicAccount} actor The actor is whom executes the command.
* @param {Array<CommandOption>} argv The command options (arguments).
* @return {AllowanceResult} Returns whether an actor is authorized to execute this command.
* @throws {FailureMissingArgument} On missing mandatory argument(s).
**/
canExecute(actor, argv) {
// - Asserts the presence of mandatory inputs
super.assertHasMandatoryArguments(argv, this.arguments);
// - By default, only target can execute commands ("owner only")
const isOperator = actor.address.equals(this.target.address);
return new index_1.AllowanceResult(isOperator);
}
/**
* Executes an automated pool command with \a actor given
* \a argv command options.
*
* @access public
* @param {PublicAccount} actor The actor is whom executes the command.
* @param {Array<CommandOption>} argv The command options (arguments).
* @return {TransactionURI<T>} Returns one transaction URI with all transactions.
* @throws {FailureMissingArgument} On missing mandatory argument(s).
* @throws {FailureOperationForbidden} On denial of authorization.
**/
execute(actor, argv) {
// - Verifies the authorization to execute
super.assertExecutionAllowance(actor, argv);
// - Creates a digital contract for this execution
const contract = this.prepare();
// - Formats the result as a transaction URI
return new symbol_uri_scheme_1.TransactionURI(contract.serialize(), symbol_sdk_1.TransactionMapping.createFromPayload);
}
/**
* Wraps the resulting transactions inside an aggregate bonded
* transaction. We will later refer to this transaction as the
* **digital contract**.
*
* Prior to announcing this digital contract to a network, and
* waiting for it to be included in a new block, you must also
* announce a HashLockTransaction to allow the use of contracts.
*
* @link https://docs.symbolplatform.com/serialization/lock_hash.html#hash-lock-transaction
* @link https://docs.symbolplatform.com/concepts/aggregate-transaction.html#id3
*
* @access protected
* @return {AggregateTransaction} Aggregate bonded transaction
* @throws {FailureEmptyContract} Given a misconfigured digital contract which is empty.
**/
prepare() {
// - Sanity check
if (!this.transactions.length) {
throw new FailureEmptyContract_1.FailureEmptyContract('No transactions result from the execution of this contract.');
}
// - Shortcut for network information
const reader = this.context.reader;
// - Creates a so-called digital contract
return symbol_sdk_1.AggregateTransaction.createBonded(this.context.parameters.deadline, this.transactions, reader.networkType, [], // "unsigned"
this.context.parameters.maxFee);
}
/**
* Returns the available **reserve** of asset \a r. This method
* is used internally to determine the available balance in the
* automated pool and calculate the liquidity shares ratio.
*
* @access protected
* @param {AssetIdentifier} r The asset identifier (i.e. for which to check reserves).
* @return number The total balance (reserve) available.
*/
reserveOf(r) {
var _a;
// - Step out if we don't have the info
if (this.reserveInfo === undefined) {
return 0; //XXX FailureEmptyReserve
}
// - Reads reserve mosaic balance
const reserve = (_a = this.reserveInfo) === null || _a === void 0 ? void 0 : _a.mosaics.filter((m) => m.id.id.equals(r.toMosaicId().id));
// - Step out if we don't have the info
if (!reserve.length) {
return 0; //XXX FailureEmptyReserve
}
return reserve[0].amount.compact();
}
}
exports.Executable = Executable;