"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const crypto_browserify_1 = require("crypto-browserify");
const byzcoin_1 = require("../../../byzcoin");
exports.contractID = "coin";
exports.commandMint = "mint";
exports.commandFetch = "fetch";
exports.commandTransfer = "transfer";
exports.commandStore = "store";
exports.argumentCoinID = "coinID";
exports.argumentDarcID = "darcID";
exports.argumentType = "type";
exports.argumentCoins = "coins";
exports.argumentDestination = "destination";
exports.ruleSpawn = "spawn:" + exports.contractID;
exports.ruleMint = rule(exports.commandMint);
exports.ruleFetch = rule(exports.commandFetch);
exports.ruleTransfer = rule(exports.commandTransfer);
exports.ruleStore = rule(exports.commandStore);
/**
 * Generate the coin instance ID for a given darc ID
 *
 * @param buf Any buffer that is known to the caller
 * @returns the id as a buffer
 */
function coinIID(buf) {
    const h = crypto_browserify_1.createHash("sha256");
    h.update(Buffer.from(exports.contractID));
    h.update(buf);
    return h.digest();
}
exports.coinIID = coinIID;
/**
 * Mints coins on ByzCoin. For this to work, the DARC governing this coin instance needs to have a
 * 'invoke.Coin.mint' rule and the instruction will need to be signed by the appropriate identity.
 *
 * @param tx used to collect one or more instructions
 * @param coinID to mint
 * @param amount positive, non-zero value to mint on this coin
 */
function mint(tx, coinID, amount) {
    if (amount.lessThanOrEqual(0)) {
        throw new Error("cannot mint 0 or negative values");
    }
    tx.invoke(coinID, exports.contractID, exports.commandMint, [new byzcoin_1.Argument({ name: exports.argumentCoins, value: Buffer.from(amount.toBytesLE()) })]);
}
exports.mint = mint;
/**
 * Creates an instruction to transfer coins to another account.
 *
 * @param tx used to collect one or more instructions that will be bundled together and sent as one transaction
 * to byzcoin.
 * @param src the source account to fetch coins from.
 * @param dest the destination account to store the coins in. The destination must exist!
 * @param amount how many coins to transfer.
 */
function transfer(tx, src, dest, amount) {
    tx.invoke(src, exports.contractID, exports.commandTransfer, [new byzcoin_1.Argument({ name: exports.argumentDestination, value: dest }),
        new byzcoin_1.Argument({ name: exports.argumentCoins, value: Buffer.from(amount.toBytesLE()) })]);
}
exports.transfer = transfer;
/**
 * Fetches coins from a coinInstance and puts it on the ByzCoin 'stack' for use by the next instruction.
 * Unused coins are discarded by all nodes and thus lost.
 *
 * @param tx used to collect one or more instructions that will be bundled together and sent as one transaction
 * to byzcoin.
 * @param src the source account to fetch coins from.
 * @param amount how many coins to put on the stack
 */
function fetch(tx, src, amount) {
    tx.invoke(src, exports.contractID, exports.commandFetch, [new byzcoin_1.Argument({ name: exports.argumentCoins, value: Buffer.from(amount.toBytesLE()) })]);
}
exports.fetch = fetch;
/**
 * Stores coins from the ByzCoin 'stack' in the given coin-account. Only the coins of the stack with the same
 * name are added to the destination account.
 *
 * @param tx used to collect one or more instructions that will be bundled together and sent as one transaction
 * to byzcoin.
 * @param dst where the coins to store
 */
function store(tx, dst) {
    tx.invoke(dst, exports.contractID, exports.commandStore, []);
}
exports.store = store;
function rule(command) {
    return `invoke:${exports.contractID}.${command}`;
}
