Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Latest LBP design implementation for metri testing #1

Merged
merged 25 commits into from
Jan 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
421c37f
removed unused code
roleengineer Dec 20, 2024
3ba6a9c
Factory refactored to template state
roleengineer Dec 20, 2024
a639189
added OrderCreator prototype
roleengineer Jan 8, 2025
6381a99
renamed factory and added prototype code inside CirclesBacking contract
roleengineer Jan 8, 2025
eaaefe9
forge install: contracts
roleengineer Jan 8, 2025
bf708a8
added factory prototype and start refactoring
roleengineer Jan 8, 2025
78e5461
move init and order preparation logic to factory
roleengineer Jan 8, 2025
52d14cc
continue refactoring
roleengineer Jan 9, 2025
3b78c6c
moved join pool call from factory to instance
roleengineer Jan 10, 2025
bdafd67
implemented claim bpt
roleengineer Jan 10, 2025
ef3d208
added factory admin functions
roleengineer Jan 10, 2025
c2f930c
prettified factory
roleengineer Jan 10, 2025
2a55831
prettified instance
roleengineer Jan 10, 2025
c1e7dcf
adjusted metri flow batch tx: approve usdc, make 48crc erc1155 transf…
roleengineer Jan 10, 2025
9a7ec4e
minor edits
roleengineer Jan 10, 2025
d8f9e4d
removed unused test
roleengineer Jan 10, 2025
cdfbf9f
resolve review comments: ensureERC20, only human avatars
roleengineer Jan 11, 2025
f7d67bc
Update src/CirclesBacking.sol
roleengineer Jan 11, 2025
b8bf3d1
added reverse mapping backer-backing and view isActiveLBP
roleengineer Jan 11, 2025
0ab8c6f
Merge branch 'mt/factory' of https://github.com/aboutcircles/circles-…
roleengineer Jan 11, 2025
95b480d
added receiver param in releaseBPT func
roleengineer Jan 11, 2025
e2036b4
simulated backing flow to set gaslimit
roleengineer Jan 12, 2025
1364baf
deployed and refactored api call
roleengineer Jan 12, 2025
cbca43a
updated block
roleengineer Jan 12, 2025
4063931
updated block again
roleengineer Jan 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@
[submodule "lib/safe-smart-account"]
path = lib/safe-smart-account
url = https://github.com/safe-global/safe-smart-account
[submodule "lib/contracts"]
path = lib/contracts
url = https://github.com/cowprotocol/contracts
1 change: 1 addition & 0 deletions lib/contracts
Submodule contracts added at ba5738
1 change: 1 addition & 0 deletions remappings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/
openzeppelin-contracts/=lib/openzeppelin-contracts/
safe-smart-account/=lib/safe-smart-account/
solmate/=lib/solmate/src/
@cowprotocol/contracts/=lib/contracts/src/contracts
45 changes: 45 additions & 0 deletions script/DeployFactory.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.28;

import {Script, console} from "forge-std/Script.sol";
import {CirclesBackingFactory} from "src/factory/CirclesBackingFactory.sol";

contract DeployFactory is Script {
address deployer = address(0x6BF173798733623cc6c221eD52c010472247d861);
CirclesBackingFactory public circlesBackingFactory; // 0xD608978aD1e1473fa98BaD368e767C5b11e3b3cE

function setUp() public {}

function run() public {
vm.startBroadcast(deployer);

circlesBackingFactory = new CirclesBackingFactory(deployer, 1);

vm.stopBroadcast();
console.log(address(circlesBackingFactory), "CirclesBackingFactory");
}
}

