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

feat: initiate vertex deployment #432

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,6 @@ We would like to thank the following projects.
- [Aave](https://github.com/aave/aave-v3-core)
- [Uniswap](https://github.com/Uniswap/v3-core)
- [Seaport](https://github.com/ProjectOpenSea/seaport)
- [Vertex](https://github.com/vertex-protocol)
- [BendDAO](https://github.com/BendDAO)
- [Blur.io](https://blur.io)
96 changes: 96 additions & 0 deletions contracts/dependencies/vertex/ArbAirdrop.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import "./interfaces/IArbAirdrop.sol";
import "./Endpoint.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

contract ArbAirdrop is OwnableUpgradeable, IArbAirdrop {
address token;
address sanctions;
uint32 pastWeeks;

mapping(uint32 => bytes32) merkleRoots;
mapping(uint32 => mapping(address => uint256)) claimed;

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}

function initialize(address _token, address _sanctions)
external
initializer
{
__Ownable_init();
token = _token;
sanctions = _sanctions;
}

function registerMerkleRoot(uint32 week, bytes32 merkleRoot)
external
onlyOwner
{
pastWeeks += 1;
require(week == pastWeeks, "Invalid week provided.");
merkleRoots[week] = merkleRoot;
}

function _verifyProof(
uint32 week,
address sender,
uint256 totalAmount,
bytes32[] calldata proof
) internal {
require(claimed[week][sender] == 0, "Already claimed.");
require(
merkleRoots[week] != bytes32(0),
"Week hasn't been registered."
);
require(
!ISanctionsList(sanctions).isSanctioned(sender),
"address is sanctioned."
);
bytes32 leaf = keccak256(
bytes.concat(keccak256(abi.encode(sender, totalAmount)))
);
bool isValidLeaf = MerkleProof.verify(proof, merkleRoots[week], leaf);
require(isValidLeaf, "Invalid proof.");
claimed[week][sender] = totalAmount;
}

function _claim(
uint32 week,
uint256 totalAmount,
bytes32[] calldata proof
) internal {
_verifyProof(week, msg.sender, totalAmount, proof);
SafeERC20.safeTransfer(IERC20(token), msg.sender, totalAmount);
emit ClaimArb(msg.sender, week, totalAmount);
}

function claim(ClaimProof[] calldata claimProofs) external {
for (uint32 i = 0; i < claimProofs.length; i++) {
_claim(
claimProofs[i].week,
claimProofs[i].totalAmount,
claimProofs[i].proof
);
}
}

function getClaimed(address account)
external
view
returns (uint256[] memory)
{
uint256[] memory result = new uint256[](pastWeeks + 1);
for (uint32 week = 1; week <= pastWeeks; week++) {
result[week] = claimed[week][account];
}
return result;
}
}
119 changes: 119 additions & 0 deletions contracts/dependencies/vertex/BaseEngine.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "hardhat/console.sol";

import "./common/Constants.sol";
import "./common/Errors.sol";
import "./libraries/MathHelper.sol";
import "./libraries/MathSD21x18.sol";
import "./interfaces/clearinghouse/IClearinghouse.sol";
import "./interfaces/engine/IProductEngine.sol";
import "./interfaces/IOffchainBook.sol";
import "./interfaces/IFeeCalculator.sol";
import "./interfaces/IEndpoint.sol";
import "./EndpointGated.sol";
import "./interfaces/clearinghouse/IClearinghouseState.sol";

abstract contract BaseEngine is IProductEngine, EndpointGated {
using MathSD21x18 for int128;

IClearinghouse internal _clearinghouse;
IFeeCalculator internal _fees;
uint32[] internal productIds;

// productId => orderbook
mapping(uint32 => IOffchainBook) public markets;

// Whether an address can apply deltas - all orderbooks and clearinghouse is whitelisted
mapping(address => bool) internal canApplyDeltas;

event BalanceUpdate(uint32 productId, bytes32 subaccount);
event ProductUpdate(uint32 productId);

function _productUpdate(uint32 productId) internal virtual {}

function _balanceUpdate(uint32 productId, bytes32 subaccount)
internal
virtual
{}

function checkCanApplyDeltas() internal view virtual {
require(canApplyDeltas[msg.sender], ERR_UNAUTHORIZED);
}

function _initialize(
address _clearinghouseAddr,
address, /* _quoteAddr */
address _endpointAddr,
address _admin,
address _feeAddr
) internal initializer {
__Ownable_init();
setEndpoint(_endpointAddr);
transferOwnership(_admin);

_clearinghouse = IClearinghouse(_clearinghouseAddr);
_fees = IFeeCalculator(_feeAddr);

canApplyDeltas[_endpointAddr] = true;
canApplyDeltas[_clearinghouseAddr] = true;
}

function getClearinghouse() external view returns (address) {
return address(_clearinghouse);
}

function getProductIds() external view returns (uint32[] memory) {
return productIds;
}

function getOrderbook(uint32 productId) public view returns (address) {
return address(markets[productId]);
}

function _addProductForId(
uint32 healthGroup,
IClearinghouseState.RiskStore memory riskStore,
address book,
int128 sizeIncrement,
int128 priceIncrementX18,
int128 minSize,
int128 lpSpreadX18
) internal returns (uint32 productId) {
require(book != address(0));
require(
riskStore.longWeightInitial <= riskStore.longWeightMaintenance &&
riskStore.shortWeightInitial >=
riskStore.shortWeightMaintenance,
ERR_BAD_PRODUCT_CONFIG
);

// register product with clearinghouse
productId = _clearinghouse.registerProductForId(
book,
riskStore,
healthGroup
);

productIds.push(productId);
canApplyDeltas[book] = true;

markets[productId] = IOffchainBook(book);
markets[productId].initialize(
_clearinghouse,
this,
getEndpoint(),
owner(),
_fees,
productId,
sizeIncrement,
priceIncrementX18,
minSize,
lpSpreadX18
);

emit AddProduct(productId);
}
}
Loading
Loading