Skip to main content

Sending Transactions & Viewing History

Sphere enables your application to easily send cryptocurrency transactions on behalf of users and to retrieve their transaction history. This functionality is crucial for any application dealing with digital asset transfers.

This page covers:

  • Sending tokens (currently, all sends are processed as gasless transactions).
  • Fetching a user's transaction history.
  • Getting an estimate of transaction fees.

Prerequisites

Before sending transactions or fetching history, ensure:

  1. User Authentication: The user on whose behalf the transaction is being made, or whose history is being fetched, must be authenticated.
  2. Authentication Parameters: For sending transactions, you must include authentication credentials directly in the request using one of these combinations:
    • email + otpCode
    • phoneNumber + otpCode
    • externalId + password

Important: Unlike other SDK methods that rely on the bearer token set via sphere.setBearerToken(), transaction sending requires explicit authentication parameters in each request for additional security.

Refer to Creating & Accessing User Wallets or OTP Verification & Session Management for details on establishing an authenticated SDK session.

import Sphere, {
Environment,
ChainName,
TokenSymbol,
TransactionRequest,
TransactionResponse,
TransactionHistoryRequest,
TransactionHistory,
TransactionHistoryResponse,
TransactionType,
} from "@stratosphere-network/wallet";

const sphere = new Sphere({
apiKey: "YOUR_API_KEY", // Your project API key
environment: Environment.DEVELOPMENT,
});

// Example: After user login, you get an accessToken
// sphere.setBearerToken("USER_ACCESS_TOKEN");

1. Sending a Transaction (sphere.transactions.send)

This method allows an authenticated user to send a specified amount of a token to a recipient address on a given chain. Currently, Sphere processes all send transactions as gasless, meaning the Stratosphere Network covers the network fees for the user, simplifying their experience. A fee is charged to the user in the token they are transferring to cover this. (See Transaction Fees for more details).

Authentication Requirement: Every send transaction requires authentication credentials to be included in the request payload. You must provide one of the following authentication combinations:

  • email + otpCode - For users authenticated via email
  • phoneNumber + otpCode - For users authenticated via phone
  • externalId + password - For users authenticated via external ID

Intuition: This is like making a bank transfer where you need to verify your identity with each transaction. The service fee is deducted from the transfer amount itself, and you don't need a separate balance for network charges. You specify the recipient, amount, currency (token & chain), and your authentication credentials.

Flow:

  1. Your application gathers transaction details from the user (recipient, amount, token, chain).
  2. It calls sphere.transactions.send() with these details (the type will effectively be gasless).
  3. The Sphere SDK communicates with the Stratosphere Network, which validates the request, processes the gas sponsoring, and submits the transaction on the blockchain.
  4. A response is returned with the transaction hash and status message.

Diagram: Sending a Transaction (Gasless)

SDK Usage: Sending Tokens

// Example 1: Sending with Email + OTP Authentication
async function sendTokensWithEmail(
toAddress: string,
value: string, // Amount as a string, e.g., "0.5"
tokenSymbol: TokenSymbol,
chainName: ChainName,
email: string,
otpCode: string
): Promise<TransactionResponse | null> {
try {
const requestPayload: TransactionRequest & { [key: string]: string } = {
to: toAddress,
value: value,
token: tokenSymbol,
chain: chainName,
type: "gasless",
// Authentication parameters
email: email,
otpCode: otpCode,
};

console.log(
`Sending ${value} ${tokenSymbol} to ${toAddress} on ${chainName} (gasless)...`
);
const response = await sphere.transactions.send(requestPayload);

if (response && response.transactionHash) {
console.log("Transaction successful!");
console.log(" Message:", response.message);
console.log(" Transaction Explorer URL:", response.transactionHash);
return response;
} else {
console.error(
"Failed to send transaction. Response was empty or missing transaction hash."
);
return null;
}
} catch (error) {
console.error("Error sending transaction:", error);
throw error;
}
}

