For the complete documentation index, see llms.txt. This page is also available as Markdown.
Fiat Deposit from Bank
This example shows how to obtain bank deposit information from an Anchor that supports inbound payments that are minted on Keeta. It assumes KYC has already been completed and shared with the Anchor. See the two KYC guides Add KYC Certificate and Share KYC Attributes for more details on handling KYC.
To run the example on the main network, the following changes are needed.
Change network from test to main
Use the main network Keeta USD Token - keeta_amnkge74xitii5dsobstldatv3irmyimujfjotftx7plaaaseam4bntb7wnna
1
Setup Account and Anchor Client
2
Establish Source Location and Destination
3
Identify Provider with Anchor Resolver
4
Request Deposit Information
5
Make an ACH Payment and Check Balance
There are multiple ways to check if an account has changed. Simplest is to query the account balance for a given token.
Alternatively, can poll the account history to identify changes affecting the account
Lastly, the UserClient has a change callback that can be implemented to connect via websocket and listen for changes. It also uses a periodic polling fallback in case the websocket disconnects.
#! /usr/bin/env ts-node
/*
* Description: Example of using the Keeta Anchor client to request USD bank deposit info (persistent address) for USD;
* This example assumes that KYC has already been completed and onboarding has been performed.
*/
import * as KeetaAnchor from '@keetanetwork/anchor';
import { Errors } from '@keetanetwork/anchor/services/asset-movement/common.js';
import { debugPrintableObject as DPO, promptUser } from '../helper.js';
import * as util from 'util';
const Account = KeetaAnchor.KeetaNet.lib.Account;
const DEBUG = false;
const logger = DEBUG ? { logger: console } : {};
const network = 'test';
const KEETA_USD_ASSET = Account.fromPublicKeyString('keeta_any4zllibya6fum3lsoimxmnmeo57nklxlh4c6d6xosfacarfaa3knkiprkmm');
const US_BANK_SOURCE = { type: 'bank-account', account: { type: 'us' }} as const;
async function main() {
console.log('Keeta Fiat Deposit Example: USD Bank Deposit Information');
console.log('==========================================================\n');
const seed = await promptUser('Enter your Keeta SEED with KYC completed: ');
if (!seed.trim()) {
throw(new Error('Invalid seed'));
}
const account = Account.fromSeed(seed.trim(), 0);
console.log(`Keeta Account: ${account.publicKeyString.get()}`);
console.log(`USD Token: ${KEETA_USD_ASSET.publicKeyString.get()}\n`);
await using userClient = KeetaAnchor.KeetaNet.UserClient.fromNetwork(network, account);
const assetMovementClient = new KeetaAnchor.AssetMovement.Client(userClient, {
root: userClient.networkAddress,
...logger
});
const keetaDestination = {
type: 'chain',
chain: { type: 'keeta', networkId: userClient.network }
} as const;
const assetPair = { from: 'USD' as const, to: KEETA_USD_ASSET };
const providers = await assetMovementClient.getProvidersForTransfer({
asset: assetPair,
from: US_BANK_SOURCE,
to: keetaDestination
});
if (!providers || providers.length === 0) {
throw(new Error('No asset movement providers found for USD bank deposit to Keeta'));
}
const provider = providers[0];
if (!provider) {
throw(new Error('Provider is undefined'));
}
console.log(`Using provider: ${String(provider.providerID)}\n`);
try {
const depositInfo = await provider.createPersistentForwardingAddress({
account,
asset: assetPair,
sourceLocation: US_BANK_SOURCE,
destinationLocation: keetaDestination,
destinationAddress: account.publicKeyString.get()
});
console.log('USD bank deposit information:');
console.log(util.inspect(DPO(depositInfo), { depth: 6, colors: true }));
} catch (error) {
if (Errors.KYCShareNeeded.isInstance(error)) {
console.error('KYC attributes must be shared with the provider before a USD deposit address can be issued.');
console.error('Complete KYC sharing (see kyc-client-sharekyc.ts), then run this example again.');
return(true);
}
if (Errors.UserActionNeeded.isInstance(error)) {
console.error('Provider onboarding steps are still required before a USD deposit address can be issued.');
console.error('Complete the actions below (see kyc-client-sharekyc.ts), then run this example again.');
console.error(util.inspect(DPO(error.actionsNeeded), { depth: 4, colors: true }));
return(true);
}
throw(error);
}
}
main().then(function() {
process.exit(0);
}, function(err: unknown) {
console.error(err);
process.exit(1);
});
using System.Text.Json;
using KeetaNet.Anchor;
using KeetaNet.Anchor.Crypto;
using KeetaNet.Examples.Common;
using UserClient = KeetaNet.Examples.Network.UserClient;
namespace KeetaNet.Examples.Anchor;
/// <summary>
/// Port of <c>src/anchor/asset-movement-fiat-deposit-from-bank.ts</c>.
/// Assumes KYC is complete and provider onboarding has already been performed.
/// </summary>
public sealed class AssetMovementFiatDepositFromBankExample : IKeetaExample
{
private const string Network = "test";
private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true };
public string Id => "anchor/asset-movement-fiat-deposit-from-bank";
public string Description =>
"Request USD bank deposit information (persistent address) for USD on Keeta";
public async Task<int> Run(string[] args, CancellationToken cancellationToken = default)
{
Console.WriteLine("Keeta Fiat Deposit Example: USD Bank Deposit Information");
Console.WriteLine("==========================================================");
Console.WriteLine();
using var runtime = WasmRuntime.Load();
string seed = Helper.ReadLine("Enter your Keeta SEED with KYC completed: ").Trim();
if (seed.Length == 0)
{
throw new InvalidOperationException("Invalid seed");
}
using Account userAccount = runtime.Accounts.FromSeed(seed, 0, "ecdsa_secp256k1");
Console.WriteLine($"Keeta Account: {userAccount.PublicKeyString}");
Console.WriteLine($"USD Token: {Constants.KeetaUsdAsset}");
Console.WriteLine();
UserClient userClient = UserClient.FromNetwork(Network, userAccount);
using AssetMovementClient assetMovementClient = runtime.CreateAssetMovementClient(
Constants.NodeApi,
userClient.NetworkAddress,
userAccount);
string keetaDestination = $"chain:keeta:{userClient.Network}";
AssetOrPair assetPair = AssetOrPair.Pair("USD", Constants.KeetaUsdAsset);
IReadOnlyList<AssetProvider> providers = await assetMovementClient.GetProvidersForTransfer(
new AssetProviderSearch(
Asset: assetPair,
From: Constants.BankAccountUsLocation,
To: keetaDestination),
cancellationToken);
if (providers.Count == 0)
{
throw new InvalidOperationException("No asset movement providers found for USD bank deposit to Keeta");
}
AssetProvider provider = providers[0];
Console.WriteLine($"Using provider: {provider.Id}");
Console.WriteLine();
AssetCreateAddressRequest request = new(
SourceLocation: Constants.BankAccountUsLocation,
Asset: assetPair,
DestinationLocation: keetaDestination,
DestinationAddress: userAccount.PublicKeyString);
try
{
JsonElement depositInfo = await assetMovementClient.CreatePersistentForwardingAddress(
provider,
request,
cancellationToken);
Console.WriteLine("USD bank deposit information:");
Console.WriteLine(JsonSerializer.Serialize(depositInfo, JsonOptions));
return 0;
}
catch (KeetaBlockerException refusal)
{
switch (refusal.Blocker)
{
case AssetKycShareNeededBlocker:
Console.Error.WriteLine("KYC attributes must be shared with the provider before a USD deposit address can be issued.");
Console.Error.WriteLine("Complete KYC sharing (see anchor/kyc-client-sharekyc), then run this example again.");
return 0;
case AssetUserActionNeededBlocker userActionNeeded:
Console.Error.WriteLine("Provider onboarding steps are still required before a USD deposit address can be issued.");
Console.Error.WriteLine("Complete the actions below (see anchor/kyc-client-sharekyc), then run this example again.");
Console.Error.WriteLine(JsonSerializer.Serialize(userActionNeeded.ActionsNeeded, JsonOptions));
return 0;
default:
throw;
}
}
}
}