@jagad/icsi
Version:
Internet Computer Subaccount Indexer Library - TypeScript SDK for ICP multi-token subaccount management, transaction tracking, and automated sweeping with webhook support
243 lines (242 loc) • 12.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.refund = refund;
exports.setUserVaultInterval = setUserVaultInterval;
exports.sweep = sweep;
exports.sweepByTokenType = sweepByTokenType;
exports.addSubaccount = addSubaccount;
exports.addSubaccountForToken = addSubaccountForToken;
exports.clearTransactions = clearTransactions;
exports.setWebhookUrl = setWebhookUrl;
exports.registerToken = registerToken;
exports.sweepSubaccountId = sweepSubaccountId;
exports.convertToIcrcAccount = convertToIcrcAccount;
exports.validateIcrcAccount = validateIcrcAccount;
exports.singleSweep = singleSweep;
exports.setSweepFailed = setSweepFailed;
const agent_1 = require("@dfinity/agent");
const utils_1 = require("./utils");
const userVault_did_1 = require("./userVault.did");
/**
* Creates an actor for interacting with a user vault canister.
* @param {HttpAgent} agent - The HTTP agent used for the call.
* @param {string} userVaultCanisterId - The canister ID of the user vault.
* @returns {_SERVICE} - The actor instance.
*/
function createUserVaultActor(agent, userVaultCanisterId) {
(0, utils_1.isNotEmptyOrError)(userVaultCanisterId, 'User Vault Canister ID is undefined.');
return agent_1.Actor.createActor(userVault_did_1.idlFactory, {
agent,
canisterId: userVaultCanisterId,
});
}
/**
* Calls the refund function on a canister with a specific amount.
* @param {HttpAgent} agent - The HTTP agent used for the call.
* @param {string} userVaultCanisterId - The canister ID of the user vault.
* @param {bigint} amount - The amount to refund.
* @returns {Promise<string>} - The result of the refund operation.
*/
async function refund(agent, userVaultCanisterId, amount) {
const actor = createUserVaultActor(agent, userVaultCanisterId);
return await actor.refund(amount);
}
/**
* Calls the set_interval function on a canister with a specific interval.
* @param {HttpAgent} agent - The HTTP agent used for the call.
* @param {string} userVaultCanisterId - The canister ID of the user vault.
* @param {bigint} interval - The interval to set.
* @returns {Promise<bigint>} - The set interval value.
*/
async function setUserVaultInterval(agent, userVaultCanisterId, interval) {
const actor = createUserVaultActor(agent, userVaultCanisterId);
return await actor.set_interval(interval);
}
/**
* Calls the sweep function on a canister.
* @param {HttpAgent} agent - The HTTP agent used for the call.
* @param {string} userVaultCanisterId - The canister ID of the user vault.
* @returns {Promise<string[]>} - The result of the sweep operation.
*/
async function sweep(agent, userVaultCanisterId) {
const actor = createUserVaultActor(agent, userVaultCanisterId);
return await actor.sweep();
}
/**
* Sweeps all subaccounts for a specific token type.
* @param {HttpAgent} agent - The HTTP agent used for the call.
* @param {string} userVaultCanisterId - The canister ID of the user vault.
* @param {TokenType} tokenType - The token type to sweep (ICP, CKUSDC, CKUSDT, or CKBTC).
* @returns {Promise<string[]>} - The result of the sweep operation.
*/
async function sweepByTokenType(agent, userVaultCanisterId, tokenType) {
const actor = createUserVaultActor(agent, userVaultCanisterId);
return await actor.sweep_by_token_type(tokenType);
}
/**
* Calls the add_subaccount function on a canister to add a generic subaccount for ICP.
* @param {HttpAgent} agent - The HTTP agent used for the call.
* @param {string} userVaultCanisterId - The canister ID of the user vault.
* @returns {Promise<string>} - The result of the add_subaccount operation.
*/
async function addSubaccount(agent, userVaultCanisterId) {
const actor = createUserVaultActor(agent, userVaultCanisterId);
return await actor.add_subaccount([{ ICP: null }]);
}
/**
* Adds a new subaccount for a specific token type (ICP, CKUSDC, CKUSDT, or CKBTC).
* @param {HttpAgent} agent - The HTTP agent used for the call.
* @param {string} userVaultCanisterId - The canister ID of the user vault.
* @param {TokenType} tokenType - The token type to create a subaccount for.
* @param {Object} tokenCanisterIds - The canister IDs for the different token types.
* @param {string} [tokenCanisterIds.ckusdcCanisterId="xevnm-gaaaa-aaaar-qafnq-cai"] - The canister ID for CKUSDC token.
* @param {string} [tokenCanisterIds.ckusdtCanisterId="vgmay-piaaa-aaaar-qafoq-cai"] - The canister ID for CKUSDT token.
* @param {string} [tokenCanisterIds.ckbtcCanisterId="mxzaz-hqaaa-aaaar-qaada-cai"] - The canister ID for CKBTC token.
* @param {string} [tokenCanisterIds.icpLedgerCanisterId="ryjl3-tyaaa-aaaaa-aaaba-cai"] - The canister ID for ICP ledger.
* @returns {Promise<AddAccountResult>} - The result of the add_subaccount operation.
*/
async function addSubaccountForToken(agent, userVaultCanisterId, tokenType, tokenCanisterIds = {}) {
const actor = createUserVaultActor(agent, userVaultCanisterId);
// Check if the token is already registered
const registeredTokens = await actor.get_registered_tokens();
if ('Err' in registeredTokens) {
throw new Error(`Failed to get registered tokens: ${registeredTokens.Err}`);
}
// Get the canister ID for the token type
let canisterId;
switch (true) {
case 'CKUSDC' in tokenType:
canisterId =
tokenCanisterIds.ckusdcCanisterId || 'xevnm-gaaaa-aaaar-qafnq-cai';
break;
case 'CKUSDT' in tokenType:
canisterId =
tokenCanisterIds.ckusdtCanisterId || 'vgmay-piaaa-aaaar-qafoq-cai';
break;
case 'CKBTC' in tokenType:
canisterId =
tokenCanisterIds.ckbtcCanisterId || 'mxzaz-hqaaa-aaaar-qaada-cai';
break;
case 'ICP' in tokenType:
canisterId =
tokenCanisterIds.icpLedgerCanisterId || 'ryjl3-tyaaa-aaaaa-aaaba-cai';
break;
default:
throw new Error(`Unsupported token type: ${JSON.stringify(tokenType)}`);
}
// Check if the token type is already registered
const isTokenRegistered = registeredTokens.Ok.some(([regTokenType, _]) => ('CKUSDC' in tokenType && 'CKUSDC' in regTokenType) ||
('CKUSDT' in tokenType && 'CKUSDT' in regTokenType) ||
('CKBTC' in tokenType && 'CKBTC' in regTokenType) ||
('ICP' in tokenType && 'ICP' in regTokenType));
// Register the token if not already registered
if (!isTokenRegistered) {
const registerResult = await actor.register_token(tokenType, canisterId);
if ('Err' in registerResult) {
throw new Error(`Failed to register token: ${registerResult.Err.message}`);
}
}
// Add a subaccount for the token type
return await actor.add_subaccount([tokenType]);
}
/**
* Calls the clear_transactions function on a canister.
* @param {HttpAgent} agent - The HTTP agent used for the call.
* @param {string} userVaultCanisterId - The canister ID of the user vault.
* @param {bigint} [index] - The optional index to start clearing from.
* @param {object} [timestamp] - The optional timestamp to clear up to.
* @param {bigint} [timestamp.timestamp_nanos] - The timestamp in nanoseconds.
* @returns {Promise<any[]>} - The result of the clear transactions operation.
*/
async function clearTransactions(agent, userVaultCanisterId, index, timestamp) {
const actor = createUserVaultActor(agent, userVaultCanisterId);
return await actor.clear_transactions(index ? [index] : [], timestamp ? [timestamp] : []);
}
/**
* Sets a new webhook URL for the user's vault.
* @param {HttpAgent} agent - The HTTP agent used for the call.
* @param {string} userVaultCanisterId - The canister ID of the user vault.
* @param {string} url - The new webhook URL to be set.
* @returns {Promise<void>} - A promise that resolves when the webhook URL is successfully set.
* @throws {Error} - Throws an error if the User Vault Canister ID is undefined.
*/
async function setWebhookUrl(agent, userVaultCanisterId, url) {
const actor = createUserVaultActor(agent, userVaultCanisterId);
return await actor.set_webhook_url(url);
}
/**
* Registers a new token type with the user vault canister.
* @param {HttpAgent} agent - The HTTP agent used for the call.
* @param {string} userVaultCanisterId - The canister ID of the user vault.
* @param {TokenType} tokenType - The token type to register (ICP, CKUSDC, CKUSDT, or CKBTC).
* @param {string} canisterId - The canister ID for the token ledger.
* @returns {Promise<any>} - A promise that resolves with the result of the register operation.
*/
async function registerToken(agent, userVaultCanisterId, tokenType, canisterId) {
const actor = createUserVaultActor(agent, userVaultCanisterId);
return await actor.register_token(tokenType, canisterId);
}
/**
* Sweeps a specific amount from a given subaccount for a specific token type.
* @param {HttpAgent} agent - The HTTP agent used for the call.
* @param {string} userVaultCanisterId - The canister ID of the user vault.
* @param {string} subaccountId - The ID of the subaccount to sweep from.
* @param {number} amount - The amount to sweep.
* @param {TokenType} [tokenType] - The token type to sweep (ICP, CKUSDC, CKUSDT, or CKBTC). Defaults to ICP if not provided.
* @returns {Promise<any>} - A promise that resolves with the result of the sweep operation.
* @throws {Error} - Throws an error if the User Vault Canister ID is undefined.
*/
async function sweepSubaccountId(agent, userVaultCanisterId, subaccountId, amount, tokenType) {
const actor = createUserVaultActor(agent, userVaultCanisterId);
// Ensure amount is explicitly a float by using parseFloat
const floatAmount = parseFloat(amount.toString());
return await actor.sweep_subaccount(subaccountId, floatAmount, tokenType ? [tokenType] : []);
}
/**
* Converts a subaccount ID to an ICRC account.
* @param {HttpAgent} agent - The HTTP agent used for the call.
* @param {string} userVaultCanisterId - The canister ID of the user vault.
* @param {string} subaccountId - The ID of the subaccount to convert.
* @returns {Promise<AddAccountResult>} - A promise that resolves with the result of the conversion.
*/
async function convertToIcrcAccount(agent, userVaultCanisterId, subaccountId) {
const actor = createUserVaultActor(agent, userVaultCanisterId);
return await actor.convert_to_icrc_account(subaccountId);
}
/**
* Validates if a string is a valid ICRC account.
* @param {HttpAgent} agent - The HTTP agent used for the call.
* @param {string} userVaultCanisterId - The canister ID of the user vault.
* @param {string} account - The account string to validate.
* @returns {Promise<boolean>} - A promise that resolves with the validation result.
*/
async function validateIcrcAccount(agent, userVaultCanisterId, account) {
const actor = createUserVaultActor(agent, userVaultCanisterId);
const result = await actor.validate_icrc_account(account);
if ('Err' in result) {
throw new Error(`Failed to validate ICRC account: ${result.Err.message}`);
}
return result.Ok;
}
/**
* Performs a single sweep for a specific transaction.
* @param {HttpAgent} agent - The HTTP agent used for the call.
* @param {string} userVaultCanisterId - The canister ID of the user vault.
* @param {string} txHash - The transaction hash to sweep.
* @returns {Promise<string[]>} - A promise that resolves with the result of the sweep operation.
*/
async function singleSweep(agent, userVaultCanisterId, txHash) {
const actor = createUserVaultActor(agent, userVaultCanisterId);
return await actor.single_sweep(txHash);
}
/**
* Sets a transaction's sweep status to failed.
* @param {HttpAgent} agent - The HTTP agent used for the call.
* @param {string} userVaultCanisterId - The canister ID of the user vault.
* @param {string} txHash - The transaction hash to mark as failed.
* @returns {Promise<string[]>} - A promise that resolves with the result of the operation.
*/
async function setSweepFailed(agent, userVaultCanisterId, txHash) {
const actor = createUserVaultActor(agent, userVaultCanisterId);
return await actor.set_sweep_failed(txHash);
}