Skip to content

Commit 3b85888

Browse files
authored
feat: add setSpread to BiPoolManager (#689)
1 parent a066b99 commit 3b85888

File tree

5 files changed

+124
-0
lines changed

5 files changed

+124
-0
lines changed

.github/workflows/lint_test.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ jobs:
2727

2828
- name: Install Foundry
2929
uses: foundry-rs/foundry-toolchain@v1
30+
with:
31+
version: v1.3.5
3032

3133
- name: Install Node.js
3234
uses: actions/setup-node@v3

contracts/interfaces/IBiPoolManager.sol

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,13 @@ interface IBiPoolManager {
112112
*/
113113
event PricingModulesUpdated(bytes32[] newIdentifiers, address[] newAddresses);
114114

115+
/**
116+
* @notice Emitted when the spread for a specified exchange is updated.
117+
* @param exchangeId The id of the exchange
118+
* @param spread The new spread
119+
*/
120+
event SpreadUpdated(bytes32 indexed exchangeId, uint256 spread);
121+
115122
/**
116123
* @notice Retrieves the pool with the specified exchangeId.
117124
* @param exchangeId The id of the pool to be retrieved.
@@ -223,6 +230,8 @@ interface IBiPoolManager {
223230

224231
function setBreakerBox(IBreakerBox newBreakerBox) external;
225232

233+
function setSpread(bytes32 exchangeId, uint256 spread) external;
234+
226235
/// @notice IOwnable:
227236
function transferOwnership(address newOwner) external;
228237

contracts/swap/BiPoolManager.sol

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,16 @@ contract BiPoolManager is IExchangeProvider, IBiPoolManager, Initializable, Owna
233233
emit PricingModulesUpdated(identifiers, modules);
234234
}
235235

236+
function setSpread(bytes32 exchangeId, uint256 spread) external onlyOwner {
237+
require(exchanges[exchangeId].asset0 != address(0), "invalid exchangeId");
238+
239+
FixidityLib.Fraction memory newSpread = FixidityLib.wrap(spread);
240+
require(newSpread.lte(FixidityLib.fixed1()), "spread must be <= 1");
241+
242+
exchanges[exchangeId].config.spread = newSpread;
243+
emit SpreadUpdated(exchangeId, spread);
244+
}
245+
236246
/**
237247
* @notice Creates a new exchange using the given parameters.
238248
* @param _exchange the PoolExchange to create.

foundry.lock

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"lib/forge-std": {
3+
"rev": "035de35f5e366c8d6ed142aec4ccb57fe2dd87d4"
4+
},
5+
"lib/foundry-chainlink-toolkit": {
6+
"rev": "d610ec9ef54c325de7de1a5622c19933b2ae26cf"
7+
},
8+
"lib/mento-std": {
9+
"rev": "cae988de9b03b6ab4811900c3c781ccbf8b8beaf"
10+
},
11+
"lib/openzeppelin-contracts": {
12+
"rev": "58a3368215581509d05bd3ec4d53cd381c9bb40e"
13+
},
14+
"lib/openzeppelin-contracts-next": {
15+
"rev": "0a25c1940ca220686588c4af3ec526f725fe2582"
16+
},
17+
"lib/openzeppelin-contracts-upgradeable": {
18+
"rev": "58fa0f81c4036f1a3b616fdffad2fd27e5d5ce21"
19+
},
20+
"lib/prb-math": {
21+
"branch": {
22+
"name": "\"release-v4\"",
23+
"rev": "1edf08dd73eb1ace0042459ba719b8ea4a55c0e0"
24+
}
25+
},
26+
"lib/safe-contracts": {
27+
"rev": "186a21a74b327f17fc41217a927dea7064f74604"
28+
}
29+
}

test/unit/swap/BiPoolManager.t.sol

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ contract BiPoolManagerTest is Test {
4444
event BucketsUpdated(bytes32 indexed exchangeId, uint256 bucket0, uint256 bucket1);
4545
event BreakerBoxUpdated(address newBreakerBox);
4646
event PricingModulesUpdated(bytes32[] newIdentifiers, address[] newAddresses);
47+
event SpreadUpdated(bytes32 indexed exchangeId, uint256 spread);
4748

4849
/* ------------------------------------------- */
4950

@@ -357,6 +358,79 @@ contract BiPoolManagerTest_initilizerSettersGetters is BiPoolManagerTest {
357358
biPoolManager.setPricingModules(newIdentifiers, newPricingModules);
358359
}
359360

361+
function test_setSpread_whenSenderIsNotOwner_shouldRevert() public {
362+
changePrank(notDeployer);
363+
vm.expectRevert("Ownable: caller is not the owner");
364+
biPoolManager.setSpread(0x0, 0);
365+
}
366+
367+
function test_setSpread_whenExchangeDoesNotExist_shouldRevert() public {
368+
vm.expectRevert("invalid exchangeId");
369+
biPoolManager.setSpread(0x0, 0.1 * 1e24);
370+
}
371+
372+
function test_setSpread_whenSpreadIsGreaterThanOne_shouldRevert() public {
373+
mockOracleRate(address(cUSD), 1e24);
374+
bytes32 exchangeId = createExchange(cUSD, bridgedUSDC);
375+
vm.expectRevert("spread must be <= 1");
376+
biPoolManager.setSpread(exchangeId, 1e24 + 1);
377+
}
378+
379+
function test_setSpread_whenCallerIsOwner_shouldUpdateAndEmit() public {
380+
mockOracleRate(address(cUSD), 1e24);
381+
createExchange(cUSD, bridgedUSDC);
382+
383+
bytes32 exchangeId = keccak256(abi.encodePacked(cUSD.symbol(), bridgedUSDC.symbol(), constantProduct.name()));
384+
FixidityLib.Fraction memory currentSpread = biPoolManager.getPoolExchange(exchangeId).config.spread;
385+
require(FixidityLib.equals(currentSpread, FixidityLib.wrap(0.1 * 1e24)), "Current spread is not 0.1");
386+
387+
vm.expectEmit(true, true, true, true);
388+
emit SpreadUpdated(exchangeId, 0.5 * 1e24);
389+
biPoolManager.setSpread(exchangeId, 0.5 * 1e24);
390+
391+
FixidityLib.Fraction memory newSpread = biPoolManager.getPoolExchange(exchangeId).config.spread;
392+
require(FixidityLib.equals(newSpread, FixidityLib.wrap(0.5 * 1e24)), "New spread is not 0.5");
393+
}
394+
395+
function test_setSpread_whenSpreadIsZero_shouldUpdate() public {
396+
mockOracleRate(address(cUSD), 1e24);
397+
bytes32 exchangeId = createExchange(cUSD, bridgedUSDC);
398+
399+
vm.expectEmit(true, true, true, true);
400+
emit SpreadUpdated(exchangeId, 0);
401+
biPoolManager.setSpread(exchangeId, 0);
402+
403+
FixidityLib.Fraction memory newSpread = biPoolManager.getPoolExchange(exchangeId).config.spread;
404+
require(FixidityLib.equals(newSpread, FixidityLib.wrap(0)), "Spread should be 0");
405+
}
406+
407+
function test_setSpread_whenSpreadIsExactlyOne_shouldUpdate() public {
408+
mockOracleRate(address(cUSD), 1e24);
409+
bytes32 exchangeId = createExchange(cUSD, bridgedUSDC);
410+
411+
vm.expectEmit(true, true, true, true);
412+
emit SpreadUpdated(exchangeId, 1e24);
413+
biPoolManager.setSpread(exchangeId, 1e24);
414+
415+
FixidityLib.Fraction memory newSpread = biPoolManager.getPoolExchange(exchangeId).config.spread;
416+
require(FixidityLib.equals(newSpread, FixidityLib.wrap(1e24)), "Spread should be 1");
417+
}
418+
419+
function test_setSpread_whenSettingSameSpread_shouldEmitAndSucceed() public {
420+
mockOracleRate(address(cUSD), 1e24);
421+
bytes32 exchangeId = createExchange(cUSD, bridgedUSDC);
422+
423+
// Initial spread is 0.1 * 1e24 from createExchange
424+
uint256 currentSpreadValue = 0.1 * 1e24;
425+
426+
vm.expectEmit(true, true, true, true);
427+
emit SpreadUpdated(exchangeId, currentSpreadValue);
428+
biPoolManager.setSpread(exchangeId, currentSpreadValue);
429+
430+
FixidityLib.Fraction memory newSpread = biPoolManager.getPoolExchange(exchangeId).config.spread;
431+
require(FixidityLib.equals(newSpread, FixidityLib.wrap(currentSpreadValue)), "Spread should remain 0.1");
432+
}
433+
360434
/* ---------- Getters ---------- */
361435

362436
function test_getPoolExchange_whenExchangeDoesNotExist_shouldRevert() public {

0 commit comments

Comments
 (0)