// Example 2: Sending with Phone + OTP Authentication
async function sendTokensWithPhone(
toAddress: string,
value: string,
tokenSymbol: TokenSymbol,
chainName: ChainName,
phoneNumber: string,
otpCode: string
): Promise<TransactionResponse | null> {
try {
const requestPayload: TransactionRequest & { [key: string]: string } = {
to: toAddress,
value: value,
token: tokenSymbol,
chain: chainName,
type: "gasless",
// Authentication parameters
phoneNumber: phoneNumber,
otpCode: otpCode,
};

console.log(
`Sending ${value} ${tokenSymbol} using phone authentication...`
);
const response = await sphere.transactions.send(requestPayload);

if (response && response.transactionHash) {
console.log("Transaction successful!");
return response;
}
return null;
} catch (error) {
console.error("Error sending transaction:", error);
throw error;
}
}

// Example 3: Sending with External ID + Password Authentication
async function sendTokensWithExternalId(
toAddress: string,
value: string,
tokenSymbol: TokenSymbol,
chainName: ChainName,
externalId: string,
password: string
): Promise<TransactionResponse | null> {
try {
const requestPayload: TransactionRequest & { [key: string]: string } = {
to: toAddress,
value: value,
token: tokenSymbol,
chain: chainName,
type: "gasless",
// Authentication parameters
externalId: externalId,
password: password,
};

console.log(
`Sending ${value} ${tokenSymbol} using external ID authentication...`
);
const response = await sphere.transactions.send(requestPayload);

if (response && response.transactionHash) {
console.log("Transaction successful!");
return response;
}
return null;
} catch (error) {
console.error("Error sending transaction:", error);
throw error;
}
}

// Example Usage:
/*
// Send 0.1 USDC on Polygon with email authentication
sendTokensWithEmail(
"0xRecipientWalletAddress...",
"0.1",
TokenSymbol.USDC,
ChainName.POLYGON,
"user@example.com",
"123456" // OTP code received via email
)
.then(response => {
if (response) {
console.log("Transaction complete! View at:", response.transactionHash);
}
})
.catch(err => console.error("Send transaction failed:", err));

// Send with phone authentication
sendTokensWithPhone(
"0xRecipientWalletAddress...",
"1.5",
TokenSymbol.USDT,
ChainName.BASE,
"+1234567890",
"654321" // OTP code received via SMS
);

// Send with external ID authentication
sendTokensWithExternalId(
"0xRecipientWalletAddress...",
"2.0",
TokenSymbol.ETH,
ChainName.ETHEREUM,
"user-external-id-123",
"userSecurePassword"
);
*/

TransactionRequest Parameters with Authentication:

The base TransactionRequest includes:

  • to: string: The recipient's wallet address.
  • value: string: The amount of the token to send, as a string (e.g., "10.5", "0.001").
  • token: TokenSymbol: The symbol of the token being sent (e.g., TokenSymbol.USDC, TokenSymbol.ETH).
  • chain: ChainName: The chain on which the transaction will occur.
  • type?: TransactionType: Optional. Currently, only "gasless" is effectively supported.
  • intent?: "unlock": Optional. Use this if the transaction's purpose is to approve or unlock tokens.

Plus one of these authentication combinations:

  • email: string + otpCode: string: For email-based authentication
  • phoneNumber: string + otpCode: string: For phone-based authentication
  • externalId: string + password: string: For external ID-based authentication

TransactionResponse

The response from a successful send operation includes:

interface TransactionResponse {
message: string; // Status message about the transaction (e.g., "Transaction confirmed!")
transactionHash: string; // Full block explorer URL for the transaction (e.g., "https://etherscan.io/tx/0x...")
}

The transactionHash field contains the complete block explorer URL for your convenience. It automatically points to the appropriate explorer based on the chain used (e.g., Etherscan for Ethereum, PolygonScan for Polygon, BeraScan for Berachain, etc.).

2. Getting Transaction History (sphere.transactions.getHistory)

This method allows you to retrieve a paginated list of past transactions for the authenticated user. The response includes both the transaction data and pagination information for easy navigation through large transaction histories.

Intuition: This is like viewing your bank statement. You can see a list of incoming and outgoing transactions, amounts, and dates.

