P2P Transfer
Peer-to-peer transfers let your users send cryptocurrency directly to any wallet address. The ONE SDK (@one_deploy/sdk v1.1.0) provides the OneSendWidget for web applications and the sendTransaction API method for all platforms.
Widget Usage (Web)
OneSendWidget
A complete send-crypto widget that handles recipient input, token selection, amount entry, gas estimation, confirmation, and transaction tracking.
import { OneSendWidget } from '@one_deploy/sdk';
function SendPage() {
return (
<OneSendWidget
walletAddress="0xSenderWalletAddress"
chainId={1}
defaultToken={{ symbol: 'ETH', chainId: 1 }}
defaultRecipient=""
allowedTokens={[
{ symbol: 'ETH', chainId: 1 },
{ symbol: 'USDC', chainId: 1, address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' },
{ symbol: 'USDT', chainId: 1, address: '0xdAC17F958D2ee523a2206206994597C13D831ec7' },
]}
onSuccess={(result) => {
console.log('Transfer sent:', result.txHash);
}}
onError={(error) => {
console.error('Transfer failed:', error.message);
}}
onClose={() => {
console.log('Widget closed');
}}
theme="light"
/>
);
}
OneSendWidgetProps
interface OneSendWidgetProps {
/** Sender wallet address */
walletAddress: string;
/** Chain ID for the transfer */
chainId: number;
/** Default token to send */
defaultToken?: TokenIdentifier;
/** Pre-filled recipient address */
defaultRecipient?: string;
/** Pre-filled amount */
defaultAmount?: string;
/** Restrict which tokens the user can send */
allowedTokens?: TokenIdentifier[];
/** Enable ENS / address book resolution (default: true) */
enableAddressResolution?: boolean;
/** Called when the transfer is confirmed on-chain */
onSuccess?: (result: EngineTransactionResponse) => void;
/** Called when the transfer fails */
onError?: (error: { code: string; message: string }) => void;
/** Called when the user closes the widget */
onClose?: () => void;
/** Widget color theme */
theme?: 'light' | 'dark' | 'auto';
/** Override CSS class name */
className?: string;
}
interface TokenIdentifier {
symbol: string;
chainId: number;
address?: string;
}
API Method: sendTransaction
The sendTransaction method on OneEngineClient handles native token transfers, ERC-20 token transfers, and arbitrary contract calls.
import { OneEngineClient } from '@one_deploy/sdk';
const engine = new OneEngineClient({
apiKey: 'YOUR_API_KEY',
projectId: 'YOUR_PROJECT_ID',
});
Send ETH (Native Token)
const result: EngineTransactionResponse = await engine.sendTransaction({
from: '0xSenderAddress',
to: '0xRecipientAddress',
chainId: 1,
value: '0.1', // amount in ETH (human-readable)
currency: 'native',
});
console.log(result);
// {
// transactionId: 'etx_abc123',
// txHash: '0x1234abcd...',
// status: 'processing',
// from: '0xSender...',
// to: '0xRecipient...',
// value: '0.1',
// chainId: 1,
// gasUsed: '21000',
// createdAt: '2026-02-02T12:00:00Z',
// }
Send USDC (ERC-20 Token)
const result = await engine.sendTransaction({
from: '0xSenderAddress',
to: '0xRecipientAddress',
chainId: 1,
value: '250.00', // amount in USDC (human-readable)
currency: 'token',
tokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
});
console.log(`Sent 250 USDC -- tx: ${result.txHash}`);
Send Custom Token
const result = await engine.sendTransaction({
from: '0xSenderAddress',
to: '0xRecipientAddress',
chainId: 137,
value: '1000',
currency: 'token',
tokenAddress: '0xYourCustomTokenAddress',
tokenDecimals: 18, // specify if non-standard discovery is needed
});
console.log(`Custom token transfer: ${result.txHash}`);
Types
interface EngineTransactionRequest {
/** Sender wallet address */
from: string;
/** Recipient wallet address */
to: string;
/** Chain ID for the transaction */
chainId: number;
/** Amount to send (human-readable string) */
value: string;
/** Currency type: 'native' for chain token, 'token' for ERC-20 */
currency: 'native' | 'token';
/** ERC-20 contract address (required when currency is 'token') */
tokenAddress?: string;
/** Token decimals override (auto-detected if omitted) */
tokenDecimals?: number;
/** Optional data payload for raw contract calls */
data?: string;
/** Gas limit override */
gasLimit?: string;
/** Max fee per gas in wei (EIP-1559) */
maxFeePerGas?: string;
/** Max priority fee per gas in wei (EIP-1559) */
maxPriorityFeePerGas?: string;
/** Arbitrary metadata */
metadata?: Record<string, string>;
}
interface EngineTransactionResponse {
/** Internal transaction identifier */
transactionId: string;
/** On-chain transaction hash */
txHash: string;
/** Current transaction status */
status: TransactionStatus;
/** Sender address */
from: string;
/** Recipient address */
to: string;
/** Amount transferred (human-readable) */
value: string;
/** Chain ID */
chainId: number;
/** Gas used (in wei, string) */
gasUsed?: string;
/** Effective gas price (in wei, string) */
effectiveGasPrice?: string;
/** Block number (available once confirmed) */
blockNumber?: number;
/** ISO 8601 creation timestamp */
createdAt: string;
/** ISO 8601 last-updated timestamp */
updatedAt: string;
}
type TransactionStatus =
| 'pending'
| 'processing'
| 'confirmed'
| 'failed'
| 'dropped';
Tracking Transaction Status
Use getTransactionStatus to poll for confirmation:
async function waitForConfirmation(transactionId: string): Promise<EngineTransactionResponse> {
let tx = await engine.getTransactionStatus(transactionId);
while (tx.status === 'pending' || tx.status === 'processing') {
await new Promise((r) => setTimeout(r, 3000));
tx = await engine.getTransactionStatus(transactionId);
console.log(`Status: ${tx.status}`);
}
return tx;
}
// Usage
const result = await engine.sendTransaction({
from: '0xSender...',
to: '0xRecipient...',
chainId: 1,
value: '0.5',
currency: 'native',
});
const confirmed = await waitForConfirmation(result.transactionId);
if (confirmed.status === 'confirmed') {
console.log(`Confirmed in block ${confirmed.blockNumber}`);
console.log(`Gas used: ${confirmed.gasUsed}`);
} else {
console.error(`Transaction ${confirmed.status}`);
}
Full Example: Multi-token Transfer
import { OneEngineClient } from '@one_deploy/sdk';
const engine = new OneEngineClient({
apiKey: process.env.ONE_API_KEY!,
projectId: process.env.ONE_PROJECT_ID!,
});
const TOKENS = {
USDC: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
USDT: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
DAI: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
};
async function sendPayment(
from: string,
to: string,
amount: string,
token: 'ETH' | 'USDC' | 'USDT' | 'DAI'
) {
const isNative = token === 'ETH';
const result = await engine.sendTransaction({
from,
to,
chainId: 1,
value: amount,
currency: isNative ? 'native' : 'token',
tokenAddress: isNative ? undefined : TOKENS[token],
});
console.log(`Sending ${amount} ${token} to ${to}`);
console.log(`Transaction hash: ${result.txHash}`);
// Wait for confirmation
let tx = await engine.getTransactionStatus(result.transactionId);
while (tx.status === 'pending' || tx.status === 'processing') {
await new Promise((r) => setTimeout(r, 3000));
tx = await engine.getTransactionStatus(result.transactionId);
}
if (tx.status === 'confirmed') {
console.log(`${amount} ${token} delivered to ${to} in block ${tx.blockNumber}`);
} else {
throw new Error(`Transfer failed with status: ${tx.status}`);
}
return tx;
}
// Send 100 USDC
await sendPayment('0xSender...', '0xRecipient...', '100', 'USDC');
// Send 0.05 ETH
await sendPayment('0xSender...', '0xRecipient...', '0.05', 'ETH');