Specification

Required APIs with Examples and Common Error Codes (Using OKX as Example)

Window Global Variable Name

// Get OKX wallet instance
const okx = (window as any).okxwallet;

// Get wallet API for different networks
const getWalletApi = (network: "livenet" | "testnet") => {
  const networkAttr = {
    livenet: "bitcoin",
    testnet: "bitcoinTestnet",
  };
  return okx[networkAttr[network]];
};

Connect Wallet Method

interface ConnectParams {
  network: "livenet" | "testnet";
  chain?: "BITCOIN_MAINNET" | "BITCOIN_TESTNET" | "BITCOIN_TESTNET4" | "FRACTAL_BITCOIN_MAINNET" | "FRACTAL_BITCOIN_TESTNET";
  handleMismatchChain?: boolean;
}

interface ConnectResult {
  name: "okx";
  network: "livenet" | "testnet";
  publicKey: string;
  accounts: string[];
  address: string;
  btcAddress: string;
  btcPublicKey: string;
  balance?: {
    confirmed?: number;
    total?: number;
    unconfirmed?: number;
  };
  chain?: string;
}

// Connect wallet
const connect = async (params: ConnectParams): Promise<ConnectResult> => {
  const { network, chain, handleMismatchChain } = params;
  const okx = getWalletApi(network);
  
  try {
    const info = await okx.connect();
    const { publicKey, address, compressedPublicKey } = info;
    
    let balance;
    if (network === "livenet") {
      balance = await okx.getBalance();
    }

    return {
      name: "okx",
      network,
      publicKey,
      accounts: [address],
      address,
      btcAddress: address,
      btcPublicKey: compressedPublicKey,
      balance,
      chain,
    };
  } catch (error) {
    throw {
      code: error.code || 1,
      msg: error.msg || error.message || "Connection failed",
      success: false,
    };
  }
};

Disconnect Wallet Method

interface DisconnectParams {
  network: "livenet" | "testnet";
  chain?: string;
  handleMismatchChain?: boolean;
}

const disconnect = async (params: DisconnectParams): Promise<void> => {
  const { network, chain, handleMismatchChain } = params;
  const okx = getWalletApi(network);
  
  try {
    await okx.disconnect();
  } catch (error) {
    throw {
      code: error.code || 1,
      msg: error.msg || error.message || "Disconnect failed",
      success: false,
    };
  }
};

Sign Method

interface SignParams {
  network: "livenet" | "testnet";
  msg: string;
  type?: string;
  chain?: string;
  handleMismatchChain?: boolean;
}

const sign = async (params: SignParams): Promise<string> => {
  const { network, msg, type, chain, handleMismatchChain } = params;
  const okx = getWalletApi(network);
  
  try {
    return await okx.signMessage(msg, type);
  } catch (error) {
    throw {
      code: error.code || 1,
      msg: error.msg || error.message || "Signing failed",
      success: false,
    };
  }
};

Sign PSBT Method

interface SignPsbtParams {
  psbt: string; // PSBT string in base64 or hex format
  option?: {
    autoFinalized: boolean;
    toSignInputs?: {
      index: number;
      address: string;
      publicKey: string;
      sighashTypes: number[];
      disableTweakSigner: boolean;
    }[];
  };
  network: "livenet" | "testnet";
  data: ConnectResult; // Wallet information
  chain?: string;
  handleMismatchChain?: boolean;
}

const signPsbt = async (params: SignPsbtParams): Promise<string> => {
  const { psbt, option, network, data, chain, handleMismatchChain } = params;
  const okx = getWalletApi(network);
  
  try {
    // Convert to hex format
    let handlePsbt = psbt;
    if (!/^[0-9a-fA-F]+$/.test(psbt)) {
      handlePsbt = Psbt.fromBase64(psbt).toHex();
    }
    
    const res = await okx.signPsbt(handlePsbt, {
      ...option,
      autoFinalized: false,
    });
    
    return res;
  } catch (error) {
    throw {
      code: error.code || 1,
      msg: error.msg || error.message || "PSBT signing failed",
      success: false,
    };
  }
};

Send BTC Method

interface SendBitcoinParams {
  from: string; // Sender address
  address: string; // Recipient address
  satoshis: number; // Amount to send (in satoshis)
  option?: {
    feeRate: number; // Fee rate
  };
  network: "livenet" | "testnet";
  chain?: string;
  handleMismatchChain?: boolean;
}

const sendBitcoin = async (params: SendBitcoinParams): Promise<string> => {
  const { from, address, satoshis, option, network, chain, handleMismatchChain } = params;
  const okx = getWalletApi(network);
  
  try {
    const sendOption: any = {
      from,
      to: address,
      value: (satoshis / 100000000).toFixed(8), // Convert to BTC
    };
    
    if (option && option.feeRate) {
      sendOption.fee = option.feeRate;
      sendOption.satBytes = option.feeRate;
    }
    
    const res = await okx.send(sendOption);
    return res.txhash;
  } catch (error) {
    throw {
      code: error.code || 1,
      msg: error.msg || error.message || "Send BTC failed",
      success: false,
    };
  }
};

Sign PSBTs Method

interface SignPsbtsParams {
  psbt: string[]; // Array of PSBT strings
  option?: Array<{
    autoFinalized: boolean;
    toSignInputs?: {
      index: number;
      address: string;
      publicKey: string;
      sighashTypes: number[];
      disableTweakSigner: boolean;
    }[];
  }>;
  network: "livenet" | "testnet";
  chain?: string;
  handleMismatchChain?: boolean;
}

const signPsbts = async (params: SignPsbtsParams): Promise<string[]> => {
  const { psbt, option = [], network, chain, handleMismatchChain } = params;
  const okx = getWalletApi(network);
  
  try {
    const handleOptions = option.length === 0
      ? psbt.map(() => ({ autoFinalized: false }))
      : option.map((item) => ({ ...item, autoFinalized: false }));

    const res = await okx.signPsbts(psbt, handleOptions);
    return res;
  } catch (error) {
    throw {
      code: error.code || 1,
      msg: error.msg || error.message || "Batch PSBT signing failed",
      success: false,
    };
  }
};

Account Switch Monitoring Event

interface WalletInfo {
  name: "okx";
  network: "livenet" | "testnet";
  publicKey: string;
  accounts: string[];
  address: string;
  btcAddress: string;
  btcPublicKey: string;
  balance?: {
    confirmed?: number;
    total?: number;
    unconfirmed?: number;
  };
}

const openMonitorOkx = (
  network: "livenet" | "testnet",
  callback?: (data: WalletInfo) => void,
) => {
  const okx = getWalletApi(network);
  
  okx.on("accountsChanged", async (accounts: string[]) => {
    if (accounts && accounts.length > 0) {
      try {
        const info = await okx.connect();
        const { publicKey, address, compressedPublicKey } = info;
        
        let balance;
        if (network === "livenet") {
          balance = await okx.getBalance();
        }

        callback?.({
          name: "okx",
          network,
          publicKey,
          accounts: [address],
          address,
          btcAddress: address,
          btcPublicKey: compressedPublicKey,
          balance,
        });
      } catch (error) {
        console.error("Account switch monitoring failed:", error);
      }
    }
  });
};

Last updated

Was this helpful?