Documentation Index
Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Aptos uses the Ed25519 elliptic curve — the same curve as Solana. You derive an Aptos address by hashing the Solana wallet’s public key with SHA3-256 and appending a scheme byte. Transactions use BCS (Binary Canonical Serialization).
| Property | Value |
|---|
| Curve | Ed25519 |
| Root Wallet | Solana |
| Address Format | 0x + SHA3-256 hex (64 chars) |
| Hashing | SHA3-256 |
| Serialization | BCS |
| Smallest Unit | Octas (1 APT = 10^8 octas) |
Dependencies
npm install @aptos-labs/ts-sdk @noble/hashes bs58
Derive Address
Extract the Ed25519 public key from the Solana wallet address, append the single-key scheme byte (0x00), and hash with SHA3-256:
import { sha3_256 } from "@noble/hashes/sha3";
import bs58 from "bs58";
function deriveAptosAddress(solanaAddress: string): string {
const pubkey = bs58.decode(solanaAddress);
const payload = new Uint8Array(33);
payload.set(pubkey, 0);
payload[32] = 0x00; // single-key Ed25519 scheme byte
return "0x" + bytesToHex(sha3_256(payload));
}
Sign a Message
Sign the raw UTF-8 bytes of the message using the Solana wallet:
async function signAptosMessage(message: string): Promise<string> {
const wallet = dynamicClient.wallets.userWallets.find(w => w.chain === "SOL")!;
const messageBytes = new TextEncoder().encode(message);
const { signedMessage } = await dynamicClient.wallets.signMessage({
wallet,
message: bytesToHex(messageBytes),
});
return signedMessage;
}
Sign a Transaction
Use the @aptos-labs/ts-sdk to build the transaction, generate the signing message, and submit with an Ed25519 authenticator:
import {
Aptos, AptosConfig, Network, generateSigningMessageForTransaction,
AccountAuthenticatorEd25519, Ed25519PublicKey, Ed25519Signature,
} from "@aptos-labs/ts-sdk";
import bs58 from "bs58";
const aptos = new Aptos(new AptosConfig({ network: Network.TESTNET }));
async function sendAptosTransfer(
recipient: string,
amountOctas: number,
aptosAddress: string,
): Promise<string> {
const wallet = dynamicClient.wallets.userWallets.find(w => w.chain === "SOL")!;
const pubkeyBytes = bs58.decode(wallet.address);
const transaction = await aptos.transaction.build.simple({
sender: aptosAddress,
data: {
function: "0x1::aptos_account::transfer",
functionArguments: [recipient, amountOctas],
},
});
const signingBytes = generateSigningMessageForTransaction(transaction);
const { signedMessage } = await dynamicClient.wallets.signMessage({
wallet,
message: bytesToHex(signingBytes),
});
const sigBytes = decodeSig(signedMessage);
const authenticator = new AccountAuthenticatorEd25519(
new Ed25519PublicKey(pubkeyBytes),
new Ed25519Signature(bytesToHex(sigBytes)),
);
const { hash } = await aptos.transaction.submit.simple({
transaction,
senderAuthenticator: authenticator,
});
return hash;
}
Verify a Signature
import { ed25519 } from "@noble/curves/ed25519";
import bs58 from "bs58";
function verifyAptosSignature(
message: string,
signature: string,
solanaAddress: string,
): boolean {
const pubkey = bs58.decode(solanaAddress);
const messageBytes = new TextEncoder().encode(message);
const sigBytes = decodeSig(signature);
return ed25519.verify(sigBytes, messageBytes, pubkey);
}
Check Balance
async function getAptosBalance(address: string): Promise<string> {
const BASE = "https://fullnode.testnet.aptoslabs.com/v1";
// Try legacy CoinStore model
try {
const res = await fetch(
`${BASE}/accounts/${address}/resource/0x1::coin::CoinStore%3C0x1::aptos_coin::AptosCoin%3E`,
);
if (res.ok) {
const data = await res.json();
const octas = BigInt(data.data?.coin?.value ?? "0");
if (octas > BigInt(0)) {
return (Number(octas) / 1e8).toFixed(8).replace(/\.?0+$/, "");
}
}
} catch {
// fall through to FA model
}
// Fall back to Fungible Asset model
try {
const res = await fetch(`${BASE}/view`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
function: "0x1::primary_fungible_store::balance",
type_arguments: ["0x1::fungible_asset::Metadata"],
arguments: [address, "0x000000000000000000000000000000000000000000000000000000000000000a"],
}),
});
if (res.ok) {
const data = await res.json();
const octas = BigInt(data[0] ?? "0");
return (Number(octas) / 1e8).toFixed(8).replace(/\.?0+$/, "");
}
} catch {
// ignore
}
return "0";
}
For full implementation details see the JavaScript Aptos guide. The only difference in React Native is the signing call — address derivation, transaction building, and RPC calls are identical.