Skip to content

Latest commit

 

History

History
562 lines (421 loc) · 12.4 KB

File metadata and controls

562 lines (421 loc) · 12.4 KB

Bitcoin Collateral Perps - API Documentation

Smart Contract API

Contract Address (Sepolia)

0x036ce338c12e315b7b888020469e675c011ca5b9f6c5b657c4e6c00f33c03be7

tBTC Token Address (Sepolia)

0x0514f13dbfabf6ec1b73524ca47aa4d2b8d8d62b20c9ed6131566bc43d93d4fc

Contract Interface

IBitcoinCollateralPerps

#[starknet::interface]
pub trait IBitcoinCollateralPerps<TContractState> {
    // Collateral Management
    fn deposit_btc_collateral(ref self: TContractState, amount: u256);
    fn withdraw_btc_collateral(ref self: TContractState, amount: u256);
    fn get_collateral_balance(self: @TContractState, user: ContractAddress) -> u256;
    
    // Position Management
    fn open_perp_position(
        ref self: TContractState, 
        market_id: felt252, 
        size: u256, 
        is_long: bool, 
        leverage: u8
    ) -> felt252;
    fn close_perp_position(ref self: TContractState, position_id: felt252);
    fn get_position(self: @TContractState, position_id: felt252) -> Position;
    
    // Risk Management
    fn check_liquidation_health(self: @TContractState, position_id: felt252) -> bool;
    
    // Admin Functions
    fn set_extended_router(ref self: TContractState, router_address: ContractAddress);
    fn set_oracle(ref self: TContractState, oracle_address: ContractAddress);
    fn pause_contract(ref self: TContractState);
    fn unpause_contract(ref self: TContractState);
    
    // Extended Protocol Integration
    fn fulfill_open_position(
        ref self: TContractState,
        request_id: felt252,
        extended_order_id: felt252,
        execution_price: u256
    );
}

Function Details

deposit_btc_collateral

Deposit tBTC tokens as collateral.

Parameters:

  • amount: u256 - Amount in satoshis (1 tBTC = 100,000,000 satoshis)

Requirements:

  • Amount >= 100,000,000 (1.0 tBTC minimum)
  • User must approve tBTC token spending first
  • Contract must not be paused

Events Emitted:

  • CollateralDeposited(user, amount, timestamp)

Example:

import { Contract, cairo } from 'starknet';

// 1. Approve tBTC spending
const tbtcToken = new Contract(erc20ABI, TBTC_TOKEN_ADDRESS, account);
await tbtcToken.approve(CONTRACT_ADDRESS, cairo.uint256(amount));

// 2. Deposit collateral
const contract = new Contract(contractABI, CONTRACT_ADDRESS, account);
const tx = await contract.deposit_btc_collateral(cairo.uint256(amount));
await provider.waitForTransaction(tx.transaction_hash);

withdraw_btc_collateral

Withdraw available tBTC collateral.

Parameters:

  • amount: u256 - Amount to withdraw in satoshis

Requirements:

  • Amount <= available_collateral
  • Contract must not be paused

Events Emitted:

  • CollateralWithdrawn(user, amount, timestamp)

Example:

const tx = await contract.withdraw_btc_collateral(cairo.uint256(amount));
await provider.waitForTransaction(tx.transaction_hash);

get_collateral_balance

Get user's available collateral balance.

Parameters:

  • user: ContractAddress - User's Starknet address

Returns:

  • u256 - Available collateral in satoshis

Example:

const balance = await contract.get_collateral_balance(userAddress);
console.log('Balance:', balance.toString(), 'satoshis');
console.log('Balance:', (Number(balance) / 1e8).toFixed(8), 'tBTC');

open_perp_position

Open a new perpetual position.

Parameters:

  • market_id: felt252 - Market identifier (e.g., 'BTC/USD', 'ETH/USD')
  • size: u256 - Position size in USD (with 8 decimals)
  • is_long: bool - true for long, false for short
  • leverage: u8 - Leverage multiplier (1-20)

Returns:

  • felt252 - Position ID

Requirements:

  • Sufficient available collateral
  • Leverage <= 20
  • Contract must not be paused

