dApp Integration
Altitude Wallet exposes a standard Ethereum provider to every web page. It implements the EIP-1193 JavaScript provider API and announces itself through EIP-6963 multi-wallet discovery. A TronLink-compatible surface is also injected for TRON dApps.
No SDK installation is required — the provider is injected automatically by the extension's content script.
How It Works
Altitude Wallet injects an inpage script into every page at document_start. The inpage script registers window.ethereum, window.tronLink, and window.tronWeb, then communicates with the content script through window.postMessage. The content script opens a persistent browser.runtime.connect Port to the background service worker, which routes dApp requests, manages site permissions, and opens a confirmation popup when user approval is required.
Your dApp Inpage Script Content Script Background Worker
│ │ │ │
│ window.ethereum │ │ │
│ .request(...) │ │ │
│ ──────────────────────> │ │ │
│ │ window.postMessage │ │
│ │ ──────────────────────> │ │
│ │ │ runtime.connect Port │
│ │ │ ──────────────────────> │
│ │ │ │
│ │ │ Open popup
│ │ │ for approval
│ │ │ │
│ │ │ <──────────────────────│
│ │ <──────────────────────│ │
│ <───────────────────── │ │ │
│ Promise resolves │ │ │
All provider methods return a Promise. Every internal request carries a unique id so responses are correlated correctly.
EIP-1193 Provider
The provider is available on window.ethereum.
Connect Wallet
const accounts = await window.ethereum.request({
method: 'eth_requestAccounts',
});
console.log('Connected address:', accounts[0]);
If the wallet is locked or the site has not been connected before, Altitude Wallet opens a confirmation popup where the user can unlock and approve access.
Get Chain ID
const chainId = await window.ethereum.request({
method: 'eth_chainId',
});
console.log('Current chain:', chainId); // e.g. "0x1"
Get Connected Accounts
const accounts = await window.ethereum.request({
method: 'eth_accounts',
});
Switch Chain
await window.ethereum.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: '0x1' }],
});
Only the chain currently selected inside the wallet is considered available. Switching to an unsupported chain returns EIP-1193 error 4902.
Read-Only RPC Calls
Read methods are forwarded to the configured RPC endpoint without user confirmation:
const blockNumber = await window.ethereum.request({
method: 'eth_blockNumber',
});
Examples of read-only methods: eth_blockNumber, eth_call, eth_getBalance, eth_getTransactionReceipt, eth_gasPrice, eth_estimateGas, net_version, eth_getCode, eth_getStorageAt.
Events
window.ethereum.on('accountsChanged', (accounts) => {
console.log('Accounts changed:', accounts);
});
window.ethereum.on('chainChanged', (chainId) => {
console.log('Chain changed:', chainId);
});
window.ethereum.on('connect', (info) => {
console.log('Connected:', info.chainId);
});
window.ethereum.on('disconnect', (error) => {
console.log('Disconnected:', error);
});
Errors
Errors returned by request() follow the EIP-1193 error shape:
interface ProviderError extends Error {
code: number;
data?: unknown;
}
| Code | Name | Typical cause |
|---|---|---|
| 4001 | User Rejected Request | The user rejected the request in the popup |
| 4100 | Unauthorized | The requested account is not authorized for this origin |
| 4200 | Unsupported Method | The method is not implemented |
| 4900 | Disconnected | The provider is disconnected from the current chain |
| 4901 | Chain Disconnected | The provider is disconnected from the requested chain |
| 4902 | Chain Unavailable | The requested chain is not available in the wallet |
| -32602 | Invalid Params | Malformed method parameters |
| -32603 | Internal Error | Unexpected error inside the wallet |
EIP-6963 Multi-Wallet Discovery
Altitude Wallet announces itself through the standard eip6963:announceProvider event.
window.addEventListener('eip6963:announceProvider', (event) => {
const { info, provider } = event.detail;
if (info.rdns === 'io.altitude.wallet') {
console.log('Altitude Wallet discovered:', info.name);
// Use provider as your EIP-1193 provider
}
});
window.dispatchEvent(new Event('eip6963:requestProvider'));
Announcements are emitted once immediately and again whenever another dApp requests providers.
TRON Provider
Altitude Wallet injects a TronLink-compatible surface on both window.tronLink and window.tronWeb. The structure mirrors the real TronLink extension, so libraries like @tronweb3/tronwallet-adapters (TronLinkAdapter) work without any special configuration.
Connect Wallet
// Request account access — returns the TRON address (base58)
const accounts = await window.tronLink.request({ method: 'tron_requestAccounts' });
console.log('Connected TRON address:', accounts[0]); // e.g. "T..."
After a successful tron_requestAccounts, the address is automatically available on tronWeb:
window.tronWeb.defaultAddress.base58; // "T..."
window.tronLink.tronWeb.defaultAddress.base58; // same — shared instance
Sign Transaction / Message
// Sign a TRON transaction
const signedTx = await window.tronWeb.trx.sign(transaction);
// Sign a message (TronLink-compatible)
const signature = await window.tronWeb.trx.signMessageV2('Hello TRON');
Signing requires user approval in the confirmation popup.
Multi-Chain Behavior
Altitude Wallet is a multi-chain wallet. The protocol used to connect determines which address is returned:
| Call | Network switched to | Address returned |
|---|---|---|
eth_requestAccounts | Ethereum (EVM) | 0x... (EVM) |
tron_requestAccounts | TRON | T... (base58) |
The wallet automatically switches the active network when a connect request is received. EVM and TRON accounts are stored independently per origin, so a dApp that connects via both protocols receives the correct address for each.
Supported Methods (Feature Set 1)
The following methods are supported by the current implementation:
| Method | Behavior |
|---|---|
eth_requestAccounts | Opens connect confirmation; returns authorized addresses |
eth_accounts | Returns previously authorized addresses for this origin |
eth_chainId | Returns the chain ID selected in the wallet |
wallet_switchEthereumChain | Returns null if the chain is selected; otherwise 4902 |
Read-only eth_* / net_* | Forwarded to RPC without confirmation |
tron_requestAccounts | TRON connect; returns TRON address (T...); auto-switches to TRON network |
tron_signTransaction | TRON transaction signing via tronWeb.trx.sign |
Methods such as eth_sendTransaction, personal_sign, and eth_signTypedData_v4 are reserved for upcoming features.
Legacy window.postMessage API
The original Altitude Wallet dApp API based on window.postMessage messages ALTITUDE_WALLET_CONNECT and ALTITUDE_WALLET_SEND_TO remains supported for backward compatibility. New integrations should prefer the EIP-1193 provider described above.
Connect Wallet
const id = crypto.randomUUID();
window.postMessage(
{
type: 'ALTITUDE_WALLET_CONNECT',
id,
},
'*'
);
The extension responds with a message of type ALTITUDE_WALLET_CONNECT_RESPONSE:
window.addEventListener('message', (event) => {
if (event.source !== window) return;
const { type, id: responseId, result, error } = event.data;
if (type === 'ALTITUDE_WALLET_CONNECT_RESPONSE' && responseId === id) {
if (error) {
console.error('Connection rejected:', error);
return;
}
console.log('Connected address:', result.address);
}
});
Send Tokens
const id = crypto.randomUUID();
window.postMessage(
{
type: 'ALTITUDE_WALLET_SEND_TO',
id,
data: {
token: {
chainId: 1,
address: '0x0000000000000000000000000000000000000000',
name: 'Ether',
symbol: 'ETH',
decimals: 18,
logoURI: 'https://assets.coingecko.com/coins/images/279/small/ethereum.png',
nativeToken: true,
},
amount: {
value: 0.001,
fiat: 2,
},
recipientAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
},
},
'*'
);
Legacy Data Types
Token
| Field | Type | Required | Description |
|---|---|---|---|
chainId | number | Yes | EVM chain ID (e.g. 1 for Ethereum, 8453 for Base) |
address | string | Yes | Token contract address. Use the zero address for native tokens |
name | string | Yes | Human-readable token name |
symbol | string | Yes | Token ticker symbol (e.g. ETH, USDC) |
decimals | number | Yes | Token decimals (18 for most ERC-20 tokens) |
logoURI | string | Yes | URL to the token icon |
nativeToken | boolean | No | Set to true for the chain's native gas token |
Amount
| Field | Type | Required | Description |
|---|---|---|---|
value | number | Yes | Amount in human-readable units (e.g. 0.001) |
fiat | number | No | USD-equivalent value for display purposes |
Recipient
| Field | Type | Required | Description |
|---|---|---|---|
recipientAddress | string | Yes | Valid EVM address (0x...) |
Complete Example
A minimal integration using the standard EIP-1193 provider:
<!DOCTYPE html>
<html>
<head>
<title>dApp Example</title>
</head>
<body>
<button id="connect">Connect Wallet</button>
<button id="chainId" disabled>Get Chain ID</button>
<script>
const provider = window.ethereum;
document.getElementById('connect').addEventListener('click', async () => {
try {
const accounts = await provider.request({ method: 'eth_requestAccounts' });
console.log('Connected:', accounts[0]);
document.getElementById('chainId').disabled = false;
} catch (err) {
console.error('Connection rejected:', err);
}
});
document.getElementById('chainId').addEventListener('click', async () => {
try {
const chainId = await provider.request({ method: 'eth_chainId' });
console.log('Chain ID:', chainId);
} catch (err) {
console.error(err);
}
});
provider.on('accountsChanged', (accounts) => {
console.log('Accounts changed:', accounts);
});
provider.on('chainChanged', (chainId) => {
console.log('Chain changed:', chainId);
});
</script>
</body>
</html>
RainbowKit + wagmi Integration
RainbowKit v2 supports EIP-6963 multi-wallet discovery out of the box. Altitude Wallet will appear in the wallet selection modal automatically no requires any setup.
npm install @rainbow-me/rainbow-kit wagmi viem @tanstack/react-query
import '@rainbow-me/rainbow-kit/styles.css';
import { WagmiProvider } from 'wagmi';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { RainbowKitProvider } from '@rainbow-me/rainbow-kit';
const queryClient = new QueryClient();
function App() {
return (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<RainbowKitProvider>
<YourApp />
</RainbowKitProvider>
</QueryClientProvider>
</WagmiProvider>
);
}
Altitude Wallet is automatically appear in the "Connect Wallet" modal via EIP-6963 — No additional configuration is required.
wagmi Configuration
import { http, createConfig } from 'wagmi';
import { mainnet, sepolia, base } from 'wagmi/chains';
export const config = createConfig({
chains: [mainnet, sepolia, base],
transports: {
[mainnet.id]: http(),
[sepolia.id]: http(),
[base.id]: http(),
},
// EIP-6963 is enabled by default in wagmi v2
multiInjectedProviderDiscovery: true,
});
When multiInjectedProviderDiscovery is true (default), wagmi automatically discovers all EIP-6963 providers including Altitude Wallet. The wallet will appear in RainbowKit's selection modal alongside MetaMask and other wallets.
Web3Modal
import { createWeb3Modal } from '@web3modal/wagmi/react';
import { mainnet, sepolia, base } from 'wagmi/chains';
const modal = createWeb3Modal({
wagmiConfig: config,
projectId: 'YOUR_PROJECT_ID',
chains: [mainnet, sepolia, base],
// EIP-6963 wallets appear automatically
});
TypeScript Definitions
For projects using TypeScript, the following interfaces describe the provider surface:
interface Eip1193Provider {
request(args: { method: string; params?: unknown[] }): Promise<unknown>;
on(event: string, listener: (...args: unknown[]) => void): void;
removeListener(event: string, listener: (...args: unknown[]) => void): void;
}
interface ProviderError extends Error {
code: number;
data?: unknown;
}
interface Eip6963ProviderInfo {
uuid: string;
name: string;
icon: string;
rdns: string;
}
interface Eip6963AnnounceProviderEvent extends CustomEvent {
detail: {
info: Eip6963ProviderInfo;
provider: Eip1193Provider;
};
}
interface TronWebLike {
defaultAddress: { base58?: string; hex?: string };
trx: {
sign(transaction: unknown): Promise<unknown>;
signMessageV2(message: string): Promise<string>;
};
address: { toHex(base58: string): string };
}
declare global {
interface Window {
ethereum?: Eip1193Provider & { providers?: Eip1193Provider[] };
tronLink?: {
ready: boolean;
tronWeb: TronWebLike;
request(args: { method: string; params?: unknown[] }): Promise<unknown>;
};
tronWeb?: TronWebLike;
}
}
Security Notes
- User confirmation required —
eth_requestAccounts,wallet_switchEthereumChain, TRON signing, and the legacysendToflow open a visible popup. The user must explicitly approve before any data is returned or any transaction is signed. - No silent signing — There is no way to sign a transaction or message without a user actively confirming it in the popup.
- Origin-scoped permissions — Connected accounts are stored per origin. A dApp can only read accounts it has been authorized to access.
- Protocol-isolated accounts — EVM and TRON accounts are stored independently per origin. A dApp connecting via
eth_requestAccountsalways receives the EVM address;tron_requestAccountsalways receives the TRON address. - Deduplicated, time-bounded connect requests — If the same origin calls
eth_requestAccountsortron_requestAccountsmultiple times concurrently (e.g. an auto-reconnect effect racing with a user click), every call shares a single confirmation popup and resolves to the same result rather than opening duplicate windows. If the user never responds, the request rejects with a timeout error after 2 minutes instead of hanging indefinitely. - Extension must be installed — The inpage script is injected by the browser extension. Without it,
window.ethereumand the legacywindow.postMessagebridge are not available.