Skip to content

Commit 1ae07f1

Browse files
authored
Expose Trading Mode Checks (#92)
1 parent f8cb19e commit 1ae07f1

File tree

12 files changed

+662
-88
lines changed

12 files changed

+662
-88
lines changed

.cursor/commands/code-review.md

Lines changed: 0 additions & 40 deletions
This file was deleted.

.cursor/commands/create-pr.md

Lines changed: 0 additions & 40 deletions
This file was deleted.

TRADING_MODE_EXAMPLE.md

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
# BreakerBox Rate Feed Trading Mode SDK Usage
2+
3+
This document shows how to use the rate feed trading mode functionality from the Mento SDK.
4+
5+
## Overview
6+
7+
The SDK exposes two key functions for working with rate feed trading modes:
8+
- `getRateFeedTradingMode()` - Query the current trading mode for a rate feed
9+
- `toRateFeedId()` - Convert a rate feed identifier string to its address
10+
11+
## Trading Modes
12+
13+
The SDK exposes a `TradingMode` enum with three possible values:
14+
15+
- `TradingMode.BIDIRECTIONAL` (0) - Bidirectional trading is enabled
16+
- `TradingMode.HALTED` (1) - Trading is temporarily halted (circuit breaker tripped)
17+
- `TradingMode.DISABLED` (2) - Trading is permanently disabled
18+
19+
## Usage Examples
20+
21+
### Example 1: Using toRateFeedId() to compute a rate feed address
22+
23+
```typescript
24+
import { Mento, TradingMode, toRateFeedId } from '@mento-protocol/mento-sdk'
25+
import { ethers } from 'ethers'
26+
27+
async function checkTradingModeByIdentifier() {
28+
const provider = new ethers.providers.JsonRpcProvider('https://forno.celo.org')
29+
const mento = await Mento.create(provider)
30+
31+
// Compute the rate feed ID from a string identifier
32+
const eurUsdRateFeedId = toRateFeedId('EURUSD')
33+
console.log(`Rate Feed ID for EURUSD: ${eurUsdRateFeedId}`)
34+
// Output: 0x5d5a22116233bdb2a9c2977279cc348b8b8ce917
35+
36+
// Works with relayed feeds too
37+
const copUsdRateFeedId = toRateFeedId('relayed:COPUSD')
38+
console.log(`Rate Feed ID for relayed:COPUSD: ${copUsdRateFeedId}`)
39+
// Output: 0x0196d1f4fda21fa442e53eaf18bf31282f6139f1
40+
41+
// Get the current trading mode
42+
const tradingMode = await mento.getRateFeedTradingMode(eurUsdRateFeedId)
43+
44+
// Check the mode
45+
switch (tradingMode) {
46+
case TradingMode.BIDIRECTIONAL:
47+
console.log('Trading is enabled')
48+
break
49+
case TradingMode.HALTED:
50+
console.log('Trading is halted - circuit breaker tripped')
51+
break
52+
case TradingMode.DISABLED:
53+
console.log('Trading is disabled')
54+
break
55+
}
56+
}
57+
```
58+
59+
### Example 2: Getting rate feed ID from an exchange
60+
61+
```typescript
62+
import { Mento, TradingMode } from '@mento-protocol/mento-sdk'
63+
import { BiPoolManager__factory } from '@mento-protocol/mento-core-ts'
64+
import { ethers } from 'ethers'
65+
66+
async function checkTradingModeFromExchange() {
67+
const provider = new ethers.providers.JsonRpcProvider('https://forno.celo.org')
68+
const mento = await Mento.create(provider)
69+
70+
// Get a rate feed ID from an exchange
71+
const exchanges = await mento.getExchanges()
72+
const biPoolManager = BiPoolManager__factory.connect(
73+
exchanges[0].providerAddr,
74+
provider
75+
)
76+
const exchangeConfig = await biPoolManager.getPoolExchange(exchanges[0].id)
77+
const rateFeedId = exchangeConfig.config.referenceRateFeedID
78+
79+
// Get the current trading mode
80+
const tradingMode = await mento.getRateFeedTradingMode(rateFeedId)
81+
console.log(`Trading mode: ${tradingMode}`)
82+
83+
// Alternative: use the existing convenience method for exchange-level check
84+
const isEnabled = await mento.isTradingEnabled(exchanges[0].id)
85+
console.log(`Is trading enabled: ${isEnabled}`)
86+
}
87+
```
88+
89+
## Implementation Details
90+
91+
### toRateFeedId(rateFeed: string): Address
92+
93+
This utility function computes the rate feed ID from a string identifier following the Solidity formula:
94+
```solidity
95+
address(uint160(uint256(keccak256(abi.encodePacked(rateFeed)))))
96+
```
97+
98+
Steps:
99+
1. Compute keccak256 hash of the UTF-8 encoded string
100+
2. Convert to BigInt (uint256)
101+
3. Mask to 160 bits (uint160)
102+
4. Convert to hex address string
103+
104+
### getRateFeedTradingMode(rateFeedId: Address): Promise<TradingMode>
105+
106+
This method:
107+
1. Gets the BreakerBox contract address for the current chain
108+
2. Connects to the BreakerBox contract
109+
3. Queries `getRateFeedTradingMode()` with the provided rate feed ID
110+
4. Returns the trading mode as a `TradingMode` enum value
111+
112+
**Note:** Multiple exchanges can share the same rate feed, so the BreakerBox operates at the rate feed level rather than the exchange level.
113+
114+
## Related Methods
115+
116+
- `isPairTradable(tokenIn: Address, tokenOut: Address): Promise<boolean>` - Checks if a token pair is currently tradable (most convenient for UI use)
117+
- `isTradingEnabled(exchangeId: string): Promise<boolean>` - Returns true only if the exchange's rate feed mode is BIDIRECTIONAL (operates at exchange level)
118+
- `getTradingLimits(exchangeId: string): Promise<TradingLimit[]>` - Get trading limits for an exchange
119+
120+
## Important Notes
121+
122+
### Multi-Hop Routes
123+
124+
The `isPairTradable()` method intelligently handles multi-hop routes. For example, if you want to swap CELO → USDT but there's no direct exchange, the route might be:
125+
- CELO → cUSD (hop 1)
126+
- cUSD → USDT (hop 2)
127+
128+
The method will check that **ALL** rate feeds in the path are in BIDIRECTIONAL mode. If any hop is HALTED or DISABLED, the entire pair is considered not tradable.
129+
130+
```typescript
131+
// Example: Multi-hop route check
132+
const isTradable = await mento.isPairTradable(celoAddress, usdtAddress)
133+
// Returns true ONLY if both CELO/cUSD AND cUSD/USDT rate feeds are BIDIRECTIONAL
134+
```
135+
136+
### Method Comparison
137+
138+
- **`isPairTradable(tokenIn, tokenOut)`** - Operates at the token pair level. Checks all rate feeds in the routing path. **Use this for UI validation.**
139+
- **`getRateFeedTradingMode(rateFeedId)`** - Operates at the rate feed level. Returns the specific mode for a single rate feed.
140+
- **`isTradingEnabled(exchangeId)`** - Operates at the exchange level. Checks a single exchange by ID.
141+
142+
## UI Integration Example
143+
144+
Here's a practical example for a trading UI with token dropdowns:
145+
146+
```typescript
147+
import { Mento, TradingMode } from '@mento-protocol/mento-sdk'
148+
import { ethers } from 'ethers'
149+
150+
// Your UI state
151+
interface TokenDropdownState {
152+
tokenToSell: string // token address
153+
tokenToBuy: string // token address
154+
}
155+
156+
async function checkIfPairIsTradable(
157+
state: TokenDropdownState,
158+
mento: Mento
159+
): Promise<boolean> {
160+
if (!state.tokenToSell || !state.tokenToBuy) {
161+
return false
162+
}
163+
164+
try {
165+
// Simple check - returns true if tradable, false if not
166+
const isTradable = await mento.isPairTradable(
167+
state.tokenToSell,
168+
state.tokenToBuy
169+
)
170+
return isTradable
171+
} catch (error) {
172+
// Pair doesn't exist or network error
173+
console.error('Error checking pair tradability:', error)
174+
return false
175+
}
176+
}
177+
178+
// React example
179+
function TradingForm() {
180+
const [tokenToSell, setTokenToSell] = useState<string>('')
181+
const [tokenToBuy, setTokenToBuy] = useState<string>('')
182+
const [isTradable, setIsTradable] = useState<boolean>(false)
183+
const [isLoading, setIsLoading] = useState<boolean>(false)
184+
185+
useEffect(() => {
186+
async function checkPair() {
187+
if (!tokenToSell || !tokenToBuy) {
188+
setIsTradable(false)
189+
return
190+
}
191+
192+
setIsLoading(true)
193+
try {
194+
const tradable = await mento.isPairTradable(tokenToSell, tokenToBuy)
195+
setIsTradable(tradable)
196+
} catch (error) {
197+
setIsTradable(false)
198+
} finally {
199+
setIsLoading(false)
200+
}
201+
}
202+
203+
checkPair()
204+
}, [tokenToSell, tokenToBuy])
205+
206+
return (
207+
<div>
208+
<select onChange={(e) => setTokenToSell(e.target.value)}>
209+
{/* token options */}
210+
</select>
211+
<select onChange={(e) => setTokenToBuy(e.target.value)}>
212+
{/* token options */}
213+
</select>
214+
215+
{isLoading && <p>Checking tradability...</p>}
216+
{!isLoading && !isTradable && tokenToSell && tokenToBuy && (
217+
<p style={{ color: 'red' }}>
218+
⚠️ Trading is currently disabled for this pair
219+
</p>
220+
)}
221+
222+
<button disabled={!isTradable || isLoading}>
223+
Swap
224+
</button>
225+
</div>
226+
)
227+
}
228+
```
229+

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@mento-protocol/mento-sdk",
33
"description": "Official SDK for interacting with the Mento Protocol",
4-
"version": "1.15.5",
4+
"version": "1.17.0",
55
"license": "MIT",
66
"author": "Mento Labs",
77
"keywords": [

src/enums/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
export * from './proposalState'
21
export * from './chainId'
2+
export * from './proposalState'
3+
export * from './tradingMode'

src/enums/tradingMode.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { TradingMode } from './tradingMode'
2+
3+
describe('TradingMode enum', () => {
4+
it('should have BIDIRECTIONAL mode with value 0', () => {
5+
expect(TradingMode.BIDIRECTIONAL).toBe(0)
6+
})
7+
8+
it('should have HALTED mode with value 1', () => {
9+
expect(TradingMode.HALTED).toBe(1)
10+
})
11+
12+
it('should have DISABLED mode with value 2', () => {
13+
expect(TradingMode.DISABLED).toBe(2)
14+
})
15+
16+
it('should allow type-safe usage', () => {
17+
const checkMode = (mode: TradingMode): boolean => {
18+
return mode === TradingMode.BIDIRECTIONAL
19+
}
20+
21+
expect(checkMode(TradingMode.BIDIRECTIONAL)).toBe(true)
22+
expect(checkMode(TradingMode.HALTED)).toBe(false)
23+
})
24+
})
25+

src/enums/tradingMode.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* Trading modes for rate feeds in the BreakerBox
3+
*/
4+
export enum TradingMode {
5+
/**
6+
* Bidirectional trading is enabled
7+
*/
8+
BIDIRECTIONAL = 0,
9+
/**
10+
* Trading is temporarily halted (circuit breaker tripped)
11+
*/
12+
HALTED = 1,
13+
/**
14+
* Trading is permanently disabled
15+
*/
16+
DISABLED = 2,
17+
}
18+

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* istanbul ignore file */
22

33
export * from './constants'
4+
export * from './enums'
45
export * from './governance'
56
export * from './mento'
67
export * from './routeUtils'

0 commit comments

Comments
 (0)