{"version":3,"file":"account-manager.mjs","sources":["../../src/types/account-manager.ts"],"sourcesContent":["import algosdk, { Address } from 'algosdk'\nimport { Config } from '../config'\nimport { calculateFundAmount, memoize } from '../util'\nimport { AccountInformation, DISPENSER_ACCOUNT, MultisigAccount, SigningAccount, TransactionSignerAccount } from './account'\nimport { AlgoAmount } from './amount'\nimport { ClientManager } from './client-manager'\nimport { CommonTransactionParams, TransactionComposer } from './composer'\nimport { TestNetDispenserApiClient } from './dispenser-client'\nimport { KmdAccountManager } from './kmd-account-manager'\nimport { SendParams, SendSingleTransactionResult } from './transaction'\nimport LogicSigAccount = algosdk.LogicSigAccount\nimport Account = algosdk.Account\nimport TransactionSigner = algosdk.TransactionSigner\n\nconst address = (address: string | Address) => (typeof address === 'string' ? Address.fromString(address) : address)\n\n/** Result from performing an ensureFunded call. */\nexport interface EnsureFundedResult {\n  /** The transaction ID of the transaction that funded the account. */\n  transactionId: string\n  /** The amount that was sent to the account. */\n  amountFunded: AlgoAmount\n}\n\n/**\n * Returns a `TransactionSigner` for the given account that can sign a transaction.\n * This function has memoization, so will return the same transaction signer for a given account.\n * @param account An account that can sign a transaction\n * @returns A transaction signer\n * @example\n * ```typescript\n * const signer = getAccountTransactionSigner(account)\n * ```\n */\nexport const getAccountTransactionSigner = memoize(function (\n  account: TransactionSignerAccount | Account | SigningAccount | LogicSigAccount | MultisigAccount,\n): TransactionSigner {\n  return 'signer' in account\n    ? account.signer\n    : 'lsig' in account\n      ? algosdk.makeLogicSigAccountTransactionSigner(account)\n      : algosdk.makeBasicAccountTransactionSigner(account)\n})\n\n/** Creates and keeps track of signing accounts that can sign transactions for a sending address. */\nexport class AccountManager {\n  private _clientManager: ClientManager\n  private _kmdAccountManager: KmdAccountManager\n  private _accounts: { [address: string]: TransactionSignerAccount } = {}\n  private _defaultSigner?: algosdk.TransactionSigner\n\n  /**\n   * Create a new account manager.\n   * @param clientManager The ClientManager client to use for algod and kmd clients\n   * @example Create a new account manager\n   * ```typescript\n   * const accountManager = new AccountManager(clientManager)\n   * ```\n   */\n  constructor(clientManager: ClientManager) {\n    this._clientManager = clientManager\n    this._kmdAccountManager = new KmdAccountManager(clientManager)\n  }\n\n  private _getComposer(getSuggestedParams?: () => Promise<algosdk.SuggestedParams>) {\n    return new TransactionComposer({\n      algod: this._clientManager.algod,\n      getSigner: this.getSigner.bind(this),\n      getSuggestedParams: getSuggestedParams ?? (() => this._clientManager.algod.getTransactionParams().do()),\n    })\n  }\n\n  /**\n   * KMD account manager that allows you to easily get and create accounts using KMD.\n   * @returns The `KmdAccountManager` instance.\n   * @example\n   * ```typescript\n   * const kmdManager = accountManager.kmd;\n   * ```\n   */\n  public get kmd() {\n    return this._kmdAccountManager\n  }\n\n  /**\n   * Sets the default signer to use if no other signer is specified.\n   *\n   * If this isn't set an a transaction needs signing for a given sender\n   * then an error will be thrown from `getSigner` / `getAccount`.\n   * @param signer The signer to use, either a `TransactionSigner` or a `TransactionSignerAccount`\n   * @example\n   * ```typescript\n   * const signer = accountManager.random() // Can be anything that returns a `algosdk.TransactionSigner` or `TransactionSignerAccount`\n   * accountManager.setDefaultSigner(signer)\n   *\n   * // When signing a transaction, if there is no signer registered for the sender then the default signer will be used\n   * const signer = accountManager.getSigner(\"SENDERADDRESS\")\n   * ```\n   * @returns The `AccountManager` so method calls can be chained\n   */\n  public setDefaultSigner(signer: algosdk.TransactionSigner | TransactionSignerAccount): AccountManager {\n    this._defaultSigner = 'signer' in signer ? signer.signer : signer\n    return this\n  }\n\n  /**\n   * Records the given account (that can sign) against the address of the provided account for later\n   * retrieval and returns a `TransactionSignerAccount` along with the original account in an `account` property.\n   */\n\n  private signerAccount<T extends TransactionSignerAccount | Account | SigningAccount | LogicSigAccount | MultisigAccount>(\n    account: T,\n  ): Address &\n    TransactionSignerAccount & {\n      /* The underlying account that specified this address. */ account: T\n    } {\n    const signer = getAccountTransactionSigner(account)\n    const acc: TransactionSignerAccount = {\n      addr: 'addr' in account ? account.addr : account.address(),\n      signer: signer,\n    }\n    this._accounts[acc.addr.toString()] = acc\n\n    const addressWithAccount = Address.fromString(acc.addr.toString()) as Address & TransactionSignerAccount & { account: T }\n    addressWithAccount.account = account\n    addressWithAccount.addr = acc.addr\n    addressWithAccount.signer = signer\n    return addressWithAccount\n  }\n\n  /**\n   * Tracks the given account for later signing.\n   *\n   * Note: If you are generating accounts via the various methods on `AccountManager`\n   * (like `random`, `fromMnemonic`, `logicsig`, etc.) then they automatically get tracked.\n   * @param account The account to register, which can be a `TransactionSignerAccount` or\n   *  a `algosdk.Account`, `algosdk.LogicSigAccount`, `SigningAccount` or `MultisigAccount`\n   * @example\n   * ```typescript\n   * const accountManager = new AccountManager(clientManager)\n   *  .setSignerFromAccount(algosdk.generateAccount())\n   *  .setSignerFromAccount(new algosdk.LogicSigAccount(program, args))\n   *  .setSignerFromAccount(new SigningAccount(mnemonic, sender))\n   *  .setSignerFromAccount(new MultisigAccount({version: 1, threshold: 1, addrs: [\"ADDRESS1...\", \"ADDRESS2...\"]}, [account1, account2]))\n   *  .setSignerFromAccount({addr: \"SENDERADDRESS\", signer: transactionSigner})\n   * ```\n   * @returns The `AccountManager` instance for method chaining\n   */\n  public setSignerFromAccount(account: TransactionSignerAccount | Account | LogicSigAccount | SigningAccount | MultisigAccount) {\n    this.signerAccount(account)\n    return this\n  }\n\n  /**\n   * Tracks the given `algosdk.TransactionSigner` against the given sender address for later signing.\n   * @param sender The sender address to use this signer for\n   * @param signer The `algosdk.TransactionSigner` to sign transactions with for the given sender\n   * @example\n   * ```typescript\n   * const accountManager = new AccountManager(clientManager)\n   *  .setSigner(\"SENDERADDRESS\", transactionSigner)\n   * ```\n   * @returns The `AccountManager` instance for method chaining\n   */\n  public setSigner(sender: string | Address, signer: algosdk.TransactionSigner) {\n    this._accounts[address(sender).toString()] = { addr: address(sender), signer }\n    return this\n  }\n\n  /**\n   * Takes all registered signers from the given `AccountManager` and adds them to this `AccountManager`.\n   *\n   * This is useful for situations where you have multiple contexts you are building accounts in such as unit tests.\n   * @param anotherAccountManager Another account manager with signers registered\n   * @param overwriteExisting Whether or not to overwrite any signers that have the same sender address with the ones in the other account manager or not (default: true)\n   * @returns The `AccountManager` instance for method chaining\n   * @example\n   * ```typescript\n   * accountManager2.setSigners(accountManager1);\n   * ```\n   */\n  public setSigners(anotherAccountManager: AccountManager, overwriteExisting = true) {\n    this._accounts = overwriteExisting\n      ? { ...this._accounts, ...anotherAccountManager._accounts }\n      : { ...anotherAccountManager._accounts, ...this._accounts }\n    return this\n  }\n\n  /**\n   * Returns the `TransactionSigner` for the given sender address, ready to sign a transaction for that sender.\n   *\n   * If no signer has been registered for that address then the default signer is used if registered and\n   * if not then an error is thrown.\n   *\n   * @param sender The sender address\n   * @example\n   * ```typescript\n   * const signer = accountManager.getSigner(\"SENDERADDRESS\")\n   * ```\n   * @returns The `TransactionSigner` or throws an error if not found and no default signer is set\n   */\n  public getSigner(sender: string | Address): algosdk.TransactionSigner {\n    const signer = this._accounts[address(sender).toString()]?.signer ?? this._defaultSigner\n    if (!signer) throw new Error(`No signer found for address ${sender}`)\n    return signer\n  }\n\n  /**\n   * Returns the `TransactionSignerAccount` for the given sender address.\n   *\n   * If no signer has been registered for that address then an error is thrown.\n   * @param sender The sender address\n   * @example\n   * ```typescript\n   * const sender = accountManager.random()\n   * // ...\n   * // Returns the `TransactionSignerAccount` for `sender` that has previously been registered\n   * const account = accountManager.getAccount(sender)\n   * ```\n   * @returns The `TransactionSignerAccount` or throws an error if not found\n   */\n  public getAccount(sender: string | Address): TransactionSignerAccount {\n    const account = this._accounts[address(sender).toString()]\n    if (!account) throw new Error(`No signer found for address ${sender}`)\n    return account\n  }\n\n  /**\n   * Returns the given sender account's current status, balance and spendable amounts.\n   *\n   * [Response data schema details](https://dev.algorand.co/reference/rest-apis/algod/#accountinformation)\n   * @example\n   * ```typescript\n   * const address = \"XBYLS2E6YI6XXL5BWCAMOA4GTWHXWENZMX5UHXMRNWWUQ7BXCY5WC5TEPA\";\n   * const accountInfo = await accountManager.getInformation(address);\n   * ```\n   *\n   * @param sender The account / address to look up\n   * @returns The account information\n   */\n  public async getInformation(sender: string | Address): Promise<AccountInformation> {\n    const {\n      round,\n      lastHeartbeat = undefined,\n      lastProposed = undefined,\n      address,\n      ...account\n    } = await this._clientManager.algod.accountInformation(sender).do()\n\n    return {\n      ...account,\n      // None of the Number types can practically overflow 2^53\n      address: Address.fromString(address),\n      balance: AlgoAmount.MicroAlgo(Number(account.amount)),\n      amountWithoutPendingRewards: AlgoAmount.MicroAlgo(Number(account.amountWithoutPendingRewards)),\n      minBalance: AlgoAmount.MicroAlgo(Number(account.minBalance)),\n      pendingRewards: AlgoAmount.MicroAlgo(Number(account.pendingRewards)),\n      rewards: AlgoAmount.MicroAlgo(Number(account.rewards)),\n      validAsOfRound: BigInt(round),\n      totalAppsOptedIn: Number(account.totalAppsOptedIn),\n      totalAssetsOptedIn: Number(account.totalAssetsOptedIn),\n      totalCreatedApps: Number(account.totalCreatedApps),\n      totalCreatedAssets: Number(account.totalCreatedAssets),\n      appsTotalExtraPages: account.appsTotalExtraPages !== undefined ? Number(account.appsTotalExtraPages) : undefined,\n      rewardBase: account.rewardBase !== undefined ? Number(account.rewardBase) : undefined,\n      totalBoxBytes: account.totalBoxBytes !== undefined ? Number(account.totalBoxBytes) : undefined,\n      totalBoxes: account.totalBoxes !== undefined ? Number(account.totalBoxes) : undefined,\n      lastHeartbeatRound: lastHeartbeat !== undefined ? BigInt(lastHeartbeat) : undefined,\n      lastProposedRound: lastProposed !== undefined ? BigInt(lastProposed) : undefined,\n    }\n  }\n\n  /**\n   * Tracks and returns an Algorand account with secret key loaded (i.e. that can sign transactions) by taking the mnemonic secret.\n   *\n   * @example\n   * ```typescript\n   * const account = accountManager.fromMnemonic(\"mnemonic secret ...\")\n   * const rekeyedAccount = accountManager.fromMnemonic(\"mnemonic secret ...\", \"SENDERADDRESS...\")\n   * ```\n   * @param mnemonicSecret The mnemonic secret representing the private key of an account; **Note: Be careful how the mnemonic is handled**,\n   *  never commit it into source control and ideally load it from the environment (ideally via a secret storage service) rather than the file system.\n   * @param sender The optional sender address to use this signer for (aka a rekeyed account)\n   * @returns The account\n   */\n  public fromMnemonic(mnemonicSecret: string, sender?: string | Address) {\n    const account = algosdk.mnemonicToSecretKey(mnemonicSecret)\n    return this.signerAccount(new SigningAccount(account, sender))\n  }\n\n  /**\n   * Tracks and returns an Algorand account that is a rekeyed version of the given account to a new sender.\n   *\n   * @example\n   * ```typescript\n   * const account = accountManager.fromMnemonic(\"mnemonic secret ...\")\n   * const rekeyedAccount = accountManager.rekeyed(account, \"SENDERADDRESS...\")\n   * ```\n   * @param account The account to use as the signer for this new rekeyed account\n   * @param sender The sender address to use as the new sender\n   * @returns The account\n   */\n  public rekeyed(sender: string | Address, account: TransactionSignerAccount) {\n    return this.signerAccount({ addr: address(sender), signer: account.signer })\n  }\n\n  /**\n   * Tracks and returns an Algorand account with private key loaded by convention from environment variables based on the given name identifier.\n   *\n   * Note: This function expects to run in a Node.js environment.\n   *\n   * ## Convention:\n   * * **Non-LocalNet:** will load process.env['\\{NAME\\}_MNEMONIC'] as a mnemonic secret; **Note: Be careful how the mnemonic is handled**,\n   *  never commit it into source control and ideally load it via a secret storage service rather than the file system.\n   *   If process.env['\\{NAME\\}_SENDER'] is defined then it will use that for the sender address (i.e. to support rekeyed accounts)\n   * * **LocalNet:** will load the account from a KMD wallet called \\{NAME\\} and if that wallet doesn't exist it will create it and fund the account for you\n   *\n   * This allows you to write code that will work seamlessly in production and local development (LocalNet) without manual config locally (including when you reset the LocalNet).\n   *\n   * @example Default\n   *\n   * If you have a mnemonic secret loaded into `process.env.MY_ACCOUNT_MNEMONIC` then you can call the following to get that private key loaded into an account object:\n   * ```typescript\n   * const account = await accountManager.fromEnvironment('MY_ACCOUNT')\n   * ```\n   *\n   * If that code runs against LocalNet then a wallet called `MY_ACCOUNT` will automatically be created with an account that is automatically funded with 1000 (default) ALGO from the default LocalNet dispenser.\n   * If not running against LocalNet then it will use proces.env.MY_ACCOUNT_MNEMONIC as the private key and (if present) process.env.MY_ACCOUNT_SENDER as the sender address.\n   *\n   * @param name The name identifier of the account\n   * @param fundWith The optional amount to fund the account with when it gets created (when targeting LocalNet), if not specified then 1000 ALGO will be funded from the dispenser account\n   * @returns The account\n   */\n  public async fromEnvironment(name: string, fundWith?: AlgoAmount) {\n    if (!process || !process.env) {\n      throw new Error('Attempt to get account with private key from a non Node.js context; this is not supported!')\n    }\n\n    const accountMnemonic = process.env[`${name.toUpperCase()}_MNEMONIC`]\n    const sender = process.env[`${name.toUpperCase()}_SENDER`]\n\n    if (accountMnemonic) {\n      const signer = algosdk.mnemonicToSecretKey(accountMnemonic)\n      return this.signerAccount(new SigningAccount(signer, sender))\n    }\n\n    if (await this._clientManager.isLocalNet()) {\n      const account = await this._kmdAccountManager.getOrCreateWalletAccount(name, fundWith)\n      return this.signerAccount(account.account)\n    }\n\n    throw new Error(`Missing environment variable ${name.toUpperCase()}_MNEMONIC when looking for account ${name}`)\n  }\n\n  /**\n   * Tracks and returns an Algorand account with private key loaded from the given KMD wallet (identified by name).\n   *\n   * @param name The name of the wallet to retrieve an account from\n   * @param predicate An optional filter to use to find the account (otherwise it will return a random account from the wallet)\n   * @param sender The optional sender address to use this signer for (aka a rekeyed account)\n   * @example Get default funded account in a LocalNet\n   *\n   * ```typescript\n   * const defaultDispenserAccount = await accountManager.fromKmd('unencrypted-default-wallet',\n   *   a => a.status !== 'Offline' && a.amount > 1_000_000_000\n   * )\n   * ```\n   * @returns The account\n   */\n  public async fromKmd(\n    name: string,\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    predicate?: (account: Record<string, any>) => boolean,\n    sender?: string | Address,\n  ) {\n    const account = await this._kmdAccountManager.getWalletAccount(name, predicate, sender)\n    if (!account) throw new Error(`Unable to find KMD account ${name}${predicate ? ' with predicate' : ''}`)\n    return this.signerAccount(account.account)\n  }\n\n  /**\n   * Tracks and returns an account that supports partial or full multisig signing.\n   *\n   * @example\n   * ```typescript\n   * const account = accountManager.multisig({version: 1, threshold: 1, addrs: [\"ADDRESS1...\", \"ADDRESS2...\"]},\n   *  [(await accountManager.fromEnvironment('ACCOUNT1')).account])\n   * ```\n   * @param multisigParams The parameters that define the multisig account\n   * @param signingAccounts The signers that are currently present\n   * @returns A multisig account wrapper\n   */\n  public multisig(multisigParams: algosdk.MultisigMetadata, signingAccounts: (algosdk.Account | SigningAccount)[]) {\n    return this.signerAccount(new MultisigAccount(multisigParams, signingAccounts))\n  }\n\n  /**\n   * Tracks and returns an account that represents a logic signature.\n   *\n   * @example\n   * ```typescript\n   * const account = accountManager.logicsig(program, [new Uint8Array(3, ...)])\n   * ```\n   * @param program The bytes that make up the compiled logic signature\n   * @param args The (binary) arguments to pass into the logic signature\n   * @returns A logic signature account wrapper\n   */\n  public logicsig(program: Uint8Array, args?: Array<Uint8Array>) {\n    return this.signerAccount(new LogicSigAccount(program, args))\n  }\n\n  /**\n   * Tracks and returns a new, random Algorand account with secret key loaded.\n   *\n   * @example\n   * ```typescript\n   * const account = accountManager.random()\n   * ```\n   * @returns The account\n   */\n  public random() {\n    return this.signerAccount(algosdk.generateAccount())\n  }\n\n  /**\n   * Returns an account (with private key loaded) that can act as a dispenser from\n   * environment variables, or against default LocalNet if no environment variables present.\n   *\n   * Note: requires a Node.js environment to execute.\n   *\n   * If present, it will load the account mnemonic stored in process.env.DISPENSER_MNEMONIC and optionally\n   * process.env.DISPENSER_SENDER if it's a rekeyed account.\n   *\n   * @example\n   * ```typescript\n   * const account = await accountManager.dispenserFromEnvironment()\n   * ```\n   *\n   * @returns The account\n   */\n  public async dispenserFromEnvironment() {\n    if (!process || !process.env) {\n      throw new Error('Attempt to get dispenser from environment from a non Node.js context; this is not supported!')\n    }\n\n    return process.env[`${DISPENSER_ACCOUNT.toUpperCase()}_MNEMONIC`]\n      ? await this.fromEnvironment(DISPENSER_ACCOUNT)\n      : await this.localNetDispenser()\n  }\n\n  /**\n   * Returns an Algorand account with private key loaded for the default LocalNet dispenser account (that can be used to fund other accounts).\n   *\n   * @example\n   * ```typescript\n   * const account = await accountManager.localNetDispenser()\n   * ```\n   * @returns The account\n   */\n  public async localNetDispenser() {\n    const dispenser = await this._kmdAccountManager.getLocalNetDispenserAccount()\n    return this.signerAccount(dispenser.account)\n  }\n\n  /**\n   * Rekey an account to a new address.\n   *\n   * **Note:** Please be careful with this function and be sure to read the [official rekey guidance](https://dev.algorand.co/concepts/accounts/rekeying).\n   *\n   * @param account The account to rekey\n   * @param rekeyTo The account address or signing account of the account that will be used to authorise transactions for the rekeyed account going forward.\n   *  If a signing account is provided that will now be tracked as the signer for `account` in this `AccountManager`\n   * @param options Any parameters to control the transaction or execution of the transaction\n   *\n   * @example Basic example (with string addresses)\n   * ```typescript\n   * await accountManager.rekeyAccount({account: \"ACCOUNTADDRESS\", rekeyTo: \"NEWADDRESS\"})\n   * ```\n   * @example Basic example (with signer accounts)\n   * ```typescript\n   * await accountManager.rekeyAccount({account: account1, rekeyTo: newSignerAccount})\n   * ```\n   * @example Advanced example\n   * ```typescript\n   * await accountManager.rekeyAccount({\n   *   account: \"ACCOUNTADDRESS\",\n   *   rekeyTo: \"NEWADDRESS\",\n   *   lease: 'lease',\n   *   note: 'note',\n   *   firstValidRound: 1000n,\n   *   validityWindow: 10,\n   *   extraFee: (1000).microAlgo(),\n   *   staticFee: (1000).microAlgo(),\n   *   // Max fee doesn't make sense with extraFee AND staticFee\n   *   //  already specified, but here for completeness\n   *   maxFee: (3000).microAlgo(),\n   *   maxRoundsToWaitForConfirmation: 5,\n   *   suppressLog: true,\n   * })\n   * ```\n   * @returns The result of the transaction and the transaction that was sent\n   */\n  async rekeyAccount(\n    account: string | Address,\n    rekeyTo: string | Address | TransactionSignerAccount,\n    options?: Omit<CommonTransactionParams, 'sender'> & SendParams,\n  ): Promise<SendSingleTransactionResult> {\n    const result = await this._getComposer()\n      .addPayment({\n        ...options,\n        sender: address(account),\n        receiver: address(account),\n        amount: AlgoAmount.MicroAlgo(0),\n        rekeyTo: address(typeof rekeyTo === 'object' && 'addr' in rekeyTo ? rekeyTo.addr : rekeyTo),\n      })\n      .send(options)\n\n    // If the rekey is a signing account set it as the signer for this account\n    if (typeof rekeyTo === 'object' && 'addr' in rekeyTo) {\n      this.rekeyed(account, rekeyTo)\n    }\n\n    Config.getLogger(options?.suppressLog).info(`Rekeyed ${account} to ${rekeyTo} via transaction ${result.txIds.at(-1)}`)\n\n    return { ...result, transaction: result.transactions.at(-1)!, confirmation: result.confirmations.at(-1)! }\n  }\n\n  private async _getEnsureFundedAmount(sender: Address, minSpendingBalance: AlgoAmount, minFundingIncrement?: AlgoAmount) {\n    const accountInfo = await this.getInformation(sender)\n    const currentSpendingBalance = accountInfo.balance.microAlgo - accountInfo.minBalance.microAlgo\n\n    const amountFunded = calculateFundAmount(minSpendingBalance.microAlgo, currentSpendingBalance, minFundingIncrement?.microAlgo ?? 0n)\n\n    return amountFunded === null ? undefined : AlgoAmount.MicroAlgo(amountFunded)\n  }\n\n  /**\n   * Funds a given account using a dispenser account as a funding source such that\n   * the given account has a certain amount of Algo free to spend (accounting for\n   * Algo locked in minimum balance requirement).\n   *\n   * https://dev.algorand.co/concepts/smart-contracts/costs-constraints#mbr\n   *\n   * @param accountToFund The account to fund\n   * @param dispenserAccount The account to use as a dispenser funding source\n   * @param minSpendingBalance The minimum balance of Algo that the account should have available to spend (i.e. on top of minimum balance requirement)\n   * @param options Optional parameters to control the funding increment, transaction or execution of the transaction\n   * @example Example using AlgorandClient\n   * ```typescript\n   * // Basic example\n   * await accountManager.ensureFunded(\"ACCOUNTADDRESS\", \"DISPENSERADDRESS\", algokit.algo(1))\n   * // With configuration\n   * await accountManager.ensureFunded(\"ACCOUNTADDRESS\", \"DISPENSERADDRESS\", algokit.algo(1),\n   *  { minFundingIncrement: algokit.algo(2), fee: (1000).microAlgo(), suppressLog: true }\n   * )\n   * ```\n   * @returns\n   * - The result of executing the dispensing transaction and the `amountFunded` if funds were needed.\n   * - `undefined` if no funds were needed.\n   */\n  async ensureFunded(\n    accountToFund: string | Address,\n    dispenserAccount: string | Address,\n    minSpendingBalance: AlgoAmount,\n    options?: {\n      minFundingIncrement?: AlgoAmount\n    } & SendParams &\n      Omit<CommonTransactionParams, 'sender'>,\n  ): Promise<(SendSingleTransactionResult & EnsureFundedResult) | undefined> {\n    const addressToFund = address(accountToFund)\n\n    const amountFunded = await this._getEnsureFundedAmount(addressToFund, minSpendingBalance, options?.minFundingIncrement)\n    if (!amountFunded) return undefined\n\n    const result = await this._getComposer()\n      .addPayment({\n        ...options,\n        sender: address(dispenserAccount),\n        receiver: addressToFund,\n        amount: amountFunded,\n      })\n      .send(options)\n\n    return {\n      ...result,\n      transaction: result.transactions[0],\n      confirmation: result.confirmations[0],\n      transactionId: result.txIds[0],\n      amountFunded: amountFunded,\n    }\n  }\n\n  /**\n   * Funds a given account using a dispenser account retrieved from the environment,\n   * per the `dispenserFromEnvironment` method, as a funding source such that\n   * the given account has a certain amount of Algo free to spend (accounting for\n   * Algo locked in minimum balance requirement).\n   *\n   * **Note:** requires a Node.js environment to execute.\n   *\n   * The dispenser account is retrieved from the account mnemonic stored in\n   * process.env.DISPENSER_MNEMONIC and optionally process.env.DISPENSER_SENDER\n   * if it's a rekeyed account, or against default LocalNet if no environment variables present.\n   *\n   * https://dev.algorand.co/concepts/smart-contracts/costs-constraints#mbr\n   *\n   * @param accountToFund The account to fund\n   * @param minSpendingBalance The minimum balance of Algo that the account should have available to spend (i.e. on top of minimum balance requirement)\n   * @param options Optional parameters to control the funding increment, transaction or execution of the transaction\n   * @example Example using AlgorandClient\n   * ```typescript\n   * // Basic example\n   * await accountManager.ensureFundedFromEnvironment(\"ACCOUNTADDRESS\", algokit.algo(1))\n   * // With configuration\n   * await accountManager.ensureFundedFromEnvironment(\"ACCOUNTADDRESS\", algokit.algo(1),\n   *  { minFundingIncrement: algokit.algo(2), fee: (1000).microAlgo(), suppressLog: true }\n   * )\n   * ```\n   * @returns\n   * - The result of executing the dispensing transaction and the `amountFunded` if funds were needed.\n   * - `undefined` if no funds were needed.\n   */\n  async ensureFundedFromEnvironment(\n    accountToFund: string | Address,\n    minSpendingBalance: AlgoAmount,\n    options?: {\n      minFundingIncrement?: AlgoAmount\n    } & SendParams &\n      Omit<CommonTransactionParams, 'sender'>,\n  ): Promise<(SendSingleTransactionResult & EnsureFundedResult) | undefined> {\n    const addressToFund = address(accountToFund)\n    const dispenserAccount = await this.dispenserFromEnvironment()\n\n    const amountFunded = await this._getEnsureFundedAmount(addressToFund, minSpendingBalance, options?.minFundingIncrement)\n    if (!amountFunded) return undefined\n\n    const result = await this._getComposer()\n      .addPayment({\n        ...options,\n        sender: dispenserAccount,\n        receiver: addressToFund,\n        amount: amountFunded,\n      })\n      .send(options)\n\n    return {\n      ...result,\n      transaction: result.transactions[0],\n      confirmation: result.confirmations[0],\n      transactionId: result.txIds[0],\n      amountFunded: amountFunded,\n    }\n  }\n\n  /**\n   * Funds a given account using the TestNet Dispenser API as a funding source such that\n   * the account has a certain amount of Algo free to spend (accounting for Algo locked\n   * in minimum balance requirement).\n   *\n   * https://dev.algorand.co/concepts/smart-contracts/costs-constraints#mbr\n   *\n   * @param accountToFund The account to fund\n   * @param dispenserClient The TestNet dispenser funding client\n   * @param minSpendingBalance The minimum balance of Algo that the account should have available to spend (i.e. on top of minimum balance requirement)\n   * @param options Optional parameters to control the funding increment, transaction or execution of the transaction\n   * @example Example using AlgorandClient\n   * ```typescript\n   * // Basic example\n   * await accountManager.ensureFundedFromTestNetDispenserApi(\"ACCOUNTADDRESS\", algorand.client.getTestNetDispenserFromEnvironment(), algokit.algo(1))\n   * // With configuration\n   * await accountManager.ensureFundedFromTestNetDispenserApi(\"ACCOUNTADDRESS\", algorand.client.getTestNetDispenserFromEnvironment(), algokit.algo(1),\n   *  { minFundingIncrement: algokit.algo(2) }\n   * )\n   * ```\n   * @returns\n   * - The result of executing the dispensing transaction and the `amountFunded` if funds were needed.\n   * - `undefined` if no funds were needed.\n   */\n  async ensureFundedFromTestNetDispenserApi(\n    accountToFund: string | Address,\n    dispenserClient: TestNetDispenserApiClient,\n    minSpendingBalance: AlgoAmount,\n    options?: {\n      minFundingIncrement?: AlgoAmount\n    },\n  ): Promise<EnsureFundedResult | undefined> {\n    if (!(await this._clientManager.isTestNet())) {\n      throw new Error('Attempt to fund using TestNet dispenser API on non TestNet network.')\n    }\n\n    const addressToFund = address(accountToFund)\n\n    const amountFunded = await this._getEnsureFundedAmount(addressToFund, minSpendingBalance, options?.minFundingIncrement)\n    if (!amountFunded) return undefined\n\n    const result = await dispenserClient.fund(addressToFund, amountFunded.microAlgo)\n    return {\n      amountFunded: AlgoAmount.MicroAlgo(result.amount),\n      transactionId: result.txId,\n    }\n  }\n}\n"],"names":[],"mappings":"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"}