/*
curl -X 'POST' \
'https://api.cow.fi/xdai/api/v1/orders' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"sellToken": "0x2a22f9c3b484c3629090FeED35F17Ff8F88f76F0",
"buyToken": "0x6A023CCd1ff6F2045C3309768eAd9E68F978f6e1",
"receiver": "0xe75F06c807038D7D38e4f9716FF953eA1dA39157",
"sellAmount": "1000000",
"buyAmount": "1",
"validTo": 1894324190,
"feeAmount": "0",
"kind": "sell",
"partiallyFillable": false,
"sellTokenBalance": "erc20",
"buyTokenBalance": "erc20",
"signingScheme": "presign",
"signature": "0x",
"from": "0xe75F06c807038D7D38e4f9716FF953eA1dA39157",
"appData": "{\"version\":\"1.1.0\",\"appCode\":\"Circles backing powered by AboutCircles\",\"metadata\":{\"hooks\":{\"version\":\"0.1.0\",\"post\":[{\"target\":\"0xe75f06c807038d7d38e4f9716ff953ea1da39157\",\"callData\":\"0x13e8f89f\",\"gasLimit\":\"6000000\"}]}}}"
}'
*/
8 changes: 4 additions & 4 deletions script/DeployMintPolicy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@
pragma solidity ^0.8.28;

import {Script, console} from "forge-std/Script.sol";
import {TestLBPMintPolicy} from "src/policy/TestLBPMintPolicy.sol";
import {CreateTestProxyLBPMintPolicy} from "src/proxy/CreateTestProxyLBPMintPolicy.sol";
import {MintPolicy} from "circles-contracts-v2/groups/BaseMintPolicy.sol";

