@pushchain/core
Version:
## Overview
275 lines • 11.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.toUniversal = toUniversal;
exports.toChainAgnostic = toChainAgnostic;
exports.fromChainAgnostic = fromChainAgnostic;
exports.convertOriginToExecutor = convertOriginToExecutor;
exports.convertExecutorToOriginAccount = convertExecutorToOriginAccount;
const tslib_1 = require("tslib");
const viem_1 = require("viem");
const chain_1 = require("../../constants/chain");
const enums_1 = require("../../constants/enums");
const anchor_1 = require("@coral-xyz/anchor");
const abi_1 = require("../../constants/abi");
const push_client_1 = require("../../push-client/push-client");
const cache_1 = require("../../cache/cache");
const push_chain_1 = require("../../push-chain/push-chain");
/**
* Formats a blockchain address based on the virtual machine type of the provided chain.
*
* - For EVM chains, it converts the address to its checksummed format.
* - For non-EVM chains (e.g., Solana), the original address is returned as-is. - Can be changed in future
* @param {CHAIN} chain - A fully qualified chain identifier (e.g., CHAIN.ETHEREUM_MAINNET).
* @param {string} address - The raw address string to normalize.
* @returns {string} - A VM-compliant formatted address.
*
* @throws {Error} If an invalid EVM address is provided.
*
* @example
* // EVM address gets checksummed
* formatAddress(CHAIN.ETHEREUM_SEPOLIA, "0xabcd...") // → "0xAbCd..."
*
* @example
* // Non-EVM address is returned as-is
* formatAddress(CHAIN.SOLANA_DEVNET, "solanaAddress123") // → "solanaAddress123"
*/
function formatAddress(chain, address) {
if (chain_1.CHAIN_INFO[chain].vm === enums_1.VM.EVM) {
try {
return (0, viem_1.getAddress)(address.toLowerCase());
}
catch (_a) {
throw new Error('Invalid EVM address format');
}
}
return address;
}
/**
* Creates a `UniversalAccount` object from an address and chain options.
* Alternative to createUniversalAccount with a different parameter structure.
*
* @param {string} address - The account address.
* @param {Object} options - The configuration options.
* @param {CHAIN} options.chain - The chain the account is associated with.
* @returns {UniversalAccount} A normalized account object with chain and address.
*
* @example
* const universalAccount = toUniversal(
* '0x35B84d6848D16415177c64D64504663b998A6ab4',
* { chain: CHAIN.ETHEREUM_SEPOLIA }
* );
* // → { chain: CHAIN.ETHEREUM_SEPOLIA, address: '0x35B84d6848D16415177c64D64504663b998A6ab4' }
*/
function toUniversal(address, options) {
return {
chain: options.chain,
address: formatAddress(options.chain, address),
};
}
/**
* Converts an address and chain into a CAIP-10 style address string.
*
* Format: `namespace:chainId:address`
* Namespace is derived from the chain's VM type using VM_NAMESPACE.
*
* @param {string} address - The account address to convert.
* @param {Object} options - The configuration options.
* @param {CHAIN} options.chain - The chain the account is associated with.
* @returns {string} A CAIP-10 formatted string.
*
* @example
* Utils.account.toChainAgnostic('0xabc123...', {
* chain: CHAIN.ETHEREUM_SEPOLIA
* })
* // → 'eip155:11155111:0xabc123...'
*/
function toChainAgnostic(address, options) {
const { chain } = options;
const chainMeta = chain_1.CHAIN_INFO[chain];
if (!chainMeta) {
throw new Error(`Unrecognized chain: ${chain}`);
}
const { chainId, vm } = chainMeta;
const namespace = chain_1.VM_NAMESPACE[vm];
return `${namespace}:${chainId}:${formatAddress(chain, address)}`;
}
/**
* Converts a CAIP-10 formatted string into a UniversalAccount.
*
* @param {string} caip - A CAIP-10 address string (e.g., 'eip155:1:0xabc...').
* @returns {UniversalAccount} The resolved account.
* @throws {Error} If the CAIP string is invalid or unsupported.
*
* @example
* Utils.account.fromChainAgnostic('eip155:11155111:0xabc...')
* // → { chain: CHAIN.ETHEREUM_SEPOLIA, address: '0xabc...' }
*/
function fromChainAgnostic(caip) {
var _a, _b;
const [namespace, chainId, rawAddress] = caip.split(':');
const chain = ((_b = (_a = Object.entries(chain_1.CHAIN_INFO).find(([, info]) => info.chainId === chainId && chain_1.VM_NAMESPACE[info.vm] === namespace)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : null);
if (!chain) {
throw new Error(`Unsupported or unknown CAIP address: ${caip}`);
}
return {
chain,
address: formatAddress(chain, rawAddress),
};
}
// Global cache instance for convertOriginToExecutor
const accountCache = new cache_1.Cache();
/**
* Determines the Push Network based on the chain type (testnet vs mainnet)
*/
function getPushNetworkFromChain(chain) {
const testnetChains = [
enums_1.CHAIN.ETHEREUM_SEPOLIA,
enums_1.CHAIN.SOLANA_TESTNET,
enums_1.CHAIN.SOLANA_DEVNET,
enums_1.CHAIN.PUSH_TESTNET_DONUT,
enums_1.CHAIN.PUSH_TESTNET,
enums_1.CHAIN.PUSH_LOCALNET,
];
const mainnetChains = [
enums_1.CHAIN.ETHEREUM_MAINNET,
enums_1.CHAIN.SOLANA_MAINNET,
enums_1.CHAIN.PUSH_MAINNET,
];
const localnetChains = [enums_1.CHAIN.PUSH_LOCALNET];
if (testnetChains.includes(chain)) {
return enums_1.PUSH_NETWORK.TESTNET_DONUT;
}
else if (mainnetChains.includes(chain)) {
return enums_1.PUSH_NETWORK.MAINNET;
}
else if (localnetChains.includes(chain)) {
return enums_1.PUSH_NETWORK.LOCALNET;
}
else {
throw new Error(`Unsupported chain for Push Network mapping: ${chain}`);
}
}
function convertOriginToExecutor(account_1) {
return tslib_1.__awaiter(this, arguments, void 0, function* (account, options = { onlyCompute: true }) {
const { chain, address } = account;
const { vm, chainId } = chain_1.CHAIN_INFO[chain];
if (isPushChain(chain)) {
if (options.onlyCompute) {
return { address: account.address, deployed: false };
}
return { address: account.address };
}
// Determine Push Network from the chain
const pushNetwork = getPushNetworkFromChain(chain);
// Check cache for computed address
const cachedAddress = accountCache.get(cache_1.CacheKeys.ueaAddressOnchain(chain, address, pushNetwork, vm));
if (cachedAddress) {
if (options.onlyCompute) {
// Check cache for deployment status
const cachedDeploymentStatus = accountCache.get(cache_1.CacheKeys.deploymentStatus(cachedAddress));
if (cachedDeploymentStatus !== null) {
return {
address: cachedAddress,
deployed: cachedDeploymentStatus,
};
}
}
else {
return { address: cachedAddress };
}
}
let pushChain;
if (pushNetwork === enums_1.PUSH_NETWORK.MAINNET) {
pushChain = enums_1.CHAIN.PUSH_MAINNET;
}
else if (pushNetwork === enums_1.PUSH_NETWORK.TESTNET_DONUT ||
pushNetwork === enums_1.PUSH_NETWORK.TESTNET) {
pushChain = enums_1.CHAIN.PUSH_TESTNET_DONUT;
}
else {
pushChain = enums_1.CHAIN.PUSH_LOCALNET;
}
// Create PushClient to get factory address
const pushClient = new push_client_1.PushClient({
rpcUrls: chain_1.CHAIN_INFO[pushChain].defaultRPC,
network: pushNetwork,
});
const computedAddress = yield pushClient.readContract({
address: pushClient.pushChainInfo.factoryAddress,
abi: abi_1.FACTORY_V1,
functionName: 'computeUEA',
args: [
{
chainNamespace: chain_1.VM_NAMESPACE[vm],
chainId: chainId,
/**
* @dev - OwnerKey should be in bytes
* for eth - convert hex to bytes
* for sol - convert base64 to bytes
* for others - not defined yet
*/
owner: vm === enums_1.VM.EVM
? address
: vm === enums_1.VM.SVM
? (0, viem_1.bytesToHex)(anchor_1.utils.bytes.bs58.decode(address))
: address,
},
],
});
// Cache the computed address
accountCache.set(cache_1.CacheKeys.ueaAddressOnchain(chain, address, pushNetwork, vm), computedAddress);
const byteCode = yield pushClient.publicClient.getCode({
address: computedAddress,
});
const isDeployed = byteCode !== undefined;
// Cache the deployment status
accountCache.set(cache_1.CacheKeys.deploymentStatus(computedAddress), isDeployed);
if (options.onlyCompute) {
return { address: computedAddress, deployed: isDeployed };
}
return { address: computedAddress };
});
}
/**
* Convert Executor to Origin Account
*
* Given a UEA (executor) address on Push Chain, returns the mapped origin
* account and an existence flag.
*/
function convertExecutorToOriginAccount(ueaAddress) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const RPC_URL = chain_1.PUSH_CHAIN_INFO[enums_1.CHAIN.PUSH_TESTNET_DONUT].defaultRPC[0];
const FACTORY_ADDRESS = chain_1.PUSH_CHAIN_INFO[enums_1.CHAIN.PUSH_TESTNET_DONUT].factoryAddress;
// Create viem public client
const client = (0, viem_1.createPublicClient)({
transport: (0, viem_1.http)(RPC_URL),
});
const originResult = (yield client.readContract({
address: FACTORY_ADDRESS,
abi: abi_1.FACTORY_V1,
functionName: 'getOriginForUEA',
args: [ueaAddress],
}));
const [account, isUEA] = originResult;
if (account.chainNamespace === '' ||
account.chainId === '' ||
account.owner === '0x') {
return { account: null, exists: isUEA };
}
const universalAccount = push_chain_1.PushChain.utils.account.fromChainAgnostic(`${account.chainNamespace}:${account.chainId}:${account.owner}`);
if (isUEA) {
if (universalAccount.chain.startsWith(chain_1.VM_NAMESPACE[enums_1.VM.SVM])) {
// Convert hex-encoded owner to base58 address format
const hexBytes = (0, viem_1.hexToBytes)(account.owner);
universalAccount.address = anchor_1.utils.bytes.bs58.encode(hexBytes);
}
}
return { account: universalAccount, exists: isUEA };
});
}
function isPushChain(chain) {
return (chain === enums_1.CHAIN.PUSH_MAINNET ||
chain === enums_1.CHAIN.PUSH_TESTNET_DONUT ||
chain === enums_1.CHAIN.PUSH_LOCALNET);
}
//# sourceMappingURL=account.js.map