Skip to content

Add ButterSwap Tracker via Historical Block Queries #1243

@premiumjibles

Description

@premiumjibles

Context

The ShapeShift affiliate revenue API aggregates fee data from multiple swap providers. ButterSwap is a cross-chain swap provider on MAP Protocol. Unlike other providers, ButterSwap doesn't have a public API for transaction-level affiliate data, but we can query historical balances directly from their smart contract.

Repository: shapeshift/unchained
Location: node/proxy/api/src/affiliateRevenue/

Technical Approach

ButterSwap's affiliate contract on MAP Protocol supports historical block queries via eth_call. We can estimate block numbers from timestamps and query the balance difference.

Key Details:

  • Contract: 0x4De2ADb9cB88c10Bf200F76c18035cbB8906b6bC
  • RPC: https://rpc.maplabs.io/
  • Chain ID: 22776 (MAP Protocol)
  • Block time: ~5 seconds
  • Function: getTotalBalance(uint256 affiliateId, address[] tokens, address quoteToken)
  • Affiliate ID: 26
  • Quote token (USDT): 0x33daba9618a75a7aff103e53afe530fbacf4a3dd

Implementation

export const getFees = async (startTimestamp: number, endTimestamp: number): Promise<Fees[]> => {
  const currentBlock = await getBlockNumber()
  const now = Math.floor(Date.now() / 1000)
  const BLOCK_TIME = 5 // MAP Protocol 5-second blocks
  
  // Estimate block numbers from timestamps
  const startBlock = currentBlock - Math.floor((now - startTimestamp) / BLOCK_TIME)
  const endBlock = currentBlock - Math.floor((now - endTimestamp) / BLOCK_TIME)
  
  // Query balance at both blocks
  const balanceAtStart = await getTotalBalance(startBlock)
  const balanceAtEnd = await getTotalBalance(endBlock)
  
  const feesForPeriod = balanceAtEnd - balanceAtStart
  
  // Return as single fee entry at end of period to conform to Fees[] shape
  if (feesForPeriod <= 0) return []
  
  return [{
    service: 'butterswap',
    amount: feesForPeriod.toString(),
    amountUsd: feesForPeriod.toString(), // Already in USDT
    chainId: 'eip155:22776',
    assetId: 'eip155:22776/erc20:0x33daba9618a75a7aff103e53afe530fbacf4a3dd',
    timestamp: endTimestamp,
    txHash: '', // No single tx - aggregate balance change
  }]
}

Acceptance Criteria

  • Create butterswap.ts following existing tracker patterns
  • Implement getTotalBalance() RPC call with block number parameter
  • Estimate block numbers from timestamps (5-second blocks)
  • Return balance difference as single Fees entry
  • Add 'butterswap' to services array in models.ts
  • Import and integrate in index.ts
  • Handle edge cases (negative balance change, contract not existing at old blocks)

Files to Create/Modify

  • node/proxy/api/src/affiliateRevenue/butterswap.ts (new)
  • node/proxy/api/src/affiliateRevenue/index.ts
  • node/proxy/api/src/models.ts
  • node/proxy/api/src/affiliateRevenue/constants.ts (add MAP Protocol chain ID, contract address)

Notes

  • Returns aggregate fees for the period, not per-transaction data
  • Block estimation is ~99% accurate (sufficient for revenue tracking)
  • No database or caching required - stateless queries
  • USDT has 18 decimals on MAP Protocol

Reference

  • Python implementation: newrfox3.0/butterswap_tracker.py
  • MAP Protocol block explorer: https://maposcan.io/

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions