Skip to main content
The IXO Protocol bonds module provides universal token bonding-curve functions to mint, burn, swap, and settle bonds. Bonds price their tokens via a bonding curve (function_type and function_parameters), accept one or more reserve_tokens, and pass through a lifecycle of HATCH → OPEN → SETTLE (or FAILED). Alpha bonds add risk-adjustment via the oracle_did-controlled MsgSetNextAlpha.

Before you start

You need:
  • An IXO account with sufficient uixo for fees on the network you target — see Networks and endpoints.
  • An offline signer — see the SDK README on creating signers.
  • For MsgCreateBond: a controller DID, a creator DID, optional oracle DID for alpha bonds, and reserve token denoms.
  • For MsgWithdrawReserve: the bond’s allow_reserve_withdrawals flag must be true.
npm install @ixo/impactxclient-sdk
import { ixo, createSigningClient } from "@ixo/impactxclient-sdk";

const signingClient = await createSigningClient(RPC_ENDPOINT, offlineSigner);

Create a bond

const createBondMsg = {
  typeUrl: "/ixo.bonds.v1beta1.MsgCreateBond",
  value: ixo.bonds.v1beta1.MsgCreateBond.fromPartial({
    bondDid: "did:ixo:bond:abc123",
    token: "BOND",
    name: "Solar Farm Alpha Bond",
    description: "Outcome-linked bond for verified solar production",
    functionType: "augmented_function",
    functionParameters: [
      ixo.bonds.v1beta1.FunctionParam.fromPartial({ param: "p0", value: "1" }),
    ],
    creatorDid: "did:ixo:creator123",
    controllerDid: "did:ixo:controller123",
    oracleDid: "did:ixo:oracle123",
    reserveTokens: ["uixo"],
    txFeePercentage: "0.5",
    exitFeePercentage: "1.0",
    feeAddress: feeAddress,
    reserveWithdrawalAddress: reserveAddress,
    maxSupply: { denom: "BOND", amount: "1000000" },
    orderQuantityLimits: [],
    sanityRate: "0",
    sanityMarginPercentage: "0",
    allowSells: true,
    allowReserveWithdrawals: false,
    alphaBond: true,
    batchBlocks: "1",
    outcomePayment: "0",
    creatorAddress: signerAddress,
  }),
};

await signingClient.signAndBroadcast(signerAddress, [createBondMsg], "auto");

Edit, set alpha, transition state

const editMsg = {
  typeUrl: "/ixo.bonds.v1beta1.MsgEditBond",
  value: ixo.bonds.v1beta1.MsgEditBond.fromPartial({
    bondDid: "did:ixo:bond:abc123",
    name: "Solar Farm Alpha Bond v2",
    description: "Updated description",
    orderQuantityLimits: "",
    sanityRate: "",
    sanityMarginPercentage: "",
    editorDid: "did:ixo:editor123",
    editorAddress: signerAddress,
  }),
};

const setAlphaMsg = {
  typeUrl: "/ixo.bonds.v1beta1.MsgSetNextAlpha",
  value: ixo.bonds.v1beta1.MsgSetNextAlpha.fromPartial({
    bondDid: "did:ixo:bond:abc123",
    alpha: "0.85",
    delta: "0.05",
    oracleDid: "did:ixo:oracle123",
    oracleAddress: oracleSignerAddress,
  }),
};

const updateStateMsg = {
  typeUrl: "/ixo.bonds.v1beta1.MsgUpdateBondState",
  value: ixo.bonds.v1beta1.MsgUpdateBondState.fromPartial({
    bondDid: "did:ixo:bond:abc123",
    state: "OPEN",
    editorDid: "did:ixo:editor123",
    editorAddress: signerAddress,
  }),
};
Bond states are: HATCH (initial fundraising), OPEN (active trading), SETTLE (settlement), FAILED.

Buy, sell, swap

const buyMsg = {
  typeUrl: "/ixo.bonds.v1beta1.MsgBuy",
  value: ixo.bonds.v1beta1.MsgBuy.fromPartial({
    buyerDid: "did:ixo:buyer123",
    amount: { denom: "BOND", amount: "1000000" },
    maxPrices: [{ denom: "uixo", amount: "100" }],
    bondDid: "did:ixo:bond:abc123",
    buyerAddress: signerAddress,
  }),
};

const sellMsg = {
  typeUrl: "/ixo.bonds.v1beta1.MsgSell",
  value: ixo.bonds.v1beta1.MsgSell.fromPartial({
    sellerDid: "did:ixo:seller123",
    amount: { denom: "BOND", amount: "1000000" },
    bondDid: "did:ixo:bond:abc123",
    sellerAddress: signerAddress,
  }),
};

const swapMsg = {
  typeUrl: "/ixo.bonds.v1beta1.MsgSwap",
  value: ixo.bonds.v1beta1.MsgSwap.fromPartial({
    swapperDid: "did:ixo:swapper123",
    bondDid: "did:ixo:bond:abc123",
    from: { denom: "uixo", amount: "1000" },
    toToken: "uatom",
    swapperAddress: signerAddress,
  }),
};

Outcome payments and withdrawals

const outcomePayMsg = {
  typeUrl: "/ixo.bonds.v1beta1.MsgMakeOutcomePayment",
  value: ixo.bonds.v1beta1.MsgMakeOutcomePayment.fromPartial({
    senderDid: "did:ixo:funder123",
    amount: "1000000",
    bondDid: "did:ixo:bond:abc123",
    senderAddress: signerAddress,
  }),
};

const withdrawShareMsg = {
  typeUrl: "/ixo.bonds.v1beta1.MsgWithdrawShare",
  value: ixo.bonds.v1beta1.MsgWithdrawShare.fromPartial({
    recipientDid: "did:ixo:holder123",
    bondDid: "did:ixo:bond:abc123",
    recipientAddress: signerAddress,
  }),
};

const withdrawReserveMsg = {
  typeUrl: "/ixo.bonds.v1beta1.MsgWithdrawReserve",
  value: ixo.bonds.v1beta1.MsgWithdrawReserve.fromPartial({
    withdrawerDid: "did:ixo:treasury123",
    amount: [{ denom: "uixo", amount: "500000" }],
    bondDid: "did:ixo:bond:abc123",
    withdrawerAddress: signerAddress,
  }),
};

Verify the result

Query bond state through the Blocksync GraphQL API or ixo.bonds.v1beta1 query endpoints on the gRPC gateway API.

Troubleshooting

function_type must be one of the supported curve types (power_function, sigmoid_function, swapper_function, augmented_function). Each requires a specific set of function_parameters — see the bonds proto.
State transitions are constrained by the bond’s lifecycle. HATCH → OPEN requires the hatch threshold to be met. OPEN → SETTLE is typically called once the outcome obligation is met or the bond expires.
MsgWithdrawReserve fails when allow_reserve_withdrawals is false on MsgCreateBond. This flag is immutable.
Only the bond’s oracle_address (resolving from oracle_did) can broadcast MsgSetNextAlpha. Confirm the signer matches.

Next steps

IXO MultiClient SDK

Module-level features and types.

Bonds proto definitions

Source of truth for bond messages.

Manage tokens

Mint outcome tokens against settled bonds.

Liquid staking

Stake IXO tokens for use in bonded protocols.