JSPM

  • Created
  • Published
  • Downloads 844
  • Score
    100M100P100Q118002F
  • License MIT

Rujira DEX integration for Vultisig SDK - Modular TypeScript SDK for swaps and limit orders on THORChain

Package Exports

  • @vultisig/rujira
  • @vultisig/rujira/assets
  • @vultisig/rujira/ghost
  • @vultisig/rujira/orderbook
  • @vultisig/rujira/perps
  • @vultisig/rujira/signer
  • @vultisig/rujira/staking
  • @vultisig/rujira/swap
  • @vultisig/rujira/utils

Readme

@vultisig/rujira

TypeScript SDK for interacting with Rujira (FIN) on THORChain.

It provides:

  • FIN swap quotes + execution (CosmWasm)
  • Secured asset ("synth-like") deposit helpers (inbound address + memo)
  • Withdrawal helpers (THORChain MsgDeposit withdrawal flow)
  • Route discovery + convenience easy routes

Status: Early/alpha. APIs may change.


Installation

# npm
npm i @vultisig/rujira

# yarn
yarn add @vultisig/rujira

# pnpm
pnpm add @vultisig/rujira

If you are working inside this monorepo, use the workspace dependency:

{
  "dependencies": {
    "@vultisig/rujira": "workspace:^"
  }
}

Secured assets (what they are)

THORChain can custody L1 assets in inbound vaults and represent them on THORChain as secured assets (bank balances / denoms).

Typical flow:

  1. You send an L1 transfer (e.g. BTC) to a THORChain inbound address
  2. You include a memo that tells THORChain which THOR address should receive the secured asset
  3. THORChain credits your THOR address with the corresponding secured denom
  4. Those secured denoms can be swapped on FIN (Rujira orderbook DEX)
  5. You can withdraw back to L1 by broadcasting a THORChain MsgDeposit with a withdraw memo

Notes:

  • THORChain secured balances are commonly stored with 8 decimals.
  • This package accepts human-friendly asset notation like BTC.BTC / ETH.ETH and maps to FIN denoms when available via the built-in asset registry.

Quick start (read-only)

import { RujiraClient } from '@vultisig/rujira'

const client = new RujiraClient({ network: 'mainnet' })
await client.connect()

// 1) Discover FIN routes / contracts
const quote = await client.swap.getQuote({
  fromAsset: 'THOR.RUNE',
  toAsset: 'BTC.BTC',
  amount: '100000000', // base units (example)
})

console.log('Expected out:', quote.expectedOutput)

Quick start (with Vultisig signing)

To execute swaps/withdrawals you need a Cosmos signer. When using a Vultisig vault, use VultisigRujiraProvider.

import { Vultisig } from '@vultisig/sdk'
import { RujiraClient, VultisigRujiraProvider } from '@vultisig/rujira'

// 1) Initialize Vultisig SDK + pick a vault
const sdk = new Vultisig({ /* ... */ })
await sdk.initialize()
const vault = await sdk.getActiveVault()
if (!vault) throw new Error('No active vault')

// 2) Create a Rujira client with a Vultisig-backed signer
const signer = new VultisigRujiraProvider(vault)
const client = new RujiraClient({ network: 'mainnet', signer })
await client.connect()

// 3) FIN swap (secured denoms on THORChain)
const thorDestination = await vault.address('THORChain')

const quote = await client.swap.getQuote({
  fromAsset: 'BTC.BTC',
  toAsset: 'ETH.ETH',
  amount: '100000',
  destination: thorDestination,
  slippageBps: 100,
})

const swapResult = await client.swap.execute(quote, { slippageBps: 100 })
console.log('Swap tx hash:', swapResult.txHash)

Deposits (secure L1 → THORChain)

Get inbound address + memo

import { RujiraClient } from '@vultisig/rujira'

const client = new RujiraClient({ network: 'mainnet' })
await client.connect()

const deposit = await client.deposit.prepare({
  fromAsset: 'BTC.BTC',
  amount: '100000', // base units; used for validation / dust threshold checks
  thorAddress: 'thor1...',
})

console.log('Send to:', deposit.inboundAddress)
console.log('Memo:', deposit.memo)

List all inbound addresses

const inbound = await client.deposit.getInboundAddresses()
console.log(inbound.map(i => ({ chain: i.chain, address: i.address })))

Check secured balances on THORChain

const balances = await client.deposit.getBalances('thor1...')
console.log(balances)

Withdrawals (THORChain → L1)

Withdrawals are executed on THORChain via MsgDeposit with a withdraw memo. When using Vultisig, withdrawal execution requires a VultisigRujiraProvider (it exposes vault access for MsgDeposit signing).

import { RujiraClient, VultisigRujiraProvider } from '@vultisig/rujira'

const client = new RujiraClient({ network: 'mainnet', signer: new VultisigRujiraProvider(vault) })
await client.connect()

const prepared = await client.withdraw.prepare({
  asset: 'BTC.BTC',
  amount: '100000',
  l1Address: 'bc1...',
})

const result = await client.withdraw.execute(prepared)
console.log('Withdraw tx hash:', result.txHash)

Easy routes (convenience)

Use pre-defined routes to avoid thinking about pairs.

import { EASY_ROUTES, listEasyRoutes, getRoutesSummary } from '@vultisig/rujira'

console.log(getRoutesSummary())
console.log(listEasyRoutes())

const route = EASY_ROUTES.RUNE_TO_USDC

API reference (high level)

new RujiraClient(options)

export interface RujiraClientOptions {
  config?: Partial<RujiraConfig>
  signer?: RujiraSigner
  rpcEndpoint?: string
  contractCache?: {
    load?: () => Promise<Record<string, string>> | Record<string, string>
    save?: (finContracts: Record<string, string>) => Promise<void> | void
  }
  debug?: boolean
  swapOptions?: RujiraSwapOptions
}

Key methods:

  • connect() / disconnect()
  • isConnected() / canSign()
  • getAddress()
  • getBalance(address, denom) / getAllBalances(address)

Modules:

  • client.swap.getQuote(params) / client.swap.execute(quote, options)
  • client.deposit.prepare(params) / client.deposit.getInboundAddresses() / client.deposit.getBalances(thorAddress)
  • client.withdraw.prepare(params) / client.withdraw.execute(prepared)

VultisigRujiraProvider

A Cosmos signer implementation that delegates signing to a Vultisig vault.

import { VultisigRujiraProvider } from '@vultisig/rujira'

const signer = new VultisigRujiraProvider(vault /*, chainId? */)

GraphQL / discovery rate limits (optional)

Rujira contract discovery may use GraphQL. If you run into HTTP 429 rate limits, you can provide an API token to the GraphQL client used by discovery.

import { RujiraDiscovery } from '@vultisig/rujira'

const discovery = new RujiraDiscovery({
  network: 'mainnet',
  graphql: { apiKey: process.env.RUJIRA_API_KEY },
})

const contracts = await discovery.discoverContracts()

Examples

See:

  • packages/rujira/examples/
  • packages/rujira/docs/

License

MIT