// Helpers.ts
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
var __values = (this && this.__values) || function(o) {
    var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
    if (m) return m.call(o);
    if (o && typeof o.length === "number") return {
        next: function () {
            if (o && i >= o.length) o = void 0;
            return { value: o && o[i++], done: !o };
        }
    };
    throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
import algosdk, { Algodv2, assignGroupID, makePaymentTxnWithSuggestedParamsFromObject, waitForConfirmation, } from "algosdk";
import { getForeignAssetAlgorand } from "../token_bridge";
import { _parseVAAAlgorand } from "./Algorand";
var ALGO_TOKEN = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
var ALGOD_ADDRESS = "http://localhost";
var ALGOD_PORT = 4001;
/**
 *  Creates a new Algodv2 client using local file consts
 * @returns a newly constructed Algodv2 client
 */
export function getAlgoClient() {
    var algodClient = new Algodv2(ALGO_TOKEN, ALGOD_ADDRESS, ALGOD_PORT);
    return algodClient;
}
var KMD_TOKEN = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
var KMD_ADDRESS = "http://localhost";
var KMD_PORT = 4002;
var KMD_WALLET_NAME = "unencrypted-default-wallet";
var KMD_WALLET_PASSWORD = "";
export function getKmdClient() {
    var kmdClient = new algosdk.Kmd(KMD_TOKEN, KMD_ADDRESS, KMD_PORT);
    return kmdClient;
}
export function getGenesisAccounts() {
    return __awaiter(this, void 0, void 0, function () {
        var retval, kmd, wallets, myWalletId, myWalletHandle, addresses, i, element, myExportedKey, mn, ta;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    retval = [];
                    kmd = getKmdClient();
                    return [4 /*yield*/, kmd.listWallets()];
                case 1:
                    wallets = (_a.sent()).wallets;
                    if (!wallets) {
                        console.error("No wallets found!");
                        return [2 /*return*/, retval];
                    }
                    myWalletId = "";
                    wallets.forEach(function (element) {
                        // console.log(element);
                        if (element.name === KMD_WALLET_NAME) {
                            myWalletId = element.id;
                        }
                    });
                    if (myWalletId.length === 0) {
                        console.error("invalid wallet ID");
                        return [2 /*return*/, retval];
                    }
                    return [4 /*yield*/, kmd.initWalletHandle(myWalletId, KMD_WALLET_PASSWORD)];
                case 2:
                    myWalletHandle = (_a.sent()).wallet_handle_token;
                    return [4 /*yield*/, kmd.listKeys(myWalletHandle)];
                case 3:
                    addresses = (_a.sent()).addresses;
                    i = 0;
                    _a.label = 4;
                case 4:
                    if (!(i < addresses.length)) return [3 /*break*/, 7];
                    element = addresses[i];
                    return [4 /*yield*/, kmd.exportKey(myWalletHandle, KMD_WALLET_PASSWORD, element)];
                case 5:
                    myExportedKey = (_a.sent()).private_key;
                    mn = algosdk.secretKeyToMnemonic(myExportedKey);
                    ta = algosdk.mnemonicToSecretKey(mn);
                    retval.push(ta);
                    _a.label = 6;
                case 6:
                    i++;
                    return [3 /*break*/, 4];
                case 7:
                    kmd.releaseWalletHandle(myWalletHandle);
                    // console.log("length of genesis accounts:", retval.length);
                    return [2 /*return*/, retval];
            }
        });
    });
}
export function firstKmdTransaction() {
    return __awaiter(this, void 0, void 0, function () {
        var genAccounts, e_1;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    _a.trys.push([0, 2, , 3]);
                    return [4 /*yield*/, getGenesisAccounts()];
                case 1:
                    genAccounts = _a.sent();
                    return [3 /*break*/, 3];
                case 2:
                    e_1 = _a.sent();
                    console.log("KMD transaction error:", e_1);
                    return [3 /*break*/, 3];
                case 3: return [2 /*return*/];
            }
        });
    });
}
// This function creates temporary accounts and funds them with the
// Genesis accounts.
export function getTempAccounts() {
    return __awaiter(this, void 0, void 0, function () {
        var retval, algodClient, genesisAccounts, numAccts, params, transactions, i, newAcct, fundingAcct, payTxn, signedTxn, signedTxnId, txId, confirmedTxn, accountInfo;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    retval = [];
                    algodClient = getAlgoClient();
                    return [4 /*yield*/, getGenesisAccounts()];
                case 1:
                    genesisAccounts = _a.sent();
                    numAccts = genesisAccounts.length;
                    if (numAccts === 0) {
                        console.error("Failed to get genesisAccounts");
                        return [2 /*return*/, retval];
                    }
                    return [4 /*yield*/, algodClient.getTransactionParams().do()];
                case 2:
                    params = _a.sent();
                    transactions = [];
                    i = 0;
                    _a.label = 3;
                case 3:
                    if (!(i < numAccts)) return [3 /*break*/, 8];
                    newAcct = createAccount();
                    if (!newAcct) {
                        throw new Error("failed to create a temp account");
                    }
                    fundingAcct = genesisAccounts[i];
                    payTxn = makePaymentTxnWithSuggestedParamsFromObject({
                        from: fundingAcct.addr,
                        to: newAcct.addr,
                        amount: 15000000,
                        suggestedParams: params,
                    });
                    signedTxn = payTxn.signTxn(fundingAcct.sk);
                    signedTxnId = payTxn.txID().toString();
                    return [4 /*yield*/, algodClient.sendRawTransaction(signedTxn).do()];
                case 4:
                    txId = _a.sent();
                    return [4 /*yield*/, algosdk.waitForConfirmation(algodClient, signedTxnId, 4)];
                case 5:
                    confirmedTxn = _a.sent();
                    return [4 /*yield*/, algodClient.accountInformation(newAcct.addr).do()];
                case 6:
                    accountInfo = _a.sent();
                    // console.log(
                    //     "Transaction Amount: %d microAlgos",
                    //     confirmedTxn.txn.txn.amt
                    // );
                    // console.log("Transaction Fee: %d microAlgos", confirmedTxn.txn.txn.fee);
                    // console.log("Account balance: %d microAlgos", accountInfo.amount);
                    retval.push(newAcct);
                    _a.label = 7;
                case 7:
                    i++;
                    return [3 /*break*/, 3];
                case 8: return [2 /*return*/, retval];
            }
        });
    });
}
export function createAccount() {
    try {
        var retval = algosdk.generateAccount();
        // let retval = new Account(tempAcct.addr, Buffer.from(tempAcct.sk));
        // let account_mnemonic = algosdk.secretKeyToMnemonic(tempAcct.sk);
        // console.log("Account Address = " + retval.addr);
        // console.log("Account Mnemonic = " + account_mnemonic);
        // console.log("Class Account:", retval);
        return retval;
    }
    catch (err) {
        console.log("err", err);
    }
}
/**
 *  Return the balances of all assets for the supplied account
 * @param client An Algodv2 client
 * @param account The account containing assets
 * @returns Map of asset index to qty
 */
