-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* build: splitter contract * feat: add events * feat: auction option * build: generic splitter * fix: naming * test: conftest * chore: remove hh config * test: splitter * chore: deploy splitter * chore: role manager script * test: import reverts
- Loading branch information
1 parent
0997196
commit 91704a3
Showing
8 changed files
with
596 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
# @version 0.3.7 | ||
|
||
interface IVault: | ||
def asset() -> address: view | ||
def balanceOf(owner: address) -> uint256: view | ||
def redeem(shares: uint256, receiver: address, owner: address, max_loss: uint256) -> uint256: nonpayable | ||
def transfer(receiver: address, amount: uint256) -> bool: nonpayable | ||
|
||
event UpdateManagerRecipient: | ||
newManagerRecipient: indexed(address) | ||
|
||
event UpdateSplitee: | ||
newSplitee: indexed(address) | ||
|
||
event UpdateSplit: | ||
newSplit: uint256 | ||
|
||
event UpdateMaxLoss: | ||
newMaxLoss: uint256 | ||
|
||
event UpdateAuction: | ||
newAuction: address | ||
|
||
MAX_BPS: constant(uint256) = 10_000 | ||
MAX_ARRAY_SIZE: public(constant(uint256)) = 20 | ||
|
||
name: public(String[64]) | ||
|
||
# Bid daddy yankee in charge of the splitter | ||
manager: public(address) | ||
# Address to receive the managers shares | ||
managerRecipient: public(address) | ||
# Team to receive the rest of the split | ||
splitee: public(address) | ||
|
||
# Percent that is sent to `managerRecipient` | ||
split: public(uint256) | ||
# Max loss to use on vault redeems | ||
maxLoss: public(uint256) | ||
|
||
# Address of the contract to conduct dutch auctions for token sales | ||
auction: public(address) | ||
|
||
@external | ||
def initialize( | ||
name: String[64], | ||
manager: address, | ||
manager_recipient: address, | ||
splitee: address, | ||
original_split: uint256 | ||
): | ||
assert self.manager == empty(address), "initialized" | ||
assert manager != empty(address), "ZERO_ADDRESS" | ||
assert manager_recipient != empty(address), "ZERO_ADDRESS" | ||
assert splitee != empty(address), "ZERO_ADDRESS" | ||
assert original_split != 0, "zero split" | ||
|
||
self.name = name | ||
self.manager = manager | ||
self.managerRecipient = manager_recipient | ||
self.splitee = splitee | ||
self.split = original_split | ||
self.maxLoss = 1 | ||
|
||
|
||
###### UNWRAP VAULT TOKENS ###### | ||
|
||
@external | ||
def unwrapVault(vault: address): | ||
assert msg.sender == self.splitee or msg.sender == self.manager, "!allowed" | ||
self._unwrapVault(vault, self.maxLoss) | ||
|
||
@external | ||
def unwrapVaults(vaults: DynArray[address, MAX_ARRAY_SIZE]): | ||
assert msg.sender == self.splitee or msg.sender == self.manager, "!allowed" | ||
|
||
max_loss: uint256 = self.maxLoss | ||
|
||
for vault in vaults: | ||
self._unwrapVault(vault, max_loss) | ||
|
||
@internal | ||
def _unwrapVault(vault: address, max_loss: uint256): | ||
vault_balance: uint256 = IVault(vault).balanceOf(self) | ||
IVault(vault).redeem(vault_balance, self, self, max_loss) | ||
|
||
###### DISTRIBUTE TOKENS ###### | ||
|
||
# split one token | ||
@external | ||
def distributeToken(token: address): | ||
splitee: address = self.splitee | ||
assert msg.sender == splitee or msg.sender == self.manager, "!allowed" | ||
self._distribute(token, self.split, self.managerRecipient, splitee) | ||
|
||
# split an array of tokens | ||
@external | ||
def distributeTokens(tokens: DynArray[address, MAX_ARRAY_SIZE]): | ||
splitee: address = self.splitee | ||
assert msg.sender == splitee or msg.sender == self.manager, "!allowed" | ||
|
||
# Cache the split storage variables | ||
split: uint256 = self.split | ||
manager_recipient: address = self.managerRecipient | ||
|
||
for token in tokens: | ||
self._distribute(token, split, manager_recipient, splitee) | ||
|
||
@internal | ||
def _distribute(token: address, split: uint256, manager_recipient: address, splitee: address): | ||
current_balance: uint256 = IVault(token).balanceOf(self) | ||
manager_split: uint256 = current_balance | ||
|
||
if split != MAX_BPS: | ||
manager_split = unsafe_div(unsafe_mul(current_balance, split), MAX_BPS) | ||
self._transferERC20(token, splitee, unsafe_sub(current_balance, manager_split)) | ||
|
||
self._transferERC20(token, manager_recipient, manager_split) | ||
|
||
###### AUCTION INITIATORS ###### | ||
|
||
@external | ||
def fundAuctions(tokens: DynArray[address, MAX_ARRAY_SIZE]): | ||
assert msg.sender == self.splitee or msg.sender == self.manager, "!allowed" | ||
auction: address = self.auction | ||
|
||
for token in tokens: | ||
amount: uint256 = IVault(token).balanceOf(self) | ||
self._transferERC20(token, auction, amount) | ||
|
||
@external | ||
def fundAuction(token: address, amount: uint256 = max_value(uint256)): | ||
assert msg.sender == self.splitee or msg.sender == self.manager, "!allowed" | ||
|
||
to_send: uint256 = amount | ||
if(amount == max_value(uint256)): | ||
to_send = IVault(token).balanceOf(self) | ||
|
||
self._transferERC20(token, self.auction, to_send) | ||
|
||
@internal | ||
def _transferERC20(token: address, recipient: address, amount: uint256): | ||
# Send tokens to the auction contract. | ||
assert IVault(token).transfer(recipient, amount, default_return_value=True), "transfer failed" | ||
|
||
###### SETTERS ###### | ||
|
||
# update recipients | ||
@external | ||
def setMangerRecipient(new_recipient: address): | ||
assert msg.sender == self.manager, "!manager" | ||
assert new_recipient != empty(address), "ZERO_ADDRESS" | ||
|
||
self.managerRecipient = new_recipient | ||
|
||
log UpdateManagerRecipient(new_recipient) | ||
|
||
@external | ||
def setSplitee(new_splitee: address): | ||
assert msg.sender == self.splitee, "!splitee" | ||
assert new_splitee != empty(address), "ZERO_ADDRESS" | ||
|
||
self.splitee = new_splitee | ||
|
||
log UpdateSplitee(new_splitee) | ||
|
||
# Update Split | ||
@external | ||
def setSplit(new_split: uint256): | ||
assert msg.sender == self.manager, "!manager" | ||
assert new_split != 0, "zero split" | ||
|
||
self.split = new_split | ||
|
||
log UpdateSplit(new_split) | ||
|
||
# Set max loss | ||
@external | ||
def setMaxLoss(new_max_loss: uint256): | ||
assert msg.sender == self.manager, "!manager" | ||
assert new_max_loss <= MAX_BPS, "MAX_BPS" | ||
|
||
self.maxLoss = new_max_loss | ||
|
||
log UpdateMaxLoss(new_max_loss) | ||
|
||
@external | ||
def setAuction(new_auction: address): | ||
assert msg.sender == self.manager, "!manager" | ||
|
||
self.auction = new_auction | ||
|
||
log UpdateAuction(new_auction) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# @version 0.3.7 | ||
|
||
interface ISplitter: | ||
def initialize( | ||
name: String[64], | ||
manager: address, | ||
manager_recipient: address, | ||
splitee: address, | ||
original_split: uint256 | ||
): nonpayable | ||
|
||
event NewSplitter: | ||
splitter: indexed(address) | ||
manager: indexed(address) | ||
manager_recipient: indexed(address) | ||
splitee: address | ||
|
||
# The address that all newly deployed vaults are based from. | ||
ORIGINAL: public(immutable(address)) | ||
|
||
@external | ||
def __init__(original: address): | ||
ORIGINAL = original | ||
|
||
|
||
@external | ||
def newSplitter( | ||
name: String[64], | ||
manager: address, | ||
manager_recipient: address, | ||
splitee: address, | ||
original_split: uint256 | ||
) -> address: | ||
|
||
# Clone a new version of the splitter | ||
new_splitter: address = create_minimal_proxy_to( | ||
ORIGINAL, | ||
value=0 | ||
) | ||
|
||
ISplitter(new_splitter).initialize( | ||
name, | ||
manager, | ||
manager_recipient, | ||
splitee, | ||
original_split | ||
) | ||
|
||
log NewSplitter(new_splitter, manager, manager_recipient, splitee) | ||
return new_splitter |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
from ape import project, accounts, Contract, chain, networks | ||
from hexbytes import HexBytes | ||
from scripts.deployments import getSalt, deploy_contract | ||
|
||
|
||
def deploy_splitter_factory(): | ||
print("Deploying Splitter Factory on ChainID", chain.chain_id) | ||
|
||
if input("Do you want to continue? ") == "n": | ||
return | ||
|
||
splitter = project.Splitter | ||
splitter_factory = project.SplitterFactory | ||
|
||
deployer = input("Name of account to use? ") | ||
deployer = accounts.load(deployer) | ||
|
||
salt = getSalt("Splitter Factory") | ||
|
||
print(f"Salt we are using {salt}") | ||
print("Init balance:", deployer.balance / 1e18) | ||
|
||
print(f"Deploying Original.") | ||
|
||
original_deploy_bytecode = HexBytes( | ||
HexBytes(splitter.contract_type.deployment_bytecode.bytecode) | ||
) | ||
|
||
original_address = deploy_contract(original_deploy_bytecode, salt, deployer) | ||
|
||
print(f"Original deployed to {original_address}") | ||
|
||
allocator_constructor = splitter_factory.constructor.encode_input(original_address) | ||
|
||
# generate and deploy | ||
deploy_bytecode = HexBytes( | ||
HexBytes(splitter_factory.contract_type.deployment_bytecode.bytecode) | ||
+ allocator_constructor | ||
) | ||
|
||
print(f"Deploying the Factory...") | ||
|
||
deploy_contract(deploy_bytecode, salt, deployer) | ||
|
||
print("------------------") | ||
print( | ||
f"Encoded Constructor to use for verifaction {allocator_constructor.hex()[2:]}" | ||
) | ||
|
||
|
||
def main(): | ||
deploy_splitter_factory() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.