/*
* Copyright (C) 2021-2022 Algodex VASP (BVI) Corp.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
const algosdk = require('algosdk');
const logger = require('../../../logger');
const AlgodError = require('../../../error/AlgodError');
const enc = require('../../../utils/encoder');
const teal = require('../../../teal');
/**
* # 🏭 makePlaceAssetTxns(order)
* Factory for creating [Maker]{@tutorial Maker} sell transactions
*
* ### ➕ Open Order Transactions:
*
* | Index | Direction | Type | Description | Signer |
* | ----- | --------- | ---- | ----------- | ------ |
* | TXN 0 | SELLER TO ESCROW | {@link algosdk.makeAssetTransferTxn} | Pay from order creator to escrow account | {@link Wallet} |
* | TXN 1 | ESCROW TO ORDERBOOK | {@link algosdk.makePaymentTxn} | Stateful app opt-in to order book | {@link algosdk.LogicSigAccount} |
* | TXN 2 | ESCROW TO ESCROW | {@link algosdk.makeAssetTransferTxn} | (Optional) ASA opt-in for the newly created escrow account | {@link algosdk.LogicSigAccount} |
* | TXN 3 | SELLER TO ESCROW | {@link algosdk.makeAssetTransferTxn} | Asset transfer Txn representing the amount of asset moved to escrow | {@link Wallet} |
*
*
*
*
* @param {Order} order The Order
* @param {boolean} [optIn] Flag for if the escrow has opted in
* @return {Promise<Structures>}
* @throws ValidationError
* @memberOf module:txns/sell
*/
async function makePlaceAssetTxns(
order,
optIn=false,
) {
if (!(order.client instanceof algosdk.Algodv2)) {
throw new AlgodError('Order must have a valid SDK client');
}
if (typeof order.appId !== 'number') {
throw new TypeError('Must have valid Application Index');
}
if (typeof order.contract !== 'undefined' && typeof order.contract.entry !== 'string') {
throw new TypeError('Order must have a valid contract state with an entry!');
}
if (order.contract?.amount === 0) {
throw new Error('Cannot place a maker order with a 0 Amount');
}
if (order.execution !== 'maker') {
throw new Error('Must be maker only mode!');
}
let _optIn = optIn;
// TODO: Remove, just use order.wallet['assets] and only fetch if it doesn't exist
if (typeof order?.wallet?.assets === 'undefined' && !_optIn) {
logger.warn({address: order.address}, 'Loading account info!');
const {account: accountInfo} = await order.indexer.lookupAccountByID(order.contract.lsig.address()).do();
if (accountInfo != null && accountInfo['apps-local-state'] != null &&
accountInfo['apps-local-state'].length > 0 &&
accountInfo['apps-local-state'][0].id === order.appId) {
_optIn = true;
}
}
// const _exists = typeof order?.contract?.creator !== 'undefined';
const _suggestedParams = await teal.getTransactionParams(order.client, order.contract.params, true);
// Main Transaction
const assetSendTxn = algosdk.makeAssetTransferTxnWithSuggestedParams(
order.address,
order.contract.lsig.address(),
undefined,
undefined,
order.contract.amount,
undefined,
order.asset.id,
_suggestedParams,
undefined,
);
// Lisg has opted in, return the transfer transaction
// NOTE: This is an early return!
if (_optIn) {
return [{
unsignedTxn: assetSendTxn,
needsUserSig: true,
senderAcct: order.address,
}];
}
const _appArgs = [
enc.encode('open'),
enc.encode(order.contract.entry.slice(59)),
new Uint8Array([order.version]),
];
/**
* Place Asset Structures
* @type {Structures}
*/
return [
// Payment Transaction
{
unsignedTxn: algosdk.makePaymentTxnWithSuggestedParams(
order.address,
order.contract.lsig.address(),
500000, // TODO: Move back to constants MIN_ASA_ESCROW_BALANCE
undefined,
undefined,
_suggestedParams,
),
senderAcct: order.address,
},
// Application OptIn Transaction
{
unsignedTxn: await teal.txns.makeTransactionFromLogicSig(
order.client,
'appOptIn',
order.contract.lsig,
_suggestedParams,
order.appId,
_appArgs,
),
lsig: order.contract.lsig,
},
// LogSigAssetOptIn Transaction
{
unsignedTxn: algosdk.makeAssetTransferTxnWithSuggestedParams(
order.contract.lsig.address(),
order.contract.lsig.address(),
undefined,
undefined,
0,
undefined,
order.asset.id,
_suggestedParams,
),
lsig: order.contract.lsig,
},
// Asset Transfer Transaction
{
unsignedTxn: assetSendTxn,
senderAcct: order.address,
},
];
}
module.exports = makePlaceAssetTxns;