Skip to main content

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');

See Also