contract DeployMintPolicy is Script {
address deployer = address(0x6BF173798733623cc6c221eD52c010472247d861);
TestLBPMintPolicy public mintPolicy; // 0xCb10eC7A4D9D764b1DcfcB9c2EBa675B1e756C96
CreateTestProxyLBPMintPolicy public proxyDeployer; // 0x777f78921890Df5Db755e77CbA84CBAdA5DB56D2
MintPolicy public mintPolicy;
CreateTestProxyLBPMintPolicy public proxyDeployer;

function setUp() public {}

function run() public {
vm.startBroadcast(deployer);

mintPolicy = new TestLBPMintPolicy();
mintPolicy = new MintPolicy();
proxyDeployer = new CreateTestProxyLBPMintPolicy(address(mintPolicy));

vm.stopBroadcast();
Expand Down
25 changes: 0 additions & 25 deletions script/DeployModuleFactory.s.sol

This file was deleted.

22 changes: 22 additions & 0 deletions script/DeployOrderCreator.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.28;

import {Script, console} from "forge-std/Script.sol";
import {OrderCreator} from "src/prototype/OrderCreator.sol";

contract DeployPrototype is Script {
address deployer = address(0x6BF173798733623cc6c221eD52c010472247d861);
OrderCreator public orderCreator;

function setUp() public {}

function run() public {
vm.startBroadcast(deployer);

orderCreator = new OrderCreator();
orderCreator.createOrder();

vm.stopBroadcast();
console.log(address(orderCreator), "orderCreator");
}
}
158 changes: 158 additions & 0 deletions src/CirclesBacking.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.28;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ICowswapSettlement} from "src/interfaces/ICowswapSettlement.sol";
import {IFactory} from "src/interfaces/IFactory.sol";
import {ILBP} from "src/interfaces/ILBP.sol";
import {IVault} from "src/interfaces/IVault.sol";

contract CirclesBacking {
// Errors
/// Already initialized.
error AlreadyInitialized();
/// Function must be called only by Cowswap posthook.
error OrderNotFilledYet();
/// LBP is already created.
error AlreadyCreated();
/// Cowswap solver must transfer the swap result before calling posthook.
error InsufficientBackingAssetBalance();
/// Unauthorized access.
error NotBacker();
/// Balancer Pool Tokens are still locked until `timestamp`.
error TokensLockedUntilTimestamp(uint256 timestamp);

// Events
/// @notice Emitted when Cowswap order is created, logging order uid.
event OrderCreated(bytes orderUid);

// Constants
/// @notice Gnosis Protocol v2 Settlement Contract.
ICowswapSettlement public constant COWSWAP_SETTLEMENT =
ICowswapSettlement(address(0x9008D19f58AAbD9eD0D60971565AA8510560ab41));
/// @notice Gnosis Protocol v2 Vault Relayer Contract.
address public constant VAULT_RELAY = 0xC92E8bdf79f0507f65a392b0ab4667716BFE0110;
/// @dev Circles Backing Factory.
IFactory internal immutable FACTORY;
/// @dev LBP token weight 50%.
uint256 internal constant WEIGHT_50 = 0.5 ether;
/// @dev Update weight duration and lbp lock period is set to 1 year.
uint256 internal constant UPDATE_WEIGHT_DURATION = 365 days;

// Storage
/// @notice Address of circles avatar, which has backed his personal circles.
address public backer;
/// @notice Address of one of supported assets, which was used to back circles.
address public backingAsset;
/// @notice Address of ERC20 stable circles version (InflationaryCircles), which is used as underlying asset in lbp.
address public personalCircles;
/// @notice Address of created Liquidity Bootstrapping Pool, which represents backing liquidity.
address public lbp;
uint256 stableCirclesAmount;
/// @notice Timestamp, when locked balancer pool tokens are allowed to be claimed by backer.
uint256 public balancerPoolTokensUnlockTimestamp;
/// @notice Cowswap order uid.
bytes public storedOrderUid;

constructor() {
FACTORY = IFactory(msg.sender);
}

// Backing logic

/// @notice Initiates core values and backing process, approves Cowswap to spend USDC and presigns order.
function initiateBacking(
address _backer,
address _backingAsset,
address _personalCircles,
bytes memory orderUid,
address usdc,
uint256 tradeAmount,
uint256 stableCRCAmount
) external {
if (backer != address(0)) revert AlreadyInitialized();
// init
backer = _backer;
backingAsset = _backingAsset;
personalCircles = _personalCircles;
stableCirclesAmount = stableCRCAmount;

// Approve USDC to Vault Relay contract
IERC20(usdc).approve(VAULT_RELAY, tradeAmount);

// Store the order UID
storedOrderUid = orderUid;

// Place the order using "setPreSignature"
COWSWAP_SETTLEMENT.setPreSignature(orderUid, true);

// Emit event with the order UID
emit OrderCreated(orderUid);
}

/// @notice Method, which should be used as Cowswap posthook interaction.
/// Creates preconfigured LBP and provides liquidity to it.
function createLBP() external {
// Check if the order has been filled on the CowSwap settlement contract
uint256 filledAmount = COWSWAP_SETTLEMENT.filledAmount(storedOrderUid);
if (filledAmount == 0) revert OrderNotFilledYet();
if (lbp != address(0)) revert AlreadyCreated();

// Backing asset balance of the contract
uint256 backingAssetBalance = IERC20(backingAsset).balanceOf(address(this));
if (backingAssetBalance == 0) revert InsufficientBackingAssetBalance();

// Create LBP
bytes32 poolId;
IVault.JoinPoolRequest memory request;
address vault;
(lbp, poolId, request, vault) =
FACTORY.createLBP(personalCircles, stableCirclesAmount, backingAsset, backingAssetBalance);

// approve vault
IERC20(personalCircles).approve(vault, stableCirclesAmount);
IERC20(backingAsset).approve(vault, backingAssetBalance);

// provide liquidity into lbp
IVault(vault).joinPool(
poolId,
address(this), // sender
address(this), // recipient
request
);

// update weight gradually
uint256 timestampInYear = block.timestamp + UPDATE_WEIGHT_DURATION;
ILBP(lbp).updateWeightsGradually(block.timestamp, timestampInYear, _endWeights());

// set bpt unlock
balancerPoolTokensUnlockTimestamp = timestampInYear;
}

// Balancer pool tokens

/// @notice Method allows backer to claim balancer pool tokens after lock period or in case of global release.
/// @param receiver Address, which will receive balancer pool tokens.
function releaseBalancerPoolTokens(address receiver) external {
if (msg.sender != backer) revert NotBacker();

if (FACTORY.releaseTimestamp() > uint32(block.timestamp)) {
if (balancerPoolTokensUnlockTimestamp > block.timestamp) {
revert TokensLockedUntilTimestamp(balancerPoolTokensUnlockTimestamp);
}
}
// zeroed timestamp
balancerPoolTokensUnlockTimestamp = 0;

uint256 bptAmount = IERC20(lbp).balanceOf(address(this));
IERC20(lbp).transfer(receiver, bptAmount);
}

// Internal functions

function _endWeights() internal pure returns (uint256[] memory endWeights) {
endWeights = new uint256[](2);
endWeights[0] = WEIGHT_50;
endWeights[1] = WEIGHT_50;
}
}
Loading
Loading