Flow:

  1. Your application calls sphere.transactions.getHistory(), optionally providing pagination parameters.
  2. The Sphere SDK communicates with the Stratosphere Network, which queries its records for the user's transaction data.
  3. A response containing a list of transactions and pagination information is returned.

Diagram: Getting Transaction History

SDK Usage: Fetching History

async function fetchTransactionHistory(
limit: number = 10,
page: number = 1,
token?: string,
chain?: string
): Promise<TransactionHistoryResponse | null> {
if (!sphere.isAuthenticated()) {
console.error("SDK is not authenticated. Please log in the user first.");
return null;
}

try {
const requestPayload: TransactionHistoryRequest = {
limit: limit,
page: page,
token: token, // Optional: Filter by specific token (e.g., "USDC")
chain: chain, // Optional: Filter by specific chain (e.g., "ethereum")
};

console.log(
`Fetching transaction history (page ${page}, limit ${limit})...`
);
if (token) console.log(` Filtering by token: ${token}`);
if (chain) console.log(` Filtering by chain: ${chain}`);

const response = await sphere.transactions.getHistory(requestPayload);

if (response && response.transactions.length > 0) {
console.log(
`Successfully fetched ${response.transactions.length} transactions:`
);
console.log(
`Pagination: Page ${response.pagination.currentPage} of ${response.pagination.pages} (${response.pagination.total} total)`
);

response.transactions.forEach((tx) => {
console.log(`\n ID: ${tx.id}`);
console.log(` Transaction Hash: ${tx.transactionHash}`);
console.log(` Created: ${new Date(tx.createdAt).toLocaleString()}`);
console.log(` Amount: ${tx.amount} ${tx.token}`);
console.log(` Chain: ${tx.chain}`);
console.log(` To: ${tx.recipientAddress}`);
console.log(` User ID: ${tx.userId}`);
if (tx.currency) {
console.log(` Currency: ${tx.currency}`);
}
});
return response;
} else {
console.log("No transaction history found.");
return {
transactions: [],
pagination: {
total: 0,
pages: 0,
currentPage: page,
perPage: limit,
},
};
}
} catch (error) {
console.error("Error fetching transaction history:", error);
throw error;
}
}

// Example Usage:
/*
// Fetch all transactions
fetchTransactionHistory()
.then(response => {
if (response && response.transactions.length > 0) {
console.log(`Found ${response.transactions.length} transactions`);
console.log(`Total available: ${response.pagination.total}`);
// Update UI with transaction history
}
});

// Fetch USDC transactions on Polygon only
fetchTransactionHistory(20, 1, "USDC", "polygon")
.then(response => {
if (response) {
console.log(`Found ${response.transactions.length} USDC transactions on Polygon`);
console.log(`Page ${response.pagination.currentPage} of ${response.pagination.pages}`);
}
});
*/

TransactionHistoryRequest Parameters:

  • limit?: number: Optional. The number of transactions to return per page.
  • page?: number: Optional. The page number for pagination.
  • token?: string: Optional. Filter results by a specific token (e.g., "USDC", "ETH").
  • chain?: string: Optional. Filter results by a specific chain (e.g., "ethereum", "polygon").

TransactionHistory Structure:

interface TransactionHistory {
id: string; // Unique identifier for the transaction record
userId: string; // ID of the user who made the transaction
transactionHash: string; // The on-chain transaction hash (e.g., "0x123...")
chain: string; // Blockchain network (e.g., "ethereum", "polygon")
token: string; // Token symbol (e.g., "USDC", "ETH")
currency?: string; // Optional currency information
amount: number; // Amount transferred as a number
recipientAddress: string; // The recipient's wallet address
createdAt: string; // ISO 8601 timestamp of when the transaction was created
}

interface TransactionHistoryResponse {
transactions: TransactionHistory[]; // Array of transaction history items
pagination: {
total: number; // Total number of transactions available
pages: number; // Total number of pages
currentPage: number; // Current page number
perPage: number; // Number of transactions per page
};
}

Note: Unlike the send() method which returns the transactionHash as a full explorer URL, the transaction history returns the actual on-chain transaction hash. You can construct explorer URLs from this hash based on the chain if needed.

3. Getting Transaction Fee (sphere.transactions.getFee)

