UNPKG

@j0nnyboi/amman

Version:

A modern mandatory toolbelt to help test solana SDK libraries and apps on a locally running validator.

237 lines 9.56 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AccountProvider = exports.DEFAULT_MINT_DECIMALS = void 0; const amman_client_1 = require("@j0nnyboi/amman-client"); const safe_token_1 = require("@safecoin/safe-token"); const web3_js_1 = require("@safecoin/web3.js"); const bn_js_1 = __importDefault(require("bn.js")); const numeral_1 = __importDefault(require("numeral")); const utils_1 = require("../utils"); const types_1 = require("./types"); const AMMAN_TRACE_UNRESOLVED_ACCOUNTS = process.env.AMMAN_TRACE_UNRESOLVED_ACCOUNTS != null; exports.DEFAULT_MINT_DECIMALS = 9; function hasKnownByteSize(x) { return typeof x.byteSize === 'number'; } function isAmmanAccountProvider(x) { const provider = x; return (typeof provider.fromAccountInfo === 'function' && (hasKnownByteSize(provider) || typeof provider.byteSize === 'function')); } /** * @private */ class AccountProvider { constructor(providers, renderers) { this.renderers = renderers; /** * providers by size * size: 0 is used for providers of accounts that don't have a fixed size */ this.byByteSize = new Map(); this.nonfixedProviders = []; this.connection = new web3_js_1.Connection(amman_client_1.LOCALHOST, 'confirmed'); this._mapProviders(providers); } static fromRecord(record, renderers) { const providers = Object.values(record).filter(isAmmanAccountProvider); return new AccountProvider(providers, renderers); } _mapProviders(providers) { for (const provider of providers) { const size = hasKnownByteSize(provider) ? provider.byteSize : 0; if (size === 0) { this.nonfixedProviders.push(provider); } else { const providersForSize = this.byByteSize.get(size); if (providersForSize == null) { this.byByteSize.set(size, [provider]); } else { providersForSize.push(provider); } } } const providersWithRender = providers.filter((x) => this.renderers.has(x)); (0, utils_1.logDebug)('Registered %d providers, %d of which have a renderer', providers.length, providersWithRender.length); (0, utils_1.logTrace)({ providersBySize: this.byByteSize }); (0, utils_1.logTrace)({ providersUnknownSize: this.nonfixedProviders }); } async tryResolveAccount(publicKey, accountInfo) { var _a; accountInfo !== null && accountInfo !== void 0 ? accountInfo : (accountInfo = (_a = (await this.connection.getAccountInfo(publicKey))) !== null && _a !== void 0 ? _a : undefined); return accountInfo != null ? this._getProviderAndResolveAccount(accountInfo, publicKey) : undefined; } async syncAccountInformation(publicKey) { (0, utils_1.logTrace)(`Resolving account ${publicKey.toBase58()}`); let accountInfo; try { accountInfo = await this.connection.getAccountInfo(publicKey, 'confirmed'); } catch (err) { (0, utils_1.logError)(err); return; } if (accountInfo == null) { (0, utils_1.logTrace)('Unable to find account info for', publicKey.toBase58()); return; } return this._getProviderAndResolveAccount(accountInfo, publicKey); } async _getProviderAndResolveAccount(accountInfo, publicKey) { var _a; if (accountInfo.lamports === 0 || accountInfo.executable || accountInfo.data.byteLength === 0) { return; } let res = this._resolveFromProviderMatching(accountInfo, publicKey); if (res != null) { (0, utils_1.logTrace)(res); return { ...res, data: accountInfo.data }; } // No matching provider found, let's try the ones for non-fixed accounts or builtins from the token program res = (_a = this._tryResolveAccountFromProviders(this.nonfixedProviders, accountInfo)) !== null && _a !== void 0 ? _a : (await this._tryResolveAccountFromBuiltins(publicKey)); return { account: res === null || res === void 0 ? void 0 : res.account, rendered: res === null || res === void 0 ? void 0 : res.rendered, data: accountInfo.data, }; } _resolveFromProviderMatching(accountInfo, publicKey) { const providers = this.byByteSize.get(accountInfo.data.byteLength); if (providers == null) { (0, utils_1.logTrace)('Unable to find a provider by byteSize for %s', publicKey.toBase58()); (0, utils_1.logTrace)({ size: accountInfo.data.byteLength, allProvidersByByteSize: this.byByteSize, }); return; } (0, utils_1.logTrace)('Found providers for %s, %O', publicKey.toBase58(), providers); return this._tryResolveAccountFromProviders(providers, accountInfo); } _tryResolveAccountFromProviders(providers, accountInfo) { for (const provider of providers) { try { return this._resolveAccount(provider, accountInfo); } catch (err) { if (AMMAN_TRACE_UNRESOLVED_ACCOUNTS) { (0, utils_1.logTrace)(err); } } } } async _tryResolveAccountFromBuiltins(address) { for (const provider of [safe_token_1.getMint, safe_token_1.getAccount]) { try { const account = await provider(this.connection, address, 'singleGossip'); if (account != null) { const ammanAccount = await this._toAmmanAccount(account); return { account: ammanAccount, rendered: undefined, }; } } catch (err) { (0, utils_1.logTrace)(err); } } } _resolveAccount(provider, accountInfo) { const [account] = provider.fromAccountInfo(accountInfo); const render = this.renderers.get(provider); const rendered = render != null ? render(account) : undefined; return { account, rendered }; } // ----------------- // Helpers // ----------------- async _toAmmanAccount(account) { const acc = {}; const amountDivisor = (0, types_1.isAccount)(account) ? (await this._getMintDecimals(account.mint)).divisor : (0, types_1.isMint)(account) ? Math.pow(10, account.decimals) : 1; for (let [key, value] of Object.entries(account)) { if (value == null) { acc[key] = value; } else if ((0, amman_client_1.isKeyLike)(value)) { const publicKeyStr = (0, amman_client_1.publicKeyString)(value); const label = await this._tryResolveAddressRemote(publicKeyStr); acc[key] = label == null ? publicKeyStr : `${label} (${publicKeyStr})`; } else if (typeof value === 'bigint') { const formatted = (0, numeral_1.default)(value).format('0,0'); // Mint specific adjustments if (key === 'amount' || key === 'supply') { const balance = value / BigInt(amountDivisor); acc[key] = formatted + ` (balance: ${balance.toString()})`; } else { acc[key] = formatted; } } else if (typeof value === 'number') { acc[key] = (0, numeral_1.default)(value).format('0,0'); } else if (bn_js_1.default.isBN(value) || (typeof value === 'object' && 'negative' in value && 'words' in value && 'red' in value)) { acc[key] = new bn_js_1.default(value).toNumber(); } else if (typeof value.pretty === 'function') { acc[key] = value.pretty(); } else if (typeof value === 'object') { acc[key] = JSON.stringify(value); } else { acc[key] = value; } } return { pretty() { return acc; }, }; } async _getMintDecimals(publicKey) { let decimals; try { const mint = await (0, safe_token_1.getMint)(this.connection, publicKey, 'singleGossip'); decimals = mint.decimals; } catch (err) { decimals = exports.DEFAULT_MINT_DECIMALS; } const divisor = Math.pow(10, decimals); return { decimals, divisor }; } async _tryResolveAddressRemote(publicKeyStr) { try { const instance = amman_client_1.Amman.existingInstance; if (instance == null) return; return await instance.addr.resolveRemoteAddress(publicKeyStr); } catch (err) { (0, utils_1.logError)(err); } } } exports.AccountProvider = AccountProvider; //# sourceMappingURL=providers.js.map