Quickstart - For Wallets & WaaS
Integrate apps into a wallet
1. Install the SDK
npm install universal-portability
2. Set Up Provider
Wrap your application with the UniversalPortabilityProvider:
import { UniversalPortabilityProvider } from 'universal-portability';
function App() {
return (
<WagmiProvider config={wagmiConfig}>
<UniversalPortabilityProvider>
{/* Your app */}
</UniversalPortabilityProvider>
</WagmiProvider>
);
}
3. Implement Message Handlers
Your wallet needs to listen for events from Interspace—such as requests to connect, sign a message, or approve a transaction.
Create these two hooks to handle communication between your wallet and embedded dApps:
src/hooks/useMessageHandler.ts
import { useEffect } from 'react';
import { useUniversalPortability } from 'universal-portability';
import { sendTransaction, signMessage } from '@wagmi/core';
import { config } from '../wagmi';
import { hexToString } from 'viem';
export interface MessageHandlerConfig {
walletAddress: string;
chainId: number;
}
export function useMessageHandler({ walletAddress, chainId }: MessageHandlerConfig) {
const { sendMessageToIFrame } = useUniversalPortability();
useEffect(() => {
const handleMessage = async (event: MessageEvent) => {
const { type, payload, requestId } = event.data;
try {
switch (type) {
case 'INTERSPACE_CONNECT_REQUEST':
sendMessageToIFrame(
{
type: 'INTERSPACE_CONNECT_RESPONSE',
payload: {
address: walletAddress,
chainId,
isConnected: true
}
}
);
break;
case 'SIGN_MESSAGE_REQUEST':
// Handle message signing
break;
case 'TRANSACTION_REQUEST':
// Handle transaction requests
break;
}
} catch (error: any) {
// Error handling
}
};
window.addEventListener('message', handleMessage);
return () => window.removeEventListener('message', handleMessage);
}, [walletAddress, chainId, sendMessageToIFrame]);
}
src/hooks/usePortHandler.ts
import { useAccount, useChainId } from 'wagmi';
import { useMessageHandler } from './useMessageHandler';
export function usePortHandler() {
const { address } = useAccount();
const chainId = useChainId();
useMessageHandler({
walletAddress: address!,
chainId: chainId!
});
return {
isReady: Boolean(address && chainId)
};
}
4. Create dApp Store Container
Interspace can serve as your "dApp store" aggregator. You can display all available apps, letting users pick which to launch. For instance:
import { Port, usePortableApps } from 'universal-portability';
function DAppStoreContainer() {
const { apps } = usePortableApps(); // array of dApp metadata
return (
<div className="dapp-grid">
{apps.map(app => (
<div key={app.id} className="dapp-card">
<img src={app.logo} alt={app.name} />
<h3>{app.name}</h3>
<button onClick={() => navigateToApp(app)}>
Launch {app.name}
</button>
</div>
))}
</div>
);
}
5. Render dApp Interface
When the user selects a dApp, you embed it:
import { Port } from 'universal-portability';
import { useAccount, useChainId } from 'wagmi';
import { usePortHandler } from '../hooks/usePortHandler';
function AppContainer({ app }) {
const rpcURL = process.env.RPC_URL;
const { address } = useAccount();
// enable postMessage communication
usePortHandler();
return (
<Port
src={`https://interspace.fi/apps/${app.slug}`}
address={address}
rpcUrl={rpcURL}
height="400px"
width="800px"
/>
);
}
Message Protocol
The SDK uses a secure postMessage protocol with these main events:
INTERSPACE_CONNECT_REQUEST
: Initial wallet connection requestSIGN_MESSAGE_REQUEST
: Request to sign a messageTRANSACTION_REQUEST
: Request to send a transactionSWITCH_CHAIN_REQUEST
: Request to switch chain*_RESPONSE
: Corresponding response events
All sensitive operations (signing, approvals) are handled by your wallet's existing security infrastructure, ensuring a safe and consistent user experience.
Contact Us
- Email: hello@intersend.io
- Telegram: @erturkarda