This method allows you to estimate the fee that Sphere will charge for a gasless transaction. This is useful for displaying potential costs to the user before they initiate a transaction. The fee is charged in the token being transferred.

Intuition: This is like asking for a quote for the service fee before committing to a bank transfer. You provide the details of the intended transfer (recipient, amount, token, chain), and the service tells you how much the fee will be in that token.

Flow:

  1. Your application gathers the potential transaction details from the user (recipient, amount, token, chain).
  2. It calls sphere.transactions.getFee() with these details.
  3. The Sphere SDK communicates with the Stratosphere Network, which calculates the estimated fee based on current network conditions and the transaction parameters.
  4. A response is returned with the estimated fee amount and the token in which the fee will be charged.

Diagram: Getting Transaction Fee

SDK Usage: Getting Fee

async function getTransactionFee(
recipientAddress: string,
amountToSend: string,
tokenSymbol: string, // Assuming TokenSymbol enum or similar for consistency, but user provided string
chainName: string // Assuming ChainName enum or similar, but user provided string
): Promise<TransactionFeeResponse | null> {
if (!sphere.isAuthenticated()) {
console.error("SDK is not authenticated. Please log in the user first.");
return null;
}

try {
const requestPayload: TransactionFeeRequest = {
recipient: recipientAddress,
amount: amountToSend,
token: tokenSymbol,
chain: chainName,
};

console.log(
`Fetching fee for sending ${amountToSend} ${tokenSymbol} to ${recipientAddress} on ${chainName}...`
);
const response = await sphere.transactions.getFee(requestPayload); // Assuming sphere.transactions.getFee exists

if (response) {
console.log("Fee estimation successful!");
console.log(" Fee Amount:", response.amount);
console.log(" Fee Token:", response.token);
return response;
} else {
console.error("Failed to get transaction fee. Response was empty.");
return null;
}
} catch (error) {
console.error("Error fetching transaction fee:", error);
throw error; // Re-throw the error so the caller can handle it
}
}

// Example Usage:
/*
getTransactionFee("0xRecipientWalletAddress...", "0.1", "USDC", "polygon")
.then(feeResponse => {
if (feeResponse) {
console.log(`Estimated fee: ${feeResponse.amount} ${feeResponse.token}`);
// Update UI with fee information
}
})
.catch(err => console.error("Get fee failed:", err));
*/

TransactionFeeRequest Parameters:

  • recipient: string: The recipient's wallet address.
  • amount: string: The amount of the token to be sent, as a string (e.g., "10.5", "0.001").
  • token: string: The symbol of the token to be sent (e.g., "USDC", "ETH").
  • chain: string: The chain on which the transaction would occur (e.g., "ethereum", "polygon").

TransactionFeeResponse Structure:

// Transaction Fee Types
export interface TransactionFeeRequest {
recipient: string;
amount: string;
chain: string;
token: string;
}

export interface TransactionFeeResponse {
amount: number; // The estimated fee amount
token: string; // The token in which the fee will be charged (usually the same as the transfer token)
}

Note: The actual method signature within the SDK is async getFee(request: TransactionFeeRequest): Promise<TransactionFeeResponse>. The TransactionFeeRequest and TransactionFeeResponse interfaces shown here are based on your provided types. Ensure these types are correctly defined and exported in your SDK.

Important Considerations

  • Authentication: All methods require an authenticated SDK.
  • Gasless Transactions: For send operations, transactions are processed as gasless. The Stratosphere Network facilitates this, and a fee is charged in the transacted token (see Transaction Fees). Future updates might introduce "normal" transactions where the user pays gas directly.
  • Transaction Explorer URLs: The send() method returns a transactionHash field that contains the full block explorer URL (not just the hash). This URL automatically points to the appropriate explorer for the chain used. The transaction is submitted to the blockchain when you receive the response.
  • History Scope: Transaction history is sourced from Stratosphere Network records and includes pagination information for efficient data retrieval.
  • Error Handling: Implement robust error handling for issues like insufficient balance (after deducting Sphere's fee for gasless), network errors, etc.

Next Steps


For comprehensive details, consult the Sphere SDK API reference or community.