DropFi Web Injection Script

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.

Overview

DropFi Web Injection Script

How window.xrpl is injected into web pages

The DropFi web injection script is automatically injected into web pages by the DropFi browser extension. This script creates the `window.xrpl` object that DApps use to interact with the DropFi wallet. The script uses `window.postMessage` to communicate with the extension's content script.

PostMessage Communication

Uses window.postMessage to communicate with the extension

Event-Driven Architecture

Implements event listeners for wallet state changes

Promise-Based API

All methods return promises for async operations

State Management

Maintains wallet state including address, network, and accounts

Complete Injection Script

Here is the complete web injection script that gets injected into web pages:

DropFi Web Injection Script

(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;
})();

Key Components

The injection script consists of several key components:
1

XRPLProvider Object

The main provider object that implements the window.xrpl API

Contains state properties (selectedAddress, network, etc.) and methods for wallet interaction

2

Event System

Implements on/off/_emit for event-driven communication

Allows DApps to listen for wallet state changes like address changes or network switches

3

Promise-Based Methods

createXRPLPromise creates promises that resolve when the extension responds

Each method (connect, disconnect, etc.) uses this pattern to handle async communication

4

Message Passing

sendToHost and handleHostResponse manage communication with the extension

Uses window.postMessage to send requests and listens for responses from the content script

5

State Synchronization

Automatically updates internal state when responses are received

Updates selectedAddress, connectedAccounts, network, and endpoint based on extension responses

Communication Flow

Understanding how the script communicates with the DropFi extension:

Request Flow

DApp calls window.xrpl.connect() → createXRPLPromise → sendToHost → window.postMessage → Extension receives message

Response Flow

Extension sends response → window.addEventListener receives → handleHostResponse → resolver called → Promise resolves

Event Emission

When state changes, _emit is called to notify all registered event listeners

Public API Methods

The window.xrpl object exposes the following public methods:
POST
connect(data)

Initiates connection to DropFi wallet

Parameters: data: object (optional) - returns Promise<string>

POST
disconnect(address)

Disconnects from the wallet

Parameters: address: string (optional) - returns Promise<void>

POST
signMessage(message)

Signs a message using the connected wallet

Parameters: message: string - returns Promise<string>

POST
sendTransaction(tx)

Sends a transaction to the XRP Ledger

Parameters: tx: object - returns Promise<string>

POST
switchNetwork(networkId)

Switches the active network

Parameters: networkId: string - returns Promise<object>

POST
changeAccount(account)

Changes the active account

Parameters: account: string - returns Promise<void>

GET
initialize()

Initializes and requests current wallet state

Parameters: None - returns Promise<object>

GET
isConnected()

Checks if wallet is currently connected

Parameters: None - returns boolean

Event System

The injection script supports an event system for listening to wallet state changes:

Event Usage Example

// 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);
Available events: xrpl_selectedAddress, xrpl_connectedAccounts, xrpl_selectedNetwork, xrpl_disconnect

On This Page

Select a documentation page to see its table of contents