@megaeth-labs/wallet-sdk
v1.0.7
Published
MegaETH Wallet SDK for web applications
Readme
MOSS Wallet SDK
Contents
- Install
- Initialize
- Connection Management
- Authentication
- Transfers
- Smart Contract Interactions
- Session Keys & Permissions
- Message Signing
- Wallet Information
- Event Handling
- Testing Locally
- Publishing
Install
npm install @megaeth-labs/wallet-sdk
A React Hooks version is also availale as @megaeth-labs/wallet-sdk-react
Types for all requests and responses can be found at src/types.ts
Initialize
Sets up the iFrame-based wallet. Resolves when the wallet is ready.
import { mega } from '@megaeth-labs/wallet-sdk';
await mega.initialise({
network: 'mainnet', // or 'testnet'
logging: 'error', // Optional: 'debug' | 'info' | 'warn' | 'error'
debug: false, // Optional: Enable internal verbose debug logging
sponsorUrl: 'https://your-sponsor-url.com', // Optional: Custom sponsor URL - see Sponsoring
sponsorMode: 'app-only', // Optional: 'everything' | 'app-only' | 'explicit'
sponsorToken: 'native', // Optional: 'native' | 'usdm'
});Connection Management
Connect Wallet
Shows the connection UI and resolves when the user connects or cancels.
const { status, address } = await mega.connect();
if (status === 'connected') {
console.log('Wallet connected:', address);
}Check Status
Get the current connection status without prompting the user.
const { status, address } = await mega.status();Disconnect
Disconnect the current wallet session.
const result = await mega.disconnect();
console.log('Disconnected:', result.status);Authentication
Authenticate with SIWE
Shows the built-in Sign-In with Ethereum (SIWE) UI. Returns a JWT that can be verified at https://wallet-api.megaeth.com/v1/partner-auth/verify?origin=YOUR_ORIGIN&jwt=JWT_TOKEN
const auth = await mega.authenticate();
if (auth.status === 'success' && auth.jwt) {
const response = await fetch(
`https://wallet-api.megaeth.com/v1/partner-auth/verify?origin=${window.location.host}&jwt=${auth.jwt}`
);
const { walletAddress } = await response.json();
}Transfers
Native Token Transfer (ETH)
Transfer native tokens from the connected wallet.
import { parseEther } from 'viem';
const result = await mega.transfer({
type: 'native',
to: '0xRecipientAddress',
amount: parseEther('0.1').toString(),
sponsor: false, // Optional: Use sponsored transactions when sponsor mode is explict
});
if (result.status === 'approved') {
console.log('Transaction hash:', result.receipt.hash);
}ERC20 Token Transfer
Transfer ERC20 tokens.
import { parseUnits } from 'viem';
const result = await mega.transfer({
type: 'erc20',
to: '0xRecipientAddress',
amount: parseUnits('100', 18).toString(), // 100 tokens with 18 decimals
contractAddress: '0xTokenContractAddress',
});ERC721 NFT Transfer
Transfer an ERC721 NFT.
const result = await mega.transfer({
type: 'erc721',
to: '0xRecipientAddress',
contractAddress: '0xNFTContractAddress',
tokenId: 1234,
amount: '0',
});ERC1155 Token Transfer
Transfer ERC1155 tokens.
const result = await mega.transfer({
type: 'erc1155',
to: '0xRecipientAddress',
contractAddress: '0xTokenContractAddress',
tokenId: 1,
amount: '5', // Number of tokens to transfer
});Smart Contract Interactions
Call Contract Method
Execute a contract method with user approval.
const result = await mega.callContract({
address: '0xContractAddress',
abi: contractABI,
functionName: 'mint',
args: [parseEther('1')],
value: parseEther('0.1'), // Optional: ETH value to send
sponsor: false, // Optional: Use sponsored transactions when sponsor mode is explict
});
if (result.status === 'approved') {
console.log('Transaction hash:', result.receipt.hash);
}Call Contract Method (Large Payload)
If you are calling a contract method with a large payload (e.g. deploying a contract via a factory), you can override the default max gas spending limit.
const result = await mega.callContract({
address: '0xContractAddress',
abi: contractABI,
functionName: 'deplosy',
args: [],
maxGasAllowance: parseEther('0.0005')
});
if (result.status === 'approved') {
console.log('Transaction hash:', result.receipt.hash);
}Silent Contract Call (Session Keys)
Execute a contract method silently using session key permissions (no user approval required).
const result = await mega.callContract({
address: '0xContractAddress',
abi: contractABI,
functionName: 'claim',
args: [],
silent: true, // Uses session key with pre-approved permissions
});Batch Contract Calls
Execute multiple contract calls in a single transaction.
const result = await mega.callContract([
{
address: '0xContract1',
abi: abi1,
functionName: 'approve',
args: ['0xSpender', parseEther('100')],
},
{
address: '0xContract2',
abi: abi2,
functionName: 'swap',
args: [parseEther('100')],
},
]);Call Contract with Raw Data
Execute a contract call using raw calldata instead of ABI.
const result = await mega.callContract({
address: '0xContractAddress',
data: '0x...' as `0x${string}`,
value: parseEther('0.1'),
});Read from Contract (No Gas)
Read data from a contract without creating a transaction.
const balance = await mega.getFromContract<bigint>({
address: '0xTokenContract',
abi: erc20ABI,
functionName: 'balanceOf',
args: ['0xUserAddress'],
});
console.log('Balance:', balance.toString());Session Keys & Permissions
Grant Permissions
Grant session key permissions for silent transactions. Users approve once, then your app can execute permitted transactions without additional prompts.
import { parseEther } from 'viem';
const result = await mega.grantPermissions({
permissions: {
expiry: 86400, // Expiry in seconds (24 hours)
permissions: {
// Specific contract calls allowed
calls: [
{
to: '0xContractAddress',
signature: 'mint(uint256)', // Function signature
},
{
to: '0xAnotherContract',
signature: 'claim()',
},
],
// Spending limits for tokens
spend: [
{
limit: parseEther('100'), // 100 ETH
period: 'day', // 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year'
token: undefined, // undefined for native ETH
},
{
limit: parseEther('1000'), // 1000 tokens
period: 'week',
token: '0xTokenAddress' as `0x${string}`,
},
],
},
},
externalAddress: '0xYourAppAddress', // Optional: External address for permissions if sending from another wallet (e.g. from your API)
sponsor: false, // Optional: Sponsor the permission grant transaction when sponsor mode is explicit
append: false, // Optional (default false): see "Re-granting permissions" below
});
if (result.status === 'approved') {
console.log('Permissions granted');
}Re-granting permissions
Spend allowances are tracked on-chain per session key, so what happens when you call
grantPermissions again for a user who already has a session depends on append:
| append | Behaviour |
| --- | --- |
| false (default) | Mints a new session key and revokes the previous one in the same transaction. The requested spend limits start from zero — nothing spent under the old key counts against them. |
| true | Re-authorizes the existing session key. The requested limits are applied on top of it, so spend already made in the current period still counts against the new allowance. |
Use the default when a re-grant should give the user a clean allowance (for example, topping a
player back up to a fresh daily limit). Use append: true when you are only widening an existing
session — adding another contract to calls, or extending the expiry — and want the current
spend accounting to carry over.
// Add a contract to the session the user already approved, keeping their spend history.
await mega.grantPermissions({
append: true,
permissions: {
expiry: 86400,
permissions: {
calls: [{ to: '0xNewContract', signature: 'claim()' }],
spend: [],
},
},
});append is ignored when externalAddress is set — that key is identified by the address you
supply, so there is no new key to mint.
Get Current Permissions
Check what permissions are currently active for an address.
const perms = await mega.getPermissions('0xUserAddress'); // Optional: address parameter
if (perms?.permissions) {
console.log('Expiry:', new Date(perms.permissions.expiry * 1000));
console.log('Allowed calls:', perms.permissions.permissions.calls);
console.log('Spending limits:', perms.permissions.permissions.spend);
}Revoke Permissions
Revoke all active session key permissions.
await mega.revokePermissions();
console.log('All permissions revoked');Message Signing
Sign Message
Request the user to sign a message.
const result = await mega.signMessage('Hello, World!');
if (result.status === 'success' && result.signature) {
console.log('Signature:', result.signature);
}Sign Structured Data (EIP-712)
Sign typed structured data.
const domain = {
name: 'MyApp',
version: '1',
chainId: 1,
verifyingContract: '0xContract',
};
const types = {
Person: [
{ name: 'name', type: 'string' },
{ name: 'wallet', type: 'address' },
],
};
const value = {
name: 'Alice',
wallet: '0x...',
};
const result = await mega.signData({
data: { domain, types, value },
});
if (result.status === 'success' && result.signature) {
console.log('Signature:', result.signature);
}Verifying Messages
For SIWE messages, the @megaeth-labss/wallet-server-verify package can be used to verify the signature.
For other messages or for more control, the following code can be used:
import { PersonalMessage } from 'ox';
import { Porto, RelayActions } from 'porto';
import { RelayClient } from 'porto/viem';
import { http, toBytes } from 'viem';
import { megaeth, megaethTestnet } from 'viem/chains';
const message = 'Hello';
const address = '0x...';
const signature = '0x...';
const chainId = 4326;
const porto = Porto.create({
relay: http('https://wallet-relay.megaeth.com'),
chains: [megaeth, megaethTestnet],
});
const client = RelayClient.fromPorto(porto, {
chainId
});
const result = await RelayActions.verifySignature(client, {
address,
digest: PersonalMessage.getSignPayload(toBytes(message)),
signature
});
if(!result.valid) {
throw new Error('Invalid Signature');
}Wallet Information
Get Token Balances
Retrieve the user's token balances.
// Get all tokens
const allBalances = await mega.balances({});
// Get specific tokens
const specificBalances = await mega.balances({
tokens: ['0xTokenAddress1', '0xTokenAddress2'],
});
specificBalances.forEach(token => {
console.log(`${token.symbol}: ${token.displayBalance}`);
console.log(`USD Value: $${token.usdBalance}`);
});Open Wallet UI
Open the wallet interface for the user.
await mega.open();Deposit Funds
Show the deposit UI to help users fund their wallet.
await mega.deposit();Event Handling
Listen to wallet events for real-time updates.
// Listen for status changes
mega.events.on('statusChange', ({ status, address }) => {
console.log('Status changed:', status, address);
});
// Stop listening
const unsubscribe = mega.events.on('statusChange', handler);
unsubscribe(); // Call to remove listenerTesting Locally
- Link locally:
pnpm link - Run build with watch:
pnpm dev - In another project run:
pnpm link @megaeth-labs/wallet-sdk - Restart the other project dev server to ensure the link is working
Caution: A pnpm workspace file will be created in the other project. Make sure to remove this file and run pnpm i before committing otherwise CI will fail.
Publishing
- Create a PR
- Merge to
main - When ready, open GitHub and click Run Workflow on the
Publish to npmjob https://github.com/megaeth-labs/wallet-sdk/actions/workflows/publish.yml