Events Emitted:

  • PositionOpened(position_id, user, market_id, size, is_long)
  • ExtendedRequestCreated(request_id, position_id, user, market, size, is_long, request_type)

Example:

// Open a long BTC/USD position with 10x leverage
const marketId = stringToFelt252('BTC/USD');
const size = cairo.uint256(1000 * 1e8); // $1000 USD
const isLong = true;
const leverage = 10;

const tx = await contract.open_perp_position(
  marketId,
  size,
  isLong,
  leverage
);

const receipt = await provider.waitForTransaction(tx.transaction_hash);

// Extract position ID from events
const positionOpenedEvent = receipt.events.find(
  e => e.keys[0] === 'PositionOpened'
);
const positionId = positionOpenedEvent.data[0];

close_perp_position

Close an existing position.

Parameters:

  • position_id: felt252 - Position ID to close

Requirements:

  • Position must exist and be active
  • Caller must be position owner
  • Contract must not be paused

Events Emitted:

  • PositionClosed(position_id, user)

Example:

const tx = await contract.close_perp_position(positionId);
await provider.waitForTransaction(tx.transaction_hash);

get_position

Get position details.

Parameters:

  • position_id: felt252 - Position ID

Returns:

  • Position - Position struct with all details

Example:

const position = await contract.get_position(positionId);
console.log('Position:', {
  id: position.id,
  owner: position.owner,
  market_id: position.market_id,
  size: position.size.toString(),
  collateral: position.collateral.toString(),
  entry_price: position.entry_price.toString(),
  is_long: position.is_long,
  leverage: position.leverage,
  is_active: position.is_active
});

check_liquidation_health

Check if a position is healthy or at risk of liquidation.

Parameters:

  • position_id: felt252 - Position ID

Returns:

  • bool - true if healthy, false if at risk

Example:

const isHealthy = await contract.check_liquidation_health(positionId);
if (!isHealthy) {
  console.warn('Position at risk of liquidation!');
}

AVNU Paymaster API

Configuration

import { PaymasterRpc } from 'starknet';

const paymasterRpc = new PaymasterRpc({
  nodeUrl: 'https://sepolia.paymaster.avnu.fi',
  headers: { 'x-paymaster-api-key': AVNU_API_KEY }
});

Using AVNU Paymaster

Status:PRODUCTION READY

// 1. Get injected wallet account
const starknet = await connect();
await starknet.enable();
const injectedAccount = starknet.account;

// 2. Update provider to PaymasterRpc
(injectedAccount as any).provider = paymasterRpc;

// 3. Execute transaction with fee token
const result = await injectedAccount.execute(calls, {
  feeToken: 'USDC' // or 'ETH', 'STRK'
});

Supported Fee Tokens:

  • USDC - USD Coin
  • ETH - Ethereum
  • STRK - Starknet Token

