The @portal-hq/core package is the main entry point for integrating Portal’s MPC wallet infrastructure into your React Native application. It includes the Portal class, React Context utilities (PortalContextProvider, usePortal), and exports for types, enums, and error handling.
Installation
npm install @portal-hq/core
# or
yarn add @portal-hq/core
The Portal Class
The Portal class is the primary interface for interacting with Portal’s MPC wallet infrastructure.
Properties
| Property | Type | Description |
|---|
api | IPortalApi | Portal API client for REST API interactions |
apiKey | string | Your Portal Client API Key |
backup | BackupOptions | Configured backup storage adapters |
chainId | number | Deprecated. Default chain ID (default: 11155111) |
featureFlags | FeatureFlags | Feature flag configuration |
gatewayConfig | GatewayLike | Gateway/RPC configuration. Defaults to Portal’s managed gateway for 10 built-in chains when omitted |
mpc | PortalMpc | MPC operations client |
provider | IPortalProvider | EIP-1193 compliant provider |
trading | Trading | Trading module for Li.Fi and 0x integrations |
yield | Yield | Yield module for Yield.xyz integration |
ramps | Ramps | Fiat on/off-ramp integrations: Noah (portal.ramps.noah) and Meld (portal.ramps.meld) |
Getters
| Getter | Type | Description |
|---|
address | Promise<string | undefined> | The primary wallet address (EIP-155) |
addresses | Promise<AddressesByNamespace | undefined> | All wallet addresses by namespace |
autoApprove | boolean | Whether auto-approve is enabled |
Constructor
import { Portal, BackupMethods } from '@portal-hq/core'
import Keychain from '@portal-hq/keychain'
import GDriveStorage from '@portal-hq/gdrive-storage'
import ICloudStorage from '@portal-hq/icloud-storage'
const portal = new Portal({
// Required
apiKey: 'YOUR_PORTAL_CLIENT_API_KEY',
backup: {
[BackupMethods.GoogleDrive]: new GDriveStorage(),
[BackupMethods.iCloud]: new ICloudStorage(),
},
// gatewayConfig is optional — Portal's RPC gateway is used automatically for 10 built-in chains.
// Supply a value only if you need additional chains or a custom RPC provider.
// gatewayConfig: { 'eip155:1': 'https://mainnet.infura.io/v3/YOUR_KEY' },
// Optional
isSimulator: false,
autoApprove: false,
keychain: new Keychain(),
apiHost: 'api.portalhq.io',
mpcHost: 'mpc.portalhq.io',
featureFlags: {},
})
PortalOptions
| Property | Type | Required | Default | Description |
|---|
apiKey | string | Yes | - | Portal Client API Key |
backup | BackupOptions | Yes | - | Backup storage adapters keyed by BackupMethods |
gatewayConfig | GatewayLike | No | Portal RPC gateway for 10 built-in chains | RPC URL string or chain-specific config object. When omitted or empty, defaults to Portal’s managed gateway. See Gateway configuration |
chainId | number | No | 11155111 | Deprecated. Default chain ID for EVM chains |
isSimulator | boolean | No | false | Running in simulator/emulator |
autoApprove | boolean | No | false | Auto-approve signing requests |
keychain | KeychainAdapter | No | new Keychain() | Keychain storage adapter |
apiHost | string | No | 'api.portalhq.io' | Portal API host |
mpcHost | string | No | 'mpc.portalhq.io' | MPC server host |
enclaveMPCHost | string | No | 'mpc-client.portalhq.io' | Enclave MPC host |
webSocketHost | string | No | 'connect.portalhq.io' | WebSocket host for Portal Connect |
version | string | No | 'v6' | MPC version (only 'v6' is supported) |
featureFlags | FeatureFlags | No | {} | Feature flags |
logLevel | LogLevel | No | 'none' | Logging level: 'none', 'error', 'warn', 'info', or 'debug'. See Logging Configuration |
logger | Logger | No | - | Custom logger implementation. See Logging Configuration |
Wallet Management Methods
createWallet
Creates a new MPC wallet with both SECP256K1 (EVM) and ED25519 (Solana) key pairs.
createWallet(progress?: ProgressCallback): Promise<AddressesByNamespace>
Parameters:
| Parameter | Type | Required | Description |
|---|
progress | ProgressCallback | No | Callback for progress updates |
Example:
const addresses = await portal.createWallet((status) => {
console.log('Status:', status.status, 'Done:', status.done)
})
console.log('EVM Address:', addresses.eip155)
console.log('Solana Address:', addresses.solana)
backupWallet
Creates encrypted backup shares for the wallet.
backupWallet(
method: BackupMethods,
progress?: ProgressCallback,
backupConfig?: BackupConfigs
): Promise<string>
Parameters:
| Parameter | Type | Required | Description |
|---|
method | BackupMethods | Yes | Backup storage method |
progress | ProgressCallback | No | Progress callback |
backupConfig | BackupConfigs | No | Additional config (e.g., password) |
Example:
// Google Drive backup
const cipherText = await portal.backupWallet(BackupMethods.GoogleDrive)
// Password backup
const cipherText = await portal.backupWallet(
BackupMethods.Password,
undefined,
{ passwordStorage: { password: 'user-password' } }
)
recoverWallet
Recovers a wallet from backup shares.
recoverWallet(
cipherText?: string,
method: BackupMethods,
progress?: ProgressCallback,
backupConfig?: BackupConfigs
): Promise<AddressesByNamespace>
Parameters:
| Parameter | Type | Required | Description |
|---|
cipherText | string | No | Encrypted backup string. Leave empty (”) or omit for cloud backups (Google Drive, iCloud). Required for local/password backups. |
method | BackupMethods | Yes | Backup method used |
progress | ProgressCallback | No | Progress callback |
backupConfig | BackupConfigs | No | Additional config |
Example:
const addresses = await portal.recoverWallet(
'',
BackupMethods.GoogleDrive,
(status) => console.log(status.status)
)
provisionWallet
Alias for recoverWallet. Provisions a wallet on a new device.
provisionWallet(
cipherText: string,
method: BackupMethods,
progress?: ProgressCallback,
backupConfig?: BackupConfigs
): Promise<AddressesByNamespace>
Wallet State Methods
doesWalletExist
Checks if a wallet exists on the Portal backend.
doesWalletExist(chainId?: string): Promise<boolean>
Example:
const exists = await portal.doesWalletExist()
const evmExists = await portal.doesWalletExist('eip155:1')
const solanaExists = await portal.doesWalletExist('solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp')
isWalletOnDevice
Checks if wallet signing shares exist on the current device.
isWalletOnDevice(chainId?: string): Promise<boolean>
Example:
const onDevice = await portal.isWalletOnDevice()
isWalletBackedUp
Checks if the wallet has a completed backup.
isWalletBackedUp(chainId?: string): Promise<boolean>
Example:
const backedUp = await portal.isWalletBackedUp()
isWalletRecoverable
Checks if the wallet can be recovered (has at least one backup method).
isWalletRecoverable(chainId?: string): Promise<boolean>
Example:
const recoverable = await portal.isWalletRecoverable()
availableRecoveryMethods
Returns the list of backup methods available for recovery.
availableRecoveryMethods(chainId?: string): Promise<BackupMethods[]>
Example:
const methods = await portal.availableRecoveryMethods()
// ['gdrive', 'icloud']
getAssets
Fetches the wallet assets for a given chain, including native balance, ERC20 token balances, and NFTs (if available).
Note: The nfts field will only be included if the request is made with the includeNfts=true query parameter. Otherwise, it may be undefined or omitted, even on chains that support NFTs.
getAssets(chainId: string): Promise<AssetsResponse>
Parameters:
| Parameter | Type | Required | Description |
|---|
chainId | string | Yes | CAIP-2 chain identifier (e.g., 'eip155:1') |
Returns:
interface AssetsResponse {
nativeBalance?: NativeBalance
tokenBalances?: TokenBalance[]
nfts?: Nft[]
}
Note: The nfts field may be undefined depending on the chain and whether NFTs are supported.
Example:
const assets = await portal.getAssets('eip155:1')
console.log('Native balance:', assets.nativeBalance)
console.log('Token balances:', assets.tokenBalances)
console.log('NFTs:', assets.nfts)
Signing Methods
personalSign (Deprecated)
Signs a message using personal_sign.
Deprecated: Use request(PortalRequestMethod.PersonalSign, [message, address], chainId, options) instead.
You can pass { signatureApprovalMemo: 'your memo' } in the options.
personalSign(message: string, chainId?: string): Promise<any>
Example (Deprecated):
const signature = await portal.personalSign('Hello, World!')
Recommended approach:
import { PortalRequestMethod } from '@portal-hq/core'
const address = await portal.address
const signature = await portal.request(
PortalRequestMethod.PersonalSign,
['Hello, World!', address],
'eip155:1',
{ signatureApprovalMemo: 'Sign message' }
)
ethSign (Deprecated)
Signs a message using eth_sign.
Deprecated: This method still supports the signature ethSign(message, chainId?, signatureApprovalMemo?), where signatureApprovalMemo is an optional memo shown in the signing UI.
The recommended approach is to use request(PortalRequestMethod.EthSign, [address, message], chainId, { signatureApprovalMemo: 'your memo' }) instead.
ethSign(message: string, chainId?: string, signatureApprovalMemo?: string): Promise<any>
Example (Deprecated):
const signature = await portal.ethSign('0x...')
Recommended approach:
import { PortalRequestMethod } from '@portal-hq/core'
const address = await portal.address
const signature = await portal.request(
PortalRequestMethod.EthSign,
[address, '0x...'],
'eip155:1',
{ signatureApprovalMemo: 'Sign message' }
)
ethSignTypedData (Deprecated)
Signs typed data (EIP-712) using eth_signTypedData_v4.
Deprecated: Use request(PortalRequestMethod.EthSignTypedDataV4, [address, typedData], chainId, options) instead.
You can pass { signatureApprovalMemo: 'your memo' } in the options.
ethSignTypedData(typedData: string, chainId?: string): Promise<any>
Example (Deprecated):
const typedData = JSON.stringify({
types: { ... },
primaryType: 'Mail',
domain: { ... },
message: { ... }
})
const signature = await portal.ethSignTypedData(typedData)
Recommended approach:
import { PortalRequestMethod } from '@portal-hq/core'
const address = await portal.address
const typedData = JSON.stringify({
types: { ... },
primaryType: 'Mail',
domain: { ... },
message: { ... }
})
const signature = await portal.request(
PortalRequestMethod.EthSignTypedDataV4,
[address, typedData],
'eip155:1',
{ signatureApprovalMemo: 'Sign typed data' }
)
rawSign
Signs raw data without any prefix.
rawSign(
message: string,
chainId?: string,
options?: RawSignOptions
): Promise<any>
Example:
const signature = await portal.rawSign(
'0xabcdef...', // Hex-encoded message
'eip155:11155111', // Optional CAIP-2 chainId
{ signatureApprovalMemo: 'Sign login challenge' } // Optional RawSignOptions
)
Transaction Methods
ethSendTransaction (Deprecated)
Sends a signed transaction to the network.
Deprecated: Use request(PortalRequestMethod.EthSendTransaction, [transaction], chainId, options) instead.
You can pass { sponsorGas: boolean, signatureApprovalMemo: 'your memo' } in the options.
ethSendTransaction(
transaction: SigningRequestParams,
chainId?: string
): Promise<any>
Example (Deprecated):
const txHash = await portal.ethSendTransaction({
to: '0x...',
value: '0x1',
data: '0x',
})
Recommended approach:
import { PortalRequestMethod } from '@portal-hq/core'
const txHash = await portal.request(
PortalRequestMethod.EthSendTransaction,
[{
to: '0x...',
value: '0x1',
data: '0x',
}],
'eip155:1',
{ signatureApprovalMemo: 'Send transaction' }
)
ethSignTransaction (Deprecated)
Signs a transaction without broadcasting.
Deprecated: Use request(PortalRequestMethod.EthSignTransaction, [transaction], chainId, options) instead.
You can pass { signatureApprovalMemo: 'your memo' } in the options.
ethSignTransaction(
transaction: SigningRequestParams,
chainId?: string
): Promise<any>
Example (Deprecated):
const signedTx = await portal.ethSignTransaction({
to: '0x...',
value: '0x1',
})
Recommended approach:
import { PortalRequestMethod } from '@portal-hq/core'
const signedTx = await portal.request(
PortalRequestMethod.EthSignTransaction,
[{
to: '0x...',
value: '0x1',
}],
'eip155:1',
{ signatureApprovalMemo: 'Sign transaction' }
)
sendAsset
High-level method to send tokens or native assets.
Recommended Signature:
sendAsset(params: SendAssetParams, chain?: string): Promise<any>
Deprecated Signature:
sendAsset(to: string, token: string, amount: string, chain?: string): Promise<any>
Note: The positional parameters signature sendAsset(to, token, amount, chain) is deprecated. Use the object-based signature sendAsset({ to, token, amount, sponsorGas, signatureApprovalMemo }, chain) instead.
SendAssetParams
interface SendAssetParams {
to: string
amount: string
token: string
sponsorGas?: boolean
signatureApprovalMemo?: string
}
Parameters:
| Parameter | Type | Required | Description |
|---|
to | string | Yes | Recipient address |
token | string | Yes | Token symbol (e.g., 'ETH', 'USDC', 'SOL') |
amount | string | Yes | Amount to send |
sponsorGas | boolean | No | Whether Portal should sponsor the gas. Only applies when the client has Account Abstraction (AA) enabled and the chain is supported. Omitting this field maintains backward compatibility. |
chain | string | No | Chain identifier (friendly name, CAIP-2, or uses default chainId) |
Supported chain values:
-
Friendly names:
'ethereum', 'sepolia', 'base', 'base-sepolia'
'polygon', 'polygon-mumbai', 'polygon-amoy'
'solana', 'solana-devnet'
'optimism', 'arbitrum', 'avalanche'
'bitcoin-p2wpkh', 'bitcoin-p2wpkh-testnet'
-
CAIP-2 format:
- EVM chains:
'eip155:1', 'eip155:11155111', etc.
- Solana:
'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', etc.
- Bitcoin (bip122 namespace):
'bip122:000000000019d6689c085ae165831e93-p2wpkh'
'bip122:000000000933ea01ad0ee984209779ba-p2wpkh'
-
If omitted and no default
chainId is set, an error will be thrown
Example:
// Send ETH on Sepolia with Portal sponsoring gas (default)
const tx1 = await portal.sendAsset({
to: '0xRecipient...',
token: 'ETH',
amount: '0.1',
}, 'sepolia')
// Send ETH on Sepolia but user pays gas
const tx2 = await portal.sendAsset({
to: '0xRecipient...',
token: 'ETH',
amount: '0.1',
sponsorGas: false
}, 'sepolia')
waitForConfirmation
Waits until a transaction is confirmed on the blockchain using strict confirmation semantics. Only a true return value indicates confirmed success.
Behavior by chain type:
- EVM chains (
eip155:*): Polls eth_getTransactionReceipt and (when applicable) eth_getUserOperationReceipt against your configured gatewayConfig URL
- Solana chains (
solana:*): Polls getSignatureStatuses with confirmed commitment level against your configured gatewayConfig URL
- Unsupported/other chains: Returns
false (not supported)
This is the default confirmation strategy used between transaction steps in portal.yield.yieldxyz.deposit(), portal.yield.yieldxyz.withdraw(), and portal.trading methods.
waitForConfirmation(txHash: string, network: string): Promise<boolean>
Parameters:
| Parameter | Type | Required | Description |
|---|
txHash | string | Yes | Transaction hash (or signature for Solana) to poll for |
network | string | Yes | CAIP-2 chain identifier (e.g., 'eip155:1', 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp') |
Returns:
true — Transaction confirmed successfully on-chain
false — Timeout, transaction failed on-chain, or unsupported network
Configuration:
Default behavior:
- Poll interval: 4 seconds (
4_000ms)
- Timeout: 15 minutes (
900_000ms)
- On timeout or failure: Returns
false (does not throw)
Strict confirmation contract:
Only waitForConfirmation(...) === true should be treated as success. Any other value (false, timeout, unsupported network) indicates failure. When used by Portal SDK methods (Yield, LiFi, 0x), this strict contract determines whether execution continues or stops.
Example:
const confirmed = await portal.waitForConfirmation(txHash, 'eip155:11155111')
if (confirmed) {
console.log('Transaction confirmed!')
} else {
console.log('Transaction failed or timed out')
}
evaluateTransaction
Evaluates a transaction for security risks using Blockaid.
evaluateTransaction(
params: EvaluateTransactionParam,
chainId: string,
operationType?: EvaluateTransactionOperationType
): Promise<BlockaidValidateTrxRes>
Example:
const evaluation = await portal.evaluateTransaction(
{ to: '0x...', value: '0x1', data: '0x' },
'eip155:1'
)
Provider Methods
request
Generic method to make JSON-RPC requests.
Preferred Signature:
request(
method: PortalRequestMethod,
params: unknown[],
chainId?: string,
options?: RequestOptions
): Promise<any>
Deprecated Signature:
request(
method: string,
params: unknown[],
chainId?: string,
options?: RequestOptions
): Promise<any>
Note: Using raw string methods is deprecated. Use the PortalRequestMethod enum instead for type safety and better IDE support.
Parameters:
| Parameter | Type | Required | Description |
|---|
method | PortalRequestMethod | string | Yes | JSON-RPC method name. PortalRequestMethod is preferred; string is accepted only for backwards compatibility and use of raw string methods is deprecated. |
params | unknown[] | Yes | Method parameters |
chainId | string | No | CAIP-2 chain identifier |
options | RequestOptions | No | Request options |
RequestOptions:
sponsorGas (boolean, optional): Whether Portal should sponsor gas. Only applies when the client has Account Abstraction (AA) enabled and the chain is supported. Omitting this field maintains default behavior.
signatureApprovalMemo (string, optional): Optional memo displayed to the user during the signature approval flow.
Example:
import { PortalRequestMethod } from '@portal-hq/core'
const balance = await portal.request(
PortalRequestMethod.EthGetBalance,
['0xAddress...', 'latest'],
'eip155:1'
)
// Send a transaction where the user pays gas
const txDetails = await portal.api.buildTransaction(
'0xRecipientAddress',
'USDC',
'1',
'eip155:1'
)
const txHash = await portal.request(
PortalRequestMethod.EthSendTransaction,
[txDetails.transaction],
'eip155:1',
{
sponsorGas: false,
signatureApprovalMemo: 'Swap via Portal'
}
)
console.log('Transaction hash:', txHash)
ethGetBalance (Deprecated)
Gets the native token balance.
Deprecated: Use request(PortalRequestMethod.EthGetBalance, [address], chainId) instead.
ethGetBalance(chainId?: string): Promise<string>
Recommended approach:
import { PortalRequestMethod } from '@portal-hq/core'
const address = await portal.address
const balance = await portal.request(
PortalRequestMethod.EthGetBalance,
[address],
'eip155:1'
)
ethGasPrice (Deprecated)
Gets the current gas price.
Deprecated: Use request(PortalRequestMethod.EthGasPrice, [], chainId) instead.
ethGasPrice(chainId?: string): Promise<string>
Recommended approach:
import { PortalRequestMethod } from '@portal-hq/core'
const gasPrice = await portal.request(
PortalRequestMethod.EthGasPrice,
[],
'eip155:1'
)
ethEstimateGas (Deprecated)
Estimates gas for a transaction.
Deprecated: Use request(PortalRequestMethod.EthEstimateGas, [transaction], chainId) instead.
ethEstimateGas(
transaction: SigningRequestParams,
chainId?: string
): Promise<string>
Recommended approach:
import { PortalRequestMethod } from '@portal-hq/core'
const gas = await portal.request(
PortalRequestMethod.EthEstimateGas,
[transaction],
'eip155:1'
)
getBalanceAsNumber
Gets the native token balance as a number (in ETH, not wei).
getBalanceAsNumber(chainId: string): Promise<number>
Example:
const balance = await portal.getBalanceAsNumber('eip155:1')
console.log(`Balance: ${balance} ETH`)
updateChain (Deprecated)
Updates the current chain ID for the provider.
updateChain(chainId: string): Promise<void>
Parameters:
| Parameter | Type | Required | Description |
|---|
chainId | string | Yes | CAIP-2 chain identifier (e.g., 'eip155:137') |
Example:
await portal.updateChain('eip155:137') // Switch to Polygon
Event Methods
Subscribes to provider events.
on(event: string, callback: EventHandler): void
Example:
portal.on('chainChanged', (chainId) => {
console.log('Chain changed to:', chainId)
})
emit
Emits a provider event.
emit(event: string, payload?: any): void
removeEventListener
Removes an event listener.
removeEventListener(event: string, callback?: EventHandler): void
Keychain Methods
deleteAddress
Deletes the stored address from keychain.
deleteAddress(): Promise<boolean>
deleteSigningShare
Deletes the signing share from keychain.
deleteSigningShare(): Promise<boolean>
deleteShares
Deletes all shares from keychain.
deleteShares(): Promise<boolean>
Gets metadata about signing share pairs.
getSigningSharesMetadata(chainId?: string): Promise<SigningSharePairMetadata[]>
Gets metadata about backup share pairs.
getBackupSharesMetadata(chainId?: string): Promise<BackupSharePairMetadata[]>
Testnet Methods
receiveTestnetAsset
Requests testnet tokens from the Portal faucet.
receiveTestnetAsset(
chainId: string,
params: FundParams
): Promise<FundResponse>
Example:
const result = await portal.receiveTestnetAsset('eip155:11155111', {
token: 'ETH',
amount: '0.1',
})
Portal Connect
createPortalConnectInstance
Creates a Portal Connect instance for WalletConnect integration.
createPortalConnectInstance(chainId: number): PortalConnect
Example:
const portalConnect = portal.createPortalConnectInstance(1)
The portal.api Object
The api property provides access to Portal’s REST API.
getClient
Gets the current client information.
portal.api.getClient(): Promise<ClientResponse>
getAssets
Fetches native balance, token balances, and NFTs for the wallet on a specific chain.
portal.api.getAssets(chainId: string): Promise<{
nativeBalance: NativeBalance
tokenBalances: TokenBalance[]
nfts?: NFT[]
}>
**Example:**
```typescript
const assets = await portal.api.getAssets('eip155:1')
getNFTs
Deprecated: Use portal.api.getNftAssets() instead.
Fetches NFTs owned by the wallet.
portal.api.getNFTs(chainId?: string): Promise<NFT[]>
Example:
const nfts = await portal.api.getNFTs('eip155:1')
getBalances
Deprecated: Use portal.getAssets() instead.
Fetches ERC20 token balances.
portal.api.getBalances(chainId?: string): Promise<Balance[]>
Example:
const balances = await portal.api.getBalances('eip155:1')
getNftAssets
Gets NFT assets held by the wallet.
public async getNftAssets(chainId: string): Promise<NFTAsset[]>
Parameters
| Name | Type | Description |
|---|
chainId | string | Chain ID to query |
Returns
Promise<NFTAsset[]> - Array of NFT assets
Example Usage
const nfts = await portal.api.getNftAssets('eip155:1');
console.log('NFT assets:', nfts);
getTransactionHistory
Returns the transaction history for a wallet across supported chains.
Replaces the legacy getTransactions method with pagination and extended support for modern transaction types (including ERC-4337 UserOperations on EVM chains). EVM responses use the normalized format documented below, while Solana currently returns its legacy response shape and will be unified in a future update.
portal.api.getTransactionHistory(
params: GetTransactionHistoryParams
): Promise<GetTransactionHistoryResponse>
Parameters
| Name | Type | Description |
|---|
params.chainId | string | Chain ID in CAIP-2 format (e.g., 'eip155:1', 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp') |
params.limit | number | Maximum number of transactions to return (default: 50; max: 1000 for EVM, 15 for Solana) |
params.offset | number | Number of transactions to skip for pagination (default: 0) |
params.order | 'asc' | 'desc' | Sort order by block number (default: 'desc', EVM only) |
params.address | string | Optional address override (EVM only) |
params.userOperations | 'include' | 'only' | 'exclude' | Optional. Filter ERC-4337 UserOperations on EVM chains (eip155:*) only. If set, the SDK always sends that value unchanged. |
Default behavior (userOperations)
- EVM (
eip155:*) — If the authenticated client has Account Abstraction enabled (isAccountAbstracted), the SDK automatically sends userOperations=only. If the client is an EOA, the SDK does not send the parameter.
- Non-EVM chains (e.g.
solana:*, Bitcoin, Tron, Stellar) — The SDK never injects userOperations; the filter does not apply to those namespaces.
If userOperations is provided, it always overrides this behavior.
Returns
Promise<GetTransactionHistoryResponse>
For Solana chains (solana:*):
{
data: {
transactions: SolanaTransactionDetails[]
},
metadata: {
address: string
chainId: string
clientId: string
limit: number
offset: number
count: number
}
}
For EVM, Bitcoin, Tron, Stellar chains:
{
data: {
transactions: TransactionHistoryItem[]
},
metadata: {
address: string
chainId: string
clientId: string
limit: number
offset: number
count: number
}
}
TransactionHistoryItem is a discriminated union:
- RegularTransaction:
type: 'transaction' with optional token metadata (asset, tokenAddress, tokenDecimals)
- UserOperationTransaction:
type: 'userOperation' with UserOp fields (userOpHash, entryPoint, actualGasCost, actualGasUsed)
Example Usage
// Get EVM transactions including UserOperations
const evmTxs = await portal.api.getTransactionHistory({
chainId: 'eip155:1',
limit: 20,
order: 'desc',
userOperations: 'include', // Include both regular txs and UserOps
})
// Type narrowing based on transaction type
evmTxs.data.transactions.forEach((tx) => {
if (tx.type === 'userOperation') {
console.log('UserOp hash:', tx.userOpHash)
console.log('Entry point:', tx.entryPoint)
// tx.asset not available (compile error)
} else {
console.log('Token:', tx.asset)
console.log('Token address:', tx.tokenAddress)
// tx.userOpHash not available (compile error)
}
})
// EVM + Account Abstraction: omit `userOperations`
// If wallet is AA-enabled, SDK injects `userOperations='only'`
// Otherwise (EOA), the parameter is not sent
const aaEvmHistory = await portal.api.getTransactionHistory({
chainId: 'eip155:42161',
limit: 20,
});
// Get Solana transactions
const solanaTxs = await portal.api.getTransactionHistory({
chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
limit: 15,
});
// Solana transactions have a different structure
solanaTxs.data.transactions.forEach(tx => {
console.log('Signature:', tx.signature);
console.log('Block time:', tx.blockTime);
console.log('Status:', tx.status);
});
// Get only UserOperations (EVM only)
const userOps = await portal.api.getTransactionHistory({
chainId: 'eip155:137',
userOperations: 'only',
limit: 10,
});
getTransactions
Deprecated: Use portal.api.getTransactionHistory() instead, which provides improved type safety with discriminated unions for regular transactions and UserOperations, and proper polymorphic response types for Solana vs unified formats.
Fetches transaction history.
portal.api.getTransactions(
chainId?: string,
limit?: number,
offset?: number,
order?: GetTransactionsOrder
): Promise<Transaction[]>
Example:
const txs = await portal.api.getTransactions('eip155:1', 10, 0, 'desc')
getNetworks
Gets supported networks.
portal.api.getNetworks(): Promise<Network[]>
getEnabledDapps
Gets enabled dApps for the client.
portal.api.getEnabledDapps(): Promise<Dapp[]>
simulateTransaction
Deprecated: Use portal.evaluateTransaction() instead.
Simulates a transaction.
portal.api.simulateTransaction(
transaction: SimulateTransactionParam,
chainId?: string
): Promise<SimulatedTransaction>
getQuote (Deprecated)
Deprecated: Use portal.trading.zeroX.getQuote() instead.
Gets a swap quote.
portal.api.getQuote(
apiKey: string,
args: QuoteArgs,
chainId?: string
): Promise<QuoteResponse>
getSources (Deprecated)
Deprecated: Use portal.trading.zeroX.getSources() instead.
Gets available swap sources.
portal.api.getSources(
apiKey: string,
chainId?: string
): Promise<Record<string, string>>
The portal.ramps object
The ramps property exposes fiat on- and off-ramp integrations.
portal.ramps (Ramps)
The Ramps class groups fiat on- and off-ramp integrations.
Properties
| Property | Type | Description |
|---|
noah | Noah | Noah ramp API |
meld | Meld | Meld buy, sell, and transfer API |
See the Noah React Native SDK guide and the Meld React Native SDK guide for end-to-end flows and prerequisites.
portal.ramps.noah (Noah)
Noah methods issue HTTP requests through portal.api to /api/v3/clients/me/integrations/noah/... with the Portal client API key. Responses follow the { data, metadata? } envelope used across Client API integrations.
initiateKyc
public async initiateKyc(data: NoahInitiateKycRequest): Promise<NoahInitiateKycResponse>
| Parameter | Type | Description |
|---|
data | NoahInitiateKycRequest | returnUrl (HTTPS), optional fiatOptions, customerType, metadata, form |
Returns — Promise<NoahInitiateKycResponse> with data.hostedUrl for hosted onboarding.
initiatePayin
public async initiatePayin(data: NoahInitiatePayinRequest): Promise<NoahInitiatePayinResponse>
| Parameter | Type | Description |
|---|
data | NoahInitiatePayinRequest | fiatCurrency, cryptoCurrency, CAIP-2 network, destinationAddress |
Returns — Promise<NoahInitiatePayinResponse> with data.payinId and structured data.bankDetails: BankDetails.
simulatePayin
public async simulatePayin(data: NoahSimulatePayinRequest): Promise<NoahSimulatePayinResponse>
| Parameter | Type | Description |
|---|
data | NoahSimulatePayinRequest | paymentMethodId, fiatAmount, fiatCurrency |
Returns — Promise<NoahSimulatePayinResponse> with data.fiatDepositId.
getPayoutCountries
public async getPayoutCountries(): Promise<NoahGetPayoutCountriesResponse>
Returns — Promise<NoahGetPayoutCountriesResponse> with data.countries: Record<string, string[]>.
getPayoutChannels
public async getPayoutChannels(data: NoahGetPayoutChannelsRequest): Promise<NoahGetPayoutChannelsResponse>
| Parameter | Type | Description |
|---|
data | NoahGetPayoutChannelsRequest | country, cryptoCurrency, fiatCurrency, optional fiatAmount |
Returns — Promise<NoahGetPayoutChannelsResponse> with data.items: Channel[] and optional data.pageToken.
public async getPayoutChannelForm(channelId: string): Promise<NoahGetPayoutChannelFormResponse>
| Parameter | Type | Description |
|---|
channelId | string | Payout channel id from getPayoutChannels |
Returns — Promise<NoahGetPayoutChannelFormResponse> with data.formSchema and optional data.formMetadata.
getPayoutQuote
public async getPayoutQuote(data: NoahGetPayoutQuoteRequest): Promise<NoahGetPayoutQuoteResponse>
| Parameter | Type | Description |
|---|
data | NoahGetPayoutQuoteRequest | channelId, cryptoCurrency, fiatAmount, optional form, fiatCurrency, paymentMethodId |
Returns — Promise<NoahGetPayoutQuoteResponse> including payoutId, formSessionId, cryptoAmountEstimate, totalFee.
initiatePayout
public async initiatePayout(data: NoahInitiatePayoutRequest): Promise<NoahInitiatePayoutResponse>
| Parameter | Type | Description |
|---|
data | NoahInitiatePayoutRequest | payoutId, sourceAddress, ISO expiry, nonce, CAIP-2 network, optional trigger |
Returns — Promise<NoahInitiatePayoutResponse> with data.destinationAddress: string | null and data.conditions: DepositSourceTriggerCondition[].
getPaymentMethods
public async getPaymentMethods(): Promise<NoahGetPaymentMethodsResponse>
Returns — Promise<NoahGetPaymentMethodsResponse> with data.paymentMethods: PaymentMethod[] and optional data.pageToken: string.
portal.ramps.meld (Meld)
Meld methods issue HTTP requests through portal.api to /api/v3/clients/me/integrations/meld/... with the Portal client API key. Responses follow the { data, metadata? } envelope used across Client API integrations.
See the Meld React Native SDK guide for end-to-end flows with full examples.
createCustomer
public async createCustomer(
request: MeldCreateCustomerRequest
): Promise<MeldCreateCustomerResponse>
| Parameter | Type | Description |
|---|
request | MeldCreateCustomerRequest | Optional name, email, phone, dateOfBirth, type ("INDIVIDUAL" | "BUSINESS") |
Returns — Promise<MeldCreateCustomerResponse> with data: MeldCustomer (id, externalId, accountId, name?, email?, phone?, dateOfBirth?, type?, status?, addresses?, serviceProviders?).
searchCustomer
public async searchCustomer(): Promise<MeldSearchCustomerResponse>
Returns — Promise<MeldSearchCustomerResponse> with data: { customers: MeldCustomer[]; count: number; remaining: number }.
getRetailQuote
public async getRetailQuote(
request: MeldGetRetailQuoteRequest
): Promise<MeldGetRetailQuoteResponse>
| Parameter | Type | Description |
|---|
request | MeldGetRetailQuoteRequest | Required: countryCode, sourceCurrencyCode, destinationCurrencyCode, sourceAmount (number). Optional: walletAddress, customerId, paymentMethodType, serviceProviders, subdivision |
Returns — Promise<MeldGetRetailQuoteResponse> with data: { quotes: MeldQuote[]; message?: string; error?: string; timestamp?: string | null }. Each MeldQuote includes required fields serviceProvider, transactionType, sourceAmount, sourceCurrencyCode, destinationAmount, destinationCurrencyCode, exchangeRate, transactionFee, totalFee, paymentMethodType; and optional fields sourceAmountWithoutFees, destinationAmountWithoutFees, networkFee, partnerFee, fiatAmountWithoutFees, countryCode, customerScore, institutionName, isNativeAvailable, rampIntelligence.
public async createRetailWidget(
request: MeldCreateRetailWidgetRequest
): Promise<MeldCreateRetailWidgetResponse>
| Parameter | Type | Description |
|---|
request | MeldCreateRetailWidgetRequest | Required: sessionType ("BUY" | "SELL" | "TRANSFER"), sessionData (MeldSessionData). Optional: externalSessionId, customerId, bypassKyc |
Returns — Promise<MeldCreateRetailWidgetResponse> with data: { id, token, widgetUrl, customerId, externalCustomerId, externalSessionId }.
searchRetailTransactions
public async searchRetailTransactions(
params?: MeldSearchRetailTransactionsParams
): Promise<MeldSearchRetailTransactionsResponse>
| Parameter | Type | Description |
|---|
params | MeldSearchRetailTransactionsParams | Optional status, limit, offset (all strings) |
Returns — Promise<MeldSearchRetailTransactionsResponse> with data: { transactions: MeldTransaction[]; count: number; remaining: number; totalCount: number }.
getRetailTransaction
public async getRetailTransaction(id: string): Promise<MeldGetRetailTransactionResponse>
| Parameter | Type | Description |
|---|
id | string | Meld transaction ID |
Returns — Promise<MeldGetRetailTransactionResponse> with data: { transaction: MeldTransaction }.
getRetailTransactionBySession
public async getRetailTransactionBySession(
sessionId: string
): Promise<MeldGetRetailTransactionResponse>
| Parameter | Type | Description |
|---|
sessionId | string | Meld session ID from createRetailWidget response (data.id) |
Returns — Promise<MeldGetRetailTransactionResponse> with data: { transaction: MeldTransaction }.
getServiceProviders
public async getServiceProviders(
params?: MeldDiscoveryParams
): Promise<MeldGetServiceProvidersResponse>
Returns — Promise<MeldGetServiceProvidersResponse> with data: MeldServiceProvider[] (serviceProvider, name, status?, categories?, categoryStatuses?, websiteUrl?, customerSupportUrl?, logos? with dark?, light?, darkShort?, lightShort?).
getCountries
public async getCountries(
params?: MeldDiscoveryParams
): Promise<MeldGetCountriesResponse>
Returns — Promise<MeldGetCountriesResponse> with data: MeldCountry[].
getFiatCurrencies
public async getFiatCurrencies(
params?: MeldDiscoveryParams
): Promise<MeldGetFiatCurrenciesResponse>
Returns — Promise<MeldGetFiatCurrenciesResponse> with data: MeldFiatCurrency[].
getCryptoCurrencies
public async getCryptoCurrencies(
params?: MeldDiscoveryParams
): Promise<MeldGetCryptoCurrenciesResponse>
Returns — Promise<MeldGetCryptoCurrenciesResponse> with data: MeldCryptoCurrency[].
getPaymentMethods
public async getPaymentMethods(
params?: MeldDiscoveryParams
): Promise<MeldGetPaymentMethodsResponse>
Returns — Promise<MeldGetPaymentMethodsResponse> with data: MeldPaymentMethod[].
getDefaults
public async getDefaults(
params?: MeldDiscoveryParams
): Promise<MeldGetDefaultsResponse>
Returns — Promise<MeldGetDefaultsResponse> with data: MeldCountryDefault[] (countryCode, defaultCurrencyCode, defaultPaymentMethods).
getBuyLimits
public async getBuyLimits(
params?: MeldDiscoveryParams
): Promise<MeldGetBuyLimitsResponse>
Returns — Promise<MeldGetBuyLimitsResponse> with data: MeldFiatCurrencyPurchaseLimit[] (currencyCode, minimumAmount, maximumAmount, defaultAmount).
getSellLimits
public async getSellLimits(
params?: MeldDiscoveryParams
): Promise<MeldGetSellLimitsResponse>
Returns — Promise<MeldGetSellLimitsResponse> with data: MeldCryptoCurrencySellLimit[] (currencyCode, chainCode, minimumAmount, maximumAmount, defaultAmount).
getKycLimits
public async getKycLimits(
params?: MeldDiscoveryParams
): Promise<MeldGetKycLimitsResponse>
Returns — Promise<MeldGetKycLimitsResponse> with data: MeldKycFiatLevel[]. Each entry includes currencyCode and optional level1, level2, level3 of type MeldKycLimitTier with dailyLimit, weeklyLimit, monthlyLimit, yearlyLimit, transactionLimit.
The portal.mpc Object
The mpc property handles MPC wallet operations directly.
generate
Generates new MPC signing shares.
portal.mpc.generate(progress?: ProgressCallback): Promise<AddressesByNamespace>
backup
Creates backup shares.
portal.mpc.backup(
method: BackupMethods,
progress?: ProgressCallback,
backupConfig?: BackupConfigs
): Promise<string>
recover
Recovers signing shares from backup.
portal.mpc.recover(
cipherText: string,
method: BackupMethods,
progress?: ProgressCallback,
backupConfig?: BackupConfigs
): Promise<AddressesByNamespace>
ejectPrivateKey
Ejects the SECP256K1 private key (for migration).
portal.mpc.ejectPrivateKey(
backupShareCipherText?: string,
backupMethod: BackupMethods,
backupConfig?: BackupConfigs,
orgShare?: string
): Promise<string>
Parameters:
| Parameter | Type | Required | Description |
|---|
backupShareCipherText | string | No | Encrypted backup share (default: '') |
backupMethod | BackupMethods | Yes | Backup method to use |
backupConfig | BackupConfigs | No | Backup configuration |
orgShare | string | No | Organization share (default: '') |
ejectPrivateKeys
Ejects both SECP256K1 and ED25519 private keys.
portal.mpc.ejectPrivateKeys(
backupShareCipherText?: string,
backupMethod: BackupMethods,
backupConfig?: BackupConfigs,
orgShare?: orgShares
): Promise<EjectedKeys>
Parameters:
| Parameter | Type | Required | Description |
|---|
backupShareCipherText | string | No | Encrypted backup share (default: '') |
backupMethod | BackupMethods | Yes | Backup method to use |
backupConfig | BackupConfigs | No | Backup configuration |
orgShare | orgShares | No | Organization shares (default: { secp256k1: '', ed25519: '' }) |
Returns:
interface EjectedKeys {
secp256k1Key?: string
ed25519Key?: string
}
isReady
Checks if the MPC client is ready.
portal.mpc.isReady(): Promise<boolean>
The portal.provider Object
The provider property is an EIP-1193 compliant provider.
request
Makes JSON-RPC requests.
portal.provider.request({
method: string,
params: any[],
chainId?: string
}): Promise<any>
Example:
const txHash = await portal.provider.request({
method: 'eth_sendTransaction',
params: [{
to: '0x...',
value: '0x1',
data: '0x',
}],
chainId: 'eip155:1',
})
React Context
PortalContextProvider
Provides the Portal instance to child components.
import { Portal, PortalContextProvider } from '@portal-hq/core'
const App = () => {
const [portal, setPortal] = useState<Portal | null>(null)
useEffect(() => {
setPortal(new Portal({ /* config */ }))
}, [])
if (!portal) return null
return (
<PortalContextProvider value={portal}>
<YourApp />
</PortalContextProvider>
)
}
usePortal
Hook to access the Portal instance.
import { usePortal } from '@portal-hq/core'
const WalletComponent = () => {
const portal = usePortal()
const createWallet = async () => {
const addresses = await portal.createWallet()
console.log(addresses)
}
return <Button onPress={createWallet} title="Create Wallet" />
}
Enums
BackupMethods
enum BackupMethods {
Custom = 'custom',
Firebase = 'firebase',
GoogleDrive = 'gdrive',
Password = 'password',
Passkey = 'passkey',
Unknown = 'unknown',
iCloud = 'icloud',
}
PortalRequestMethod
enum PortalRequestMethod {
EthSign = 'eth_sign',
EthSignTransaction = 'eth_signTransaction',
EthSignUserOperation = 'eth_signUserOperation'
EthSignTypedDataV4 = 'eth_signTypedData_v4',
EthSendTransaction = 'eth_sendTransaction',
EthGetBalance = 'eth_getBalance',
EthGasPrice = 'eth_gasPrice',
EthEstimateGas = 'eth_estimateGas',
PersonalSign = 'personal_sign',
RawSign = 'raw_sign',
SolSignAndSendTransaction = 'sol_signAndSendTransaction',
SolSignTransaction = 'sol_signTransaction',
SolSignMessage = 'sol_signMessage',
// Additional Solana and other supported chain methods are also available.
}
PortalNamespace
enum PortalNamespace {
eip155 = 'eip155',
solana = 'solana',
}
PortalCurve
enum PortalCurve {
ED25519 = 'ED25519',
SECP256K1 = 'SECP256K1',
}
PortalSharePairStatus
enum PortalSharePairStatus {
COMPLETED = 'completed',
INCOMPLETE = 'incomplete',
}
MpcErrorCodes
enum MpcErrorCodes {
CLIENT_NOT_VERIFIED = 'CLIENT_NOT_VERIFIED',
FORMAT_SHARES_ERROR = 'FORMAT_SHARES_ERROR',
GOOGLE_UNAUTHENTICATED = 'GOOGLE_UNAUTHENTICATED',
KEYCHAIN_UNAVAILABLE = 'KEYCHAIN_UNAVAILABLE',
MPC_MODULE_NOT_FOUND = 'MPC_MODULE_NOT_FOUND',
PASSWORD_REQUIRED = 'PASSWORD_REQUIRED',
STORAGE_UNAVAILABLE = 'STORAGE_UNAVAILABLE',
UNABLE_TO_READ_SIGNING_STORAGE = 'UNABLE_TO_READ_SIGNING_STORAGE',
UNEXPECTED_ERROR = 'UNEXPECTED_ERROR',
UNSUPPORTED_MPC_VERSION = 'UNSUPPORTED_MPC_VERSION',
UNSUPPORTED_STORAGE_METHOD = 'UNSUPPORTED_STORAGE_METHODS',
WALLET_MODIFICATION_ALREADY_IN_PROGRESS = 'WALLET_MODIFICATION_ALREADY_IN_PROGRESS',
}
EvaluateTransactionOperationType
enum EvaluateTransactionOperationType {
// Defined in @portal-hq/utils.
// Supported values are documented in the Evaluate a transaction guide.
}
Error Classes
MpcError
Custom error class for MPC operations.
class MpcError extends Error {
code: string
context?: string
}
Example:
import { MpcError, MpcErrorCodes } from '@portal-hq/core'
try {
await portal.createWallet()
} catch (error) {
if (error instanceof MpcError) {
if (error.code === MpcErrorCodes.WALLET_MODIFICATION_ALREADY_IN_PROGRESS) {
console.log('Please wait for the current operation to complete')
}
}
}
Types
PortalOptions
interface PortalOptions {
apiKey: string
backup: BackupOptions
gatewayConfig?: GatewayLike // optional — defaults to Portal RPC gateway for 10 built-in chains
/** @deprecated */
chainId?: number
isSimulator?: boolean
autoApprove?: boolean
keychain?: KeychainAdapter
apiHost?: string
mpcHost?: string
featureFlags?: FeatureFlags
}
BackupOptions
interface BackupOptions {
custom?: Storage
firebase?: Storage
gdrive?: Storage
icloud?: Storage
passkey?: Storage
password?: Storage
}
FeatureFlags
interface FeatureFlags {
enableSdkPerformanceMetrics?: boolean
useEnclaveMPCApi?: boolean
usePresignatures?: boolean
}
Properties:
| Property | Type | Default | Description |
|---|
enableSdkPerformanceMetrics | boolean | false | Enable SDK performance metrics tracking |
useEnclaveMPCApi | boolean | false | Use Enclave MPC API instead of standard MPC |
usePresignatures | boolean | false | Enable automatic presignature use for faster signing. The SDK generates and consumes presignatures in the background; you do not call presign APIs directly. Applies to SECP256K1 (EVM) signing only. See Feature flags for details. |
AddressesByNamespace
interface AddressesByNamespace {
eip155?: string
solana?: string
}
GatewayConfig
gatewayConfig is optional. When omitted (or set to {}), the SDK automatically builds a default config that routes RPC traffic through Portal’s managed gateway for 10 built-in chains:
| Chain | CAIP-2 ID |
|---|
| Ethereum Mainnet | eip155:1 |
| Ethereum Sepolia | eip155:11155111 |
| Polygon Mainnet | eip155:137 |
| Polygon Amoy | eip155:80002 |
| Base Mainnet | eip155:8453 |
| Base Sepolia | eip155:84532 |
| Monad Mainnet | eip155:143 |
| Monad Testnet | eip155:10143 |
| Solana Mainnet | solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp |
| Solana Devnet | solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 |
Default URLs follow the pattern https://{apiHost}/rpc/v1/{namespace}/{reference} (e.g. https://api.portalhq.io/rpc/v1/eip155/1).
When gatewayConfig is a non-empty object or a string, it is used exactly as supplied — the SDK does not merge defaults into a custom config.
Requests to Portal’s managed gateway automatically include your apiKey as a Bearer token — no extra configuration needed. Requests to a custom RPC URL (e.g. Infura, Alchemy) are sent without it, since third-party providers require their own credentials.
// Omit entirely — Portal gateway used automatically (recommended)
new Portal({ apiKey, backup })
// String format — single URL applied to all chains
const gatewayConfig = 'https://mainnet.infura.io/v3/YOUR_KEY'
// Object format — per-chain RPC URLs (replaces defaults entirely)
const gatewayConfig: GatewayConfig = {
'eip155:1': 'https://mainnet.infura.io/v3/YOUR_KEY',
'eip155:137': 'https://polygon-mainnet.infura.io/v3/YOUR_KEY',
}
// Extend defaults with additional chains using buildDefaultGatewayConfig
import { buildDefaultGatewayConfig } from '@portal-hq/utils'
const gatewayConfig = {
...buildDefaultGatewayConfig('api.portalhq.io'),
'eip155:42161': 'https://arb-mainnet.g.alchemy.com/v2/YOUR_KEY',
}
Dapp
interface Dapp {
id: string
name: string
addresses: Address[]
dappOnNetworks: DappOnNetwork[]
image: DappImage
}
Address
interface Address {
id: string
network: Network
value: string
}
Exports Summary
// Classes
export { Portal }
export { PortalApi }
export { MpcError }
// Context
export { PortalContext, PortalContextProvider, usePortal }
// Enums
export { BackupMethods, PortalCurve, PortalSharePairStatus, PortalNamespace }
export { MpcErrorCodes }
export { EvaluateTransactionOperationType, PortalRequestMethod }
// Yield.xyz (see https://docs.portalhq.io/integrations/yield-xyz for documentation)
export { YieldXyz, PortalYieldXyzApi, PortalYieldXyzApiError, YieldXyzErrorCode }
// Types
export type { PortalOptions, Address, Dapp, FeatureFlags, BackupOptions }
export type { IYieldXyz, IPortalYieldXyzApi, YieldXyzOptions, PortalYieldXyzApiOptions }
export type { YieldXyzOperationContext }
export type { RawSignOptions, RequestOptions, SendAssetParams }
// Yield.xyz related types are re-exported by @portal-hq/core.