export function getBalances(client, account) {
    return __awaiter(this, void 0, void 0, function () {
        var balances, accountInfo, assets;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    balances = new Map();
                    return [4 /*yield*/, client.accountInformation(account).do()];
                case 1:
                    accountInfo = _a.sent();
                    console.log("Account Info:", accountInfo);
                    console.log("Account Info|created-assets:", accountInfo["created-assets"]);
                    // Put the algo balance in key 0
                    balances.set(0, accountInfo.amount);
                    assets = accountInfo.assets;
                    console.log("assets", assets);
                    assets.forEach(function (asset) {
                        console.log("inside foreach", asset);
                        var assetId = asset["asset-id"];
                        var amount = asset.amount;
                        balances.set(assetId, amount);
                    });
                    console.log("balances", balances);
                    return [2 /*return*/, balances];
            }
        });
    });
}
/**
 * Return the balance of the supplied asset index for the supplied account
 * @param client An Algodv2 client
 * @param account The account to query for the supplied asset index
 * @param assetId The asset index
 * @returns The quantity of the asset in the supplied account
 */
export function getBalance(client, account, assetId) {
    return __awaiter(this, void 0, void 0, function () {
        var accountInfo, ret, assets;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, client.accountInformation(account).do()];
                case 1:
                    accountInfo = _a.sent();
                    if (assetId == 0) {
                        return [2 /*return*/, accountInfo.amount];
                    }
                    ret = 0;
                    assets = accountInfo.assets;
                    assets.forEach(function (asset) {
                        if (assetId === asset["asset-id"]) {
                            ret = asset.amount;
                            return;
                        }
                    });
                    return [2 /*return*/, ret];
            }
        });
    });
}
export function createAsset(account) {
    return __awaiter(this, void 0, void 0, function () {
        var aClient, params, note, addr, defaultFrozen, decimals, totalIssuance, unitName, assetName, assetURL, assetMetadataHash, manager, reserve, freeze, clawback, txn, rawSignedTxn, tx, ptx, assetID;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    console.log("Creating asset...");
                    aClient = getAlgoClient();
                    return [4 /*yield*/, aClient.getTransactionParams().do()];
                case 1:
                    params = _a.sent();
                    note = undefined;
                    addr = account.addr;
                    defaultFrozen = false;
                    decimals = 10;
                    totalIssuance = 1000000;
                    unitName = "NORIUM";
                    assetName = "norium";
                    assetURL = "http://someurl";
                    assetMetadataHash = "16efaa3924a6fd9d3a4824799a4ac65d";
                    manager = account.addr;
                    reserve = account.addr;
                    freeze = account.addr;
                    clawback = account.addr;
                    txn = algosdk.makeAssetCreateTxnWithSuggestedParams(addr, note, totalIssuance, decimals, defaultFrozen, manager, reserve, freeze, clawback, unitName, assetName, assetURL, assetMetadataHash, params);
                    rawSignedTxn = txn.signTxn(account.sk);
                    return [4 /*yield*/, aClient.sendRawTransaction(rawSignedTxn).do()];
                case 2:
                    tx = _a.sent();
                    return [4 /*yield*/, algosdk.waitForConfirmation(aClient, tx.txId, 4)];
                case 3:
                    ptx = _a.sent();
                    assetID = ptx["asset-index"];
                    //Get the completed Transaction
                    console.log("createAsset() - Transaction " +
                        tx.txId +
                        " confirmed in round " +
                        ptx["confirmed-round"]);
                    return [2 /*return*/, assetID];
            }
        });
    });
}
export function getForeignAssetFromVaaAlgorand(client, tokenBridgeId, vaa) {
    return __awaiter(this, void 0, void 0, function () {
        var parsedVAA;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    parsedVAA = _parseVAAAlgorand(vaa);
                    return [4 /*yield*/, getForeignAssetAlgorand(client, tokenBridgeId, parsedVAA.get("FromChain"), parsedVAA.get("Contract"))];
                case 1: return [2 /*return*/, _a.sent()];
            }
        });
    });
}
export function signSendAndConfirmAlgorand(algodClient, txs, wallet) {
    return __awaiter(this, void 0, void 0, function () {
        var signedTxns, txs_1, txs_1_1, tx, _a, _b, e_2_1, result;
        var e_2, _c;
        return __generator(this, function (_d) {
            switch (_d.label) {
                case 0:
                    assignGroupID(txs.map(function (tx) { return tx.tx; }));
                    signedTxns = [];
                    _d.label = 1;
                case 1:
                    _d.trys.push([1, 7, 8, 9]);
                    txs_1 = __values(txs), txs_1_1 = txs_1.next();
                    _d.label = 2;
                case 2:
                    if (!!txs_1_1.done) return [3 /*break*/, 6];
                    tx = txs_1_1.value;
                    if (!tx.signer) return [3 /*break*/, 4];
                    _b = (_a = signedTxns).push;
                    return [4 /*yield*/, tx.signer.signTxn(tx.tx)];
                case 3:
                    _b.apply(_a, [_d.sent()]);
                    return [3 /*break*/, 5];
                case 4:
                    signedTxns.push(tx.tx.signTxn(wallet.sk));
                    _d.label = 5;
                case 5:
                    txs_1_1 = txs_1.next();
                    return [3 /*break*/, 2];
                case 6: return [3 /*break*/, 9];
                case 7:
                    e_2_1 = _d.sent();
                    e_2 = { error: e_2_1 };
                    return [3 /*break*/, 9];
                case 8:
                    try {
                        if (txs_1_1 && !txs_1_1.done && (_c = txs_1.return)) _c.call(txs_1);
                    }
                    finally { if (e_2) throw e_2.error; }
                    return [7 /*endfinally*/];
                case 9: return [4 /*yield*/, algodClient.sendRawTransaction(signedTxns).do()];
                case 10:
                    _d.sent();
                    return [4 /*yield*/, waitForConfirmation(algodClient, txs[txs.length - 1].tx.txID(), 1)];
                case 11:
                    result = _d.sent();
                    return [2 /*return*/, result];
            }
        });
    });
}