Key Points:

  • ✅ Use injected wallet account (don't create Account manually)
  • ✅ Works with ArgentX and Braavos v1.1.0+
  • ✅ Supports SNIP-9 v2 (execute_from_outside)
  • ✅ Real-time balance checking before transaction

Extended Protocol API

Base URL

https://api.starknet.sepolia.extended.exchange/api/v1

WebSocket

wss://api.starknet.sepolia.extended.exchange/stream.extended.exchange/v1

Get Markets

Endpoint: GET /markets

Response:

interface ExtendedMarketStats {
  market_id: string;
  symbol: string;
  last_price: number;
  change_24h: number;
  volume_24h: number;
  high_24h: number;
  low_24h: number;
  open_interest: number;
}

Example:

const response = await fetch(
  'https://api.starknet.sepolia.extended.exchange/api/v1/markets',
  {
    headers: {
      'X-Api-Key': EXTENDED_API_KEY,
      'Content-Type': 'application/json'
    }
  }
);
const markets = await response.json();

Get Market Stats

Endpoint: GET /markets/{marketId}

Example:

const marketId = 'BTC-USD';
const response = await fetch(
  `https://api.starknet.sepolia.extended.exchange/api/v1/markets/${marketId}`,
  {
    headers: {
      'X-Api-Key': EXTENDED_API_KEY,
      'Content-Type': 'application/json'
    }
  }
);
const stats = await response.json();

Place Order

Endpoint: POST /orders

Request:

interface ExtendedOrderRequest {
  market_id: string;
  side: 'long' | 'short';
  size: string;
  leverage: number;
  order_type: 'market' | 'limit';
  price?: string; // Required for limit orders
}

Response:

interface ExtendedOrderResponse {
  order_id: string;
  status: 'pending' | 'filled' | 'rejected';
  execution_price?: string;
  timestamp: number;
}

Get Positions

Endpoint: GET /positions/{address}

Response:

interface ExtendedPosition {
  position_id: string;
  market_id: string;
  side: 'long' | 'short';
  size: string;
  entry_price: string;
  current_price: string;
  pnl: string;
  leverage: number;
  liquidation_price: string;
}

Frontend API

Contract Helper Functions

Located in frontend/lib/contract.ts

getTBTCBalance

async function getTBTCBalance(address: string): Promise<bigint>

Get user's tBTC token balance.

approveTBTC

async function approveTBTC(account: Account, amount: bigint): Promise<string>

Approve tBTC token spending.

depositCollateral

async function depositCollateral(
  account: Account,
  amount: bigint,
  usePaymaster: boolean = false,
  gasToken?: string
): Promise<string>

Deposit tBTC collateral with optional AVNU Paymaster.

withdrawCollateral

async function withdrawCollateral(
  account: Account,
  amount: bigint
): Promise<string>

Withdraw tBTC collateral.

openPosition

async function openPosition(
  account: Account,
  marketId: string,
  size: bigint,
  isLong: boolean,
  leverage: number,
  usePaymaster: boolean = false,
  gasToken?: string
): Promise<string>

Open a new position with optional AVNU Paymaster.

closePosition

async function closePosition(
  account: Account,
  positionId: string
): Promise<string>

Close an existing position.

getUserPositions

async function getUserPositions(userAddress: string): Promise<Position[]>

Get all user positions.

Complete Workflow Example

import { connect } from '@starknet-io/get-starknet';
import { cairo } from 'starknet';
import { 
  getTBTCBalance, 
  approveTBTC, 
  depositCollateral, 
  openPosition 
} from './lib/contract';

// 1. Connect wallet
const starknet = await connect();
await starknet.enable();
const account = starknet.account;

// 2. Check tBTC balance
const balance = await getTBTCBalance(account.address);
console.log('tBTC Balance:', (Number(balance) / 1e8).toFixed(8));

// 3. Approve tBTC spending
const amount = BigInt(2 * 1e8); // 2.0 tBTC
const approveTx = await approveTBTC(account, amount);
console.log('Approve TX:', approveTx);

// 4. Deposit collateral with AVNU Paymaster (pay with USDC)
const depositTx = await depositCollateral(
  account, 
  amount, 
  true, // usePaymaster
  'USDC' // gasToken
);
console.log('Deposit TX:', depositTx);

// 5. Open position
const positionTx = await openPosition(
  account,
  'BTC/USD',
  BigInt(1000 * 1e8), // $1000 USD
  true, // long
  10, // 10x leverage
  true, // usePaymaster
  'USDC' // gasToken
);
console.log('Position TX:', positionTx);

// 6. View on Starkscan
console.log(`https://sepolia.starkscan.co/tx/${positionTx}`);

Error Handling

Common Errors

Error Message Cause Solution
Contract paused Contract is in paused state Wait for unpause or contact admin
Amount below minimum Deposit < 1.0 tBTC Increase deposit amount
Insufficient collateral Not enough available collateral Deposit more tBTC
tBTC transfer failed Approval or balance issue Check approval and balance
Position not found Invalid position ID Verify position ID
Not position owner Caller doesn't own position Use correct wallet
Leverage too high Leverage > 20 Reduce leverage

Rate Limits

  • Extended Protocol API: 100 requests/minute
  • AVNU Paymaster: No documented limits
  • Starknet RPC: Depends on provider

Resources