Understand how the DropFi web extension injects the window.xrpl provider into web pages. This script enables DApps to communicate with the DropFi browser extension.
How window.xrpl is injected into web pages
Uses window.postMessage to communicate with the extension
Implements event listeners for wallet state changes
All methods return promises for async operations
Maintains wallet state including address, network, and accounts
(function () {
const XRPLProvider = {
isDropFi: true,
selectedAddress: null,
selectedNetwork: null,
connectedAccounts: [],
network: null,
endpoint: null,
listeners: {},
resolvers: {},
_emit(event, payload) {
(this.listeners[event] || []).forEach((fn) => fn(payload));
},
on(event, cb) {
this.listeners[event] = this.listeners[event] || [];
this.listeners[event].push(cb);
},
off(event, cb) {
if (!this.listeners[event]) return;
this.listeners[event] = this.listeners[event].filter((fn) => fn !== cb);
},
createXRPLPromise(method, data = {}) {
return new Promise((resolve) => {
this.resolvers[method] = (result) => {
if (method === 'xrpl_stateRequest' && result) {
this.selectedAddress = result.selectedAddress;
this.connectedAccounts = result.connectedAccounts;
this.network = result.network;
this.endpoint = result.endpoint;
this._emit('xrpl_selectedAddress', result.selectedAddress);
this._emit('xrpl_connectedAccounts', result.connectedAccounts);
this._emit('xrpl_selectedNetwork', result.network);
} else if (method === 'xrpl_connect' && result) {
this.selectedAddress = result;
this.connectedAccounts = [result];
this._emit('xrpl_selectedAddress', result);
this._emit('xrpl_connectedAccounts', [result]);
} else if (method === 'xrpl_disconnect') {
const old = this.selectedAddress;
this.selectedAddress = null;
this.connectedAccounts = [];
this._emit('xrpl_selectedAddress', null);
this._emit('xrpl_connectedAccounts', []);
this._emit('xrpl_disconnect', old);
} else if (method === 'xrpl_switchNetwork' && result) {
this.network = result.network;
this.endpoint = result.endpoint;
this._emit('xrpl_selectedNetwork', result.network);
}
resolve(result);
};
this.sendToHost(method, data);
});
},
sendToHost(method, params) {
window.postMessage(
{
source: 'xrpl-injected',
method,
params,
},
'*',
);
},
handleHostResponse(message) {
if (message?.source !== 'xrpl-content-script') return;
const { type, payload } = message;
const resolverMap = {
CONNECT_WALLET_RESPONSE: 'xrpl_connect',
SIGN_MESSAGE_RESPONSE: 'xrpl_signMessage',
SEND_TRANSACTION_RESPONSE: 'xrpl_sendTransaction',
DISCONNECT_RESPONSE: 'xrpl_disconnect',
SWITCH_NETWORK_RESPONSE: 'xrpl_switchNetwork',
CHANGE_ACCOUNT_RESPONSE: 'xrpl_changeAccount',
XRPL_INITIALIZE_RESPONSE: 'xrpl_stateRequest',
};
const methodKey = resolverMap[type];
if (methodKey && this.resolvers[methodKey]) {
this.resolvers[methodKey](payload);
}
},
// Public Methods
connect: (data) => XRPLProvider.createXRPLPromise('xrpl_connect', { data }),
disconnect: (address) => XRPLProvider.createXRPLPromise('xrpl_disconnect', { address }),
signMessage: (message) => XRPLProvider.createXRPLPromise('xrpl_signMessage', { message }),
sendTransaction: (tx) => XRPLProvider.createXRPLPromise('xrpl_sendTransaction', { tx }),
switchNetwork: (networkId) => XRPLProvider.createXRPLPromise('xrpl_switchNetwork', { networkId }),
changeAccount: (account) => XRPLProvider.createXRPLPromise('xrpl_changeAccount', { account }),
initialize: () => XRPLProvider.createXRPLPromise('xrpl_stateRequest'),
isConnected: () => !!XRPLProvider.selectedAddress,
};
window.addEventListener('message', (event) => {
if (event.source !== window) return;
XRPLProvider.handleHostResponse(event.data);
});
// Inject provider
window.xrpl = XRPLProvider;
})();The main provider object that implements the window.xrpl API
Contains state properties (selectedAddress, network, etc.) and methods for wallet interaction
Implements on/off/_emit for event-driven communication
Allows DApps to listen for wallet state changes like address changes or network switches
createXRPLPromise creates promises that resolve when the extension responds
Each method (connect, disconnect, etc.) uses this pattern to handle async communication
sendToHost and handleHostResponse manage communication with the extension
Uses window.postMessage to send requests and listens for responses from the content script
Automatically updates internal state when responses are received
Updates selectedAddress, connectedAccounts, network, and endpoint based on extension responses
DApp calls window.xrpl.connect() → createXRPLPromise → sendToHost → window.postMessage → Extension receives message
Extension sends response → window.addEventListener receives → handleHostResponse → resolver called → Promise resolves
When state changes, _emit is called to notify all registered event listeners
connect(data)Initiates connection to DropFi wallet
Parameters: data: object (optional) - returns Promise<string>
disconnect(address)Disconnects from the wallet
Parameters: address: string (optional) - returns Promise<void>
signMessage(message)Signs a message using the connected wallet
Parameters: message: string - returns Promise<string>
sendTransaction(tx)Sends a transaction to the XRP Ledger
Parameters: tx: object - returns Promise<string>
switchNetwork(networkId)Switches the active network
Parameters: networkId: string - returns Promise<object>
changeAccount(account)Changes the active account
Parameters: account: string - returns Promise<void>
initialize()Initializes and requests current wallet state
Parameters: None - returns Promise<object>
isConnected()Checks if wallet is currently connected
Parameters: None - returns boolean
// Listen for address changes
window.xrpl.on('xrpl_selectedAddress', (address) => {
console.log('Address changed:', address);
});
// Listen for network changes
window.xrpl.on('xrpl_selectedNetwork', (network) => {
console.log('Network changed:', network);
});
// Listen for disconnect events
window.xrpl.on('xrpl_disconnect', (oldAddress) => {
console.log('Disconnected from:', oldAddress);
});
// Remove event listener
const handler = (address) => console.log(address);
window.xrpl.on('xrpl_selectedAddress', handler);
window.xrpl.off('xrpl_selectedAddress', handler);