@ledgerhq/coin-stacks
Version:
Ledger Stacks Coin integration
236 lines • 8.84 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.fetchFungibleTokenMetadataCached = exports.fetchFungibleTokenMetadata = exports.fetchNonce = exports.fetchFullMempoolTxs = exports.fetchMempoolTransactionsPage = exports.broadcastTx = exports.fetchFullTxs = exports.fetchAllTransactions = exports.fetchTransactionsPage = exports.fetchBlockHeight = exports.fetchEstimatedFees = exports.fetchAllTokenBalances = exports.fetchTokenBalancesPage = exports.fetchBalances = exports.StacksNetwork = void 0;
const live_env_1 = require("@ledgerhq/live-env");
const network_1 = __importDefault(require("@ledgerhq/live-network/network"));
const transformers_1 = require("./transformers");
const cache_1 = require("@ledgerhq/live-network/cache");
const network_2 = require("@stacks/network");
exports.StacksNetwork = {
mainnet: new network_2.StacksMainnet({ url: (0, live_env_1.getEnv)("API_STACKS_ENDPOINT") }),
testnet: new network_2.StacksTestnet(),
};
/**
* Builds the Stacks API URL with an optional path
*/
const getStacksURL = (path) => {
const baseUrl = (0, live_env_1.getEnv)("API_STACKS_ENDPOINT");
if (!baseUrl)
throw new Error("API base URL not available");
return `${baseUrl}${path ? path : ""}`;
};
/**
* Basic GET request to the Stacks API
*/
const fetch = async (path) => {
const url = getStacksURL(path);
// We force data to this way as network func is not using the correct param type. Changing that func will generate errors in other implementations
const opts = {
method: "GET",
url,
};
const rawResponse = await (0, network_1.default)(opts);
// We force data to this way as network func is not using the correct param type. Changing that func will generate errors in other implementations
const { data } = rawResponse;
return data;
};
/**
* Basic POST request with JSON data to the Stacks API
*/
const send = async (path, data) => {
const url = getStacksURL(path);
const opts = {
method: "POST",
url,
data: JSON.stringify(data),
headers: { "Content-Type": "application/json" },
};
const rawResponse = await (0, network_1.default)(opts);
// We force data to this way as network func is not using generics. Changing that func will generate errors in other implementations
const { data: responseData } = rawResponse;
return responseData;
};
/**
* Basic POST request with raw binary data to the Stacks API
*/
const sendRaw = async (path, data) => {
const url = getStacksURL(path);
const opts = {
method: "POST",
url,
data,
headers: { "Content-Type": "application/octet-stream" },
};
const rawResponse = await (0, network_1.default)(opts);
// We force data to this way as network func is not using generics. Changing that func will generate errors in other implementations
const { data: responseData } = rawResponse;
return responseData;
};
/**
* Fetches STX balance for an address
*/
const fetchBalances = async (addr) => {
const data = await fetch(`/extended/v1/address/${addr}/stx`);
return data;
};
exports.fetchBalances = fetchBalances;
/**
* Fetches a page of token balances for an address
*/
const fetchTokenBalancesPage = async (addr, offset = 0, limit = 50) => {
try {
const response = await fetch(`/extended/v2/addresses/${addr}/balances/ft?offset=${offset}&limit=${limit}`);
return response;
}
catch {
return { limit, offset, total: 0, results: [] };
}
};
exports.fetchTokenBalancesPage = fetchTokenBalancesPage;
/**
* Fetches all token balances for an address by paginating through results
*/
const fetchAllTokenBalances = async (addr) => {
const limit = 50;
let offset = 0;
let total = 0;
const tokenBalanceMap = {};
do {
const response = await (0, exports.fetchTokenBalancesPage)(addr, offset, limit);
// Map token balances to a more convenient format
for (const item of response.results) {
tokenBalanceMap[item.token.toLowerCase()] = item.balance;
}
offset += limit;
total = response.total;
} while (offset < total);
return tokenBalanceMap;
};
exports.fetchAllTokenBalances = fetchAllTokenBalances;
/**
* Fetches estimated fees for a transfer
*/
const fetchEstimatedFees = async (request) => {
// Cast to Record<string, unknown> to satisfy type constraints
const feeRate = await send(`/v2/fees/transfer`, request);
return feeRate;
};
exports.fetchEstimatedFees = fetchEstimatedFees;
/**
* Fetches current blockchain status, including block height
*/
const fetchBlockHeight = async () => {
const data = await fetch("/extended");
return data;
};
exports.fetchBlockHeight = fetchBlockHeight;
/**
* Fetches a page of transactions for an address
*/
const fetchTransactionsPage = async (addr, offset = 0, limit = 50) => {
try {
const response = await fetch(`/extended/v2/addresses/${addr}/transactions?offset=${offset}&limit=${limit}`);
return response;
}
catch {
return { limit, offset, total: 0, results: [] };
}
};
exports.fetchTransactionsPage = fetchTransactionsPage;
/**
* Fetches all transactions for an address
*/
const fetchAllTransactions = async (addr) => {
let qty;
let offset = 0;
const limit = 50;
const allTransactions = [];
// Fetch all transactions in pages
do {
const { results, total } = await (0, exports.fetchTransactionsPage)(addr, offset, limit);
allTransactions.push(...results);
offset += limit;
qty = total;
} while (offset < qty);
return allTransactions;
};
exports.fetchAllTransactions = fetchAllTransactions;
/**
* Fetches all transactions for an address and organizes them by type
*/
const fetchFullTxs = async (addr) => {
// 1. Fetch all transactions
const allTransactions = await (0, exports.fetchAllTransactions)(addr);
// 2. Extract regular token transfers
const tokenTransfers = (0, transformers_1.extractTokenTransferTransactions)(allTransactions);
// 3. Extract and group contract calls
const contractTransactions = await (0, transformers_1.extractContractTransactions)(allTransactions);
// 4. Add send-many transactions to token transfers
const sendManyTransactions = (0, transformers_1.extractSendManyTransactions)(allTransactions);
tokenTransfers.push(...sendManyTransactions);
return [tokenTransfers, contractTransactions];
};
exports.fetchFullTxs = fetchFullTxs;
/**
* Broadcasts a signed transaction to the Stacks network
*/
const broadcastTx = async (message) => {
let response = await sendRaw(`/v2/transactions`, message);
if (response !== "")
response = `0x${response}`;
return response;
};
exports.broadcastTx = broadcastTx;
/**
* Fetches a page of mempool transactions for an address
*/
const fetchMempoolTransactionsPage = async (addr, offset = 0, limit = 50) => {
const response = await fetch(`/extended/v1/tx/mempool?sender_address=${addr}&offset=${offset}&limit=${limit}`);
return response;
};
exports.fetchMempoolTransactionsPage = fetchMempoolTransactionsPage;
/**
* Fetches all mempool transactions for an address
*/
const fetchFullMempoolTxs = async (addr) => {
let qty;
let offset = 0;
const limit = 50;
let txs = [];
do {
const { results, total } = await (0, exports.fetchMempoolTransactionsPage)(addr, offset, limit);
txs = txs.concat(results);
offset += limit;
qty = total;
} while (offset < qty);
return txs;
};
exports.fetchFullMempoolTxs = fetchFullMempoolTxs;
/**
* Fetches the nonce for an address
*/
const fetchNonce = async (addr) => {
const response = await fetch(`/extended/v1/address/${addr}/nonces`);
return response;
};
exports.fetchNonce = fetchNonce;
/**
* Fetches metadata for a fungible token by contract address
* This can be used to extract the asset_identifier from a contract_id
* @param contractAddress - The contract address in format: ADDRESS.CONTRACT_NAME
* @returns The fungible token metadata including asset_identifier
*/
const fetchFungibleTokenMetadata = async (contractAddress) => {
const url = `/metadata/v1/ft?address=${contractAddress}`;
const response = await fetch(url);
return response;
};
exports.fetchFungibleTokenMetadata = fetchFungibleTokenMetadata;
/**
* Fetches metadata for a fungible token by contract address with caching
*/
exports.fetchFungibleTokenMetadataCached = (0, cache_1.makeLRUCache)(exports.fetchFungibleTokenMetadata, args => args, (0, cache_1.minutes)(60));
//# sourceMappingURL=api.js.map