Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0x70236b36f86AB4bd557Fe9934E1246537B472918
Balance 0 ETH
Nonce 39
Code Size 10172 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

10172 bytes
0x60806040523480156200001157600080fd5b50600436106200020c5760003560e01c806380faa57d1162000125578063cd3daf9d11620000af578063df136d65116200007a578063df136d651462000515578063ebe2b12b146200051f578063f2fde38b1462000529578063f3fef3a3146200054057600080fd5b8063cd3daf9d146200047c578063d1af0c7d1462000486578063d4f8faa714620004ae578063d7f5c90014620004e757600080fd5b8063adc9772e11620000f0578063adc9772e146200043a578063c8f33c911462000451578063cc1a378f146200045b578063ccca123b146200047257600080fd5b806380faa57d14620003b75780638b87634714620003c15780638d23fc6114620003e45780638da5cb5b146200041b57600080fd5b80633c6b16ab11620001a7578063715018a61162000172578063715018a6146200036457806372f702f3146200036e5780637ae2b5c714620003965780637b0a47ee14620003ad57600080fd5b80633c6b16ab14620002f35780633d18b912146200030a5780636e372ef8146200031457806370a08231146200032b57600080fd5b806318160ddd11620001e857806318160ddd14620002775780631c1f78eb14620002805780632d8dea94146200028a578063386a952514620002e957600080fd5b80628cc26214620002115780630700037d146200023b57806307d97918146200025e575b600080fd5b620002286200022236600462001a78565b62000557565b6040519081526020015b60405180910390f35b620002286200024c36600462001a78565b60096020526000908152604090205481565b620002756200026f36600462001a78565b620005f8565b005b600e5462000228565b620002286200084a565b620002c36200029b36600462001a78565b600b6020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200162000232565b6200022860055481565b620002756200030436600462001b1f565b62000863565b6200027562000af1565b620002756200032536600462001b1f565b62000d0a565b620002286200033c36600462001a78565b73ffffffffffffffffffffffffffffffffffffffff166000908152600f602052604090205490565b6200027562000dc9565b620002c37f000000000000000000000000321c2fe4446c7c963dc41dd58879af648838f98d81565b62000228620003a736600462001b53565b62000e5a565b6200022860045481565b6200022862000e74565b62000228620003d236600462001a78565b60086020526000908152604090205481565b6200040a620003f536600462001a78565b600c6020526000908152604090205460ff1681565b604051901515815260200162000232565b60005473ffffffffffffffffffffffffffffffffffffffff16620002c3565b620002756200044b36600462001ace565b62000e84565b6200022860065481565b620002756200046c36600462001b1f565b62001295565b6200022860025481565b6200022862001407565b620002c37f000000000000000000000000321c2fe4446c7c963dc41dd58879af648838f98d81565b620002c3620004bf36600462001a78565b600a6020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b62000228620004f836600462001a96565b600d60209081526000928352604080842090915290825290205481565b6200022860075481565b6200022860035481565b620002756200053a36600462001a78565b62001476565b620002756200055136600462001ace565b620015ac565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600960209081526040808320546008909252822054670de0b6b3a7640000906200059c62001407565b620005a8919062001c0d565b73ffffffffffffffffffffffffffffffffffffffff85166000908152600f6020526040902054620005da919062001bcd565b620005e6919062001b91565b620005f2919062001b76565b92915050565b73ffffffffffffffffffffffffffffffffffffffff81166200067b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f44656c6567617465652063616e2774206265203000000000000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8181166000908152600b602052604090205416156200070c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f44656c656761746f7220616c7265616479206372656174656400000000000000604482015260640162000672565b6000817f000000000000000000000000321c2fe4446c7c963dc41dd58879af648838f98d6040516200073e9062001a40565b73ffffffffffffffffffffffffffffffffffffffff928316815291166020820152604001604051809103906000f0801580156200077f573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff8084166000818152600b6020908152604080832080549587167fffffffffffffffffffffffff00000000000000000000000000000000000000009687168117909155808452600a835281842080549096168517909555600c90915280822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555193945090927f0976a62688d14faa8e35e63a7ada50f147ba1a0357f99182a596f9afea2502f49190a35050565b60006005546004546200085e919062001bcd565b905090565b60005473ffffffffffffffffffffffffffffffffffffffff163314620008e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000672565b620008f2600062001905565b600354421062000914576005546200090b908262001b91565b6004556200095e565b60004260035462000926919062001c0d565b90506000600454826200093a919062001bcd565b6005549091506200094c828562001b76565b62000958919062001b91565b60045550505b426006819055600554620009729162001b76565b6003556040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000321c2fe4446c7c963dc41dd58879af648838f98d73ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381600087803b15801562000a0057600080fd5b505af115801562000a15573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000a3b919062001b39565b90506005548162000a4d919062001b91565b600454111562000aba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f50726f76696465642072657761726420746f6f20686967680000000000000000604482015260640162000672565b6040518281527fde88a922e0d3b88b24e9623efeb464919c6bf9f66857a65e2bfcf2ce87a9433d9060200160405180910390a15050565b6002600154141562000b60576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640162000672565b600260015562000b703362001905565b33600090815260096020526040902054801562000d03573360008181526009602052604080822091909155517fa9059cbb00000000000000000000000000000000000000000000000000000000815260048101919091526024810182905273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000321c2fe4446c7c963dc41dd58879af648838f98d169063a9059cbb90604401602060405180830381600087803b15801562000c2a57600080fd5b505af115801562000c3f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c65919062001afb565b62000ccd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5472616e73666572204661696c65640000000000000000000000000000000000604482015260640162000672565b60405181815233907fe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e04869060200160405180910390a25b5060018055565b60005473ffffffffffffffffffffffffffffffffffffffff16331462000d8d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000672565b60028190556040518181527fd7a3703f78487664fd138129246eed2d18e2fbbe550ea6839eb8717034543a52906020015b60405180910390a150565b60005473ffffffffffffffffffffffffffffffffffffffff16331462000e4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000672565b62000e58600062001982565b565b600081831062000e6b578162000e6d565b825b9392505050565b60006200085e4260035462000e5a565b6002600154141562000ef3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640162000672565b600260015573ffffffffffffffffffffffffffffffffffffffff82166000908152600c602052604090205460ff1662000f89576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420612076616c69642064656c656761746f720000000000000000000000604482015260640162000672565b6000811162000ff5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e2030000000604482015260640162000672565b620010003362001905565b80600e5462001010919062001b76565b600e55336000908152600f60205260409020546200103090829062001b76565b336000818152600f6020526040908190209290925590517fadc9772e000000000000000000000000000000000000000000000000000000008152600481019190915260248101829052829073ffffffffffffffffffffffffffffffffffffffff82169063adc9772e90604401600060405180830381600087803b158015620010b757600080fd5b505af1158015620010cc573d6000803e3d6000fd5b5050505060025442620010e0919062001b76565b336000818152600d6020908152604080832073ffffffffffffffffffffffffffffffffffffffff89811680865291909352928190209490945592517f23b872dd00000000000000000000000000000000000000000000000000000000815260048101929092526024820152604481018490527f000000000000000000000000321c2fe4446c7c963dc41dd58879af648838f98d909116906323b872dd90606401602060405180830381600087803b1580156200119b57600080fd5b505af1158015620011b0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620011d6919062001afb565b6200123e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5472616e73666572204661696c65640000000000000000000000000000000000604482015260640162000672565b604051828152339073ffffffffffffffffffffffffffffffffffffffff8516907f5dac0c1b1112564a045ba943c9d50270893e8e826c49be8e7073adc713ab7bd7906020015b60405180910390a350506001805550565b60005473ffffffffffffffffffffffffffffffffffffffff16331462001318576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000672565b6003544211620013d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152605860248201527f50726576696f7573207265776172647320706572696f64206d7573742062652060448201527f636f6d706c657465206265666f7265206368616e67696e67207468652064757260648201527f6174696f6e20666f7220746865206e657720706572696f640000000000000000608482015260a40162000672565b60058190556040518181527ffb46ca5a5e06d4540d6387b930a7c978bce0db5f449ec6b3f5d07c6e1d44f2d39060200162000dbe565b6000600e54600014156200141c575060075490565b600e546004546006546200142f62000e74565b6200143b919062001c0d565b62001447919062001bcd565b6200145b90670de0b6b3a764000062001bcd565b62001467919062001b91565b6007546200085e919062001b76565b60005473ffffffffffffffffffffffffffffffffffffffff163314620014f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000672565b73ffffffffffffffffffffffffffffffffffffffff81166200159e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840162000672565b620015a98162001982565b50565b600260015414156200161b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640162000672565b600260015573ffffffffffffffffffffffffffffffffffffffff82166000908152600c602052604090205460ff16620016b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420612076616c69642064656c656761746f720000000000000000000000604482015260640162000672565b600081116200171d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e2030000000604482015260640162000672565b336000908152600d6020908152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902054421015620017df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f4e65656420746f207761697420746865206d696e696d756d207374616b696e6760448201527f20706572696f6400000000000000000000000000000000000000000000000000606482015260840162000672565b620017ea3362001905565b80600e54620017fa919062001c0d565b600e55336000908152600f60205260409020546200181a90829062001c0d565b336000818152600f6020526040908190209290925590517f68ce7d8a000000000000000000000000000000000000000000000000000000008152600481019190915260248101829052829073ffffffffffffffffffffffffffffffffffffffff8216906368ce7d8a90604401600060405180830381600087803b158015620018a157600080fd5b505af1158015620018b6573d6000803e3d6000fd5b505060405184815233925073ffffffffffffffffffffffffffffffffffffffff861691507fd1c19fbcd4551a5edfb66d43d2e337c04837afda3482b42bdf569a8fccdae5fb9060200162001284565b6200190f62001407565b6007556200191c62000e74565b60065573ffffffffffffffffffffffffffffffffffffffff811615620015a9576200194781620019f7565b73ffffffffffffffffffffffffffffffffffffffff821660009081526009602090815260408083209390935560075460089091529190205550565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600960209081526040808320546008909252822054600754670de0b6b3a764000091620005a89162001c0d565b610b308062001c5783390190565b803573ffffffffffffffffffffffffffffffffffffffff8116811462001a7357600080fd5b919050565b60006020828403121562001a8b57600080fd5b62000e6d8262001a4e565b6000806040838503121562001aaa57600080fd5b62001ab58362001a4e565b915062001ac56020840162001a4e565b90509250929050565b6000806040838503121562001ae257600080fd5b62001aed8362001a4e565b946020939093013593505050565b60006020828403121562001b0e57600080fd5b8151801515811462000e6d57600080fd5b60006020828403121562001b3257600080fd5b5035919050565b60006020828403121562001b4c57600080fd5b5051919050565b6000806040838503121562001b6757600080fd5b50508035926020909101359150565b6000821982111562001b8c5762001b8c62001c27565b500190565b60008262001bc8577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161562001c085762001c0862001c27565b500290565b60008282101562001c225762001c2262001c27565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fdfe60a060405234801561001057600080fd5b50604051610b30380380610b3083398101604081905261002f91610243565b610038336101d7565b6001600160a01b0382161580159061005857506001600160a01b03811615155b61009e5760405162461bcd60e51b81526020600482015260126024820152710416464726573732063616e277420626520360741b60448201526064015b60405180910390fd5b806001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156100d957600080fd5b505af11580156100ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101119190610276565b60ff166012146101635760405162461bcd60e51b815260206004820152601360248201527f446563696d616c73206d757374206265203138000000000000000000000000006044820152606401610095565b606081901b6001600160601b0319166080526040516317066a5760e21b81526001600160a01b038381166004830152821690635c19a95c90602401600060405180830381600087803b1580156101b857600080fd5b505af11580156101cc573d6000803e3d6000fd5b5050505050506102a0565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b038116811461023e57600080fd5b919050565b6000806040838503121561025657600080fd5b61025f83610227565b915061026d60208401610227565b90509250929050565b60006020828403121561028857600080fd5b815160ff8116811461029957600080fd5b9392505050565b60805160601c6108646102cc60003960008181610153015281816101a6015261034801526108646000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063adc9772e1161005b578063adc9772e146100fa578063eca5b8d31461010d578063f2fde38b1461013b578063fc0c546a1461014e57600080fd5b80631e31d0531461008d57806368ce7d8a146100bf578063715018a6146100d45780638da5cb5b146100dc575b600080fd5b610095610175565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100d26100cd366004610760565b61023c565b005b6100d261042e565b60005473ffffffffffffffffffffffffffffffffffffffff16610095565b6100d2610108366004610760565b6104bb565b61012d61011b36600461071f565b60016020526000908152604090205481565b6040519081526020016100b6565b6100d261014936600461071f565b61057a565b6100957f000000000000000000000000000000000000000000000000000000000000000081565b6040517f587cde1e0000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063587cde1e90602401602060405180830381600087803b1580156101ff57600080fd5b505af1158015610213573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102379190610743565b905090565b60005473ffffffffffffffffffffffffffffffffffffffff1633146102c2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216600090815260016020526040812080548392906102f79084906107c6565b90915550506040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb90604401602060405180830381600087803b15801561038c57600080fd5b505af11580156103a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103c4919061078c565b61042a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5472616e73666572206661696c6564000000000000000000000000000000000060448201526064016102b9565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146104af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b6104b960006106aa565b565b60005473ffffffffffffffffffffffffffffffffffffffff16331461053c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260016020526040812080548392906105719084906107ae565b90915550505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146105fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016102b9565b73ffffffffffffffffffffffffffffffffffffffff811661069e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016102b9565b6106a7816106aa565b50565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006020828403121561073157600080fd5b813561073c8161080c565b9392505050565b60006020828403121561075557600080fd5b815161073c8161080c565b6000806040838503121561077357600080fd5b823561077e8161080c565b946020939093013593505050565b60006020828403121561079e57600080fd5b8151801515811461073c57600080fd5b600082198211156107c1576107c16107dd565b500190565b6000828210156107d8576107d86107dd565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff811681146106a757600080fdfea2646970667358221220cca28e2f7ee296c8b266ffe8a685288d67a173acbc51590725b38714e24354b464736f6c63430008060033a26469706673582212201069c6d86c2120badd37dfccb04497f1147e9a1099451d4cf83df73c17520b4c64736f6c63430008060033

Verified Source Code Full Match

Compiler: v0.8.6+commit.11564f7e EVM: berlin Optimization: Yes (999999 runs)
Delegator.sol 75 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.6;

import "./interfaces/IGovernanceToken.sol";
import "../lib/openzeppelin-contracts/contracts/access/Ownable.sol";

/**
 * @title Delegator Contract
 * @author Cryptex.Finance
 * @notice Contract in charge of handling delegations.
 */

contract Delegator is Ownable {
   /* ========== STATE VARIABLES ========== */

   /// @notice Address of the staking governance token
   address public immutable token;

   /// @notice Tracks the amount of staked tokens per user
   mapping(address => uint256) public stakerBalance;

   /* ========== CONSTRUCTOR ========== */

   /**
    * @notice Constructor
    * @param delegatee_ address
    * @param token_ address
    * @dev when created delegates all it's power to delegatee_ and can't be changed later
    * @dev sets delegator factory as owner
    */
   constructor(address delegatee_, address token_) {
      require(
         delegatee_ != address(0) && token_ != address(0),
         "Address can't be 0"
      );
      require(IGovernanceToken(token_).decimals() == 18, "Decimals must be 18");
      token = token_;
      IGovernanceToken(token_).delegate(delegatee_);
   }

   /* ========== MUTATIVE FUNCTIONS ========== */

   /**
    * @notice Increases the balance of the staker
    * @param staker_ caller of the stake function
    * @param amount_ uint to be staked and delegated
    * @dev Only delegatorFactory can call it
    * @dev after the balance is updated the amount is transferred from the user to this contract
    */
   function stake(address staker_, uint256 amount_) external onlyOwner {
      stakerBalance[staker_] += amount_;
   }

   /**
    * @notice Decreases the balance of the staker
    * @param staker_ caller of the stake function
    * @param amount_ uint to be withdrawn and undelegated
    * @dev Only delegatorFactory can call it
    * @dev after the balance is updated the amount is transferred back to the user from this contract
    */
   function removeStake(address staker_, uint256 amount_) external onlyOwner {
      stakerBalance[staker_] -= amount_;
      require(
         IGovernanceToken(token).transfer(staker_, amount_),
         "Transfer failed"
      );
   }

   /* ========== VIEWS ========== */

   /// @notice returns the delegatee of this contract
   function delegatee() external returns (address) {
      return IGovernanceToken(token).delegates(address(this));
   }
}
DelegatorFactory.sol 360 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.6;

import "./interfaces/IGovernanceToken.sol";
import "./Delegator.sol";
import "../lib/openzeppelin-contracts/contracts/access/Ownable.sol";
import "../lib/openzeppelin-contracts/contracts/security/ReentrancyGuard.sol";

/**
 * @title Delegator Contract Factory
 * @author Cryptex.Finance
 * @notice Contract in charge of generating Delegator contracts, handling delegations and CTX balance map, rewards.
 */

contract DelegatorFactory is Ownable, ReentrancyGuard {
   /* ========== STATE VARIABLES ========== */

   /// @notice Address of the staking governance token
   address public immutable stakingToken;

   /// @notice Address of the reward token
   address public immutable rewardsToken;

   /// @notice Minimum wait time before removing stake
   uint256 public waitTime;

   /// @notice Tracks the period where users stop earning rewards
   uint256 public periodFinish = 0;
   uint256 public rewardRate = 0;

   /// @notice How long the rewards lasts, it updates when more rewards are added
   uint256 public rewardsDuration = 186 days;

   /// @notice Last time rewards were updated
   uint256 public lastUpdateTime;

   /// @notice Amount of reward calculated per token stored
   uint256 public rewardPerTokenStored;

   /// @notice Track the rewards paid to users
   mapping(address => uint256) public userRewardPerTokenPaid;

   /// @notice Tracks the user rewards
   mapping(address => uint256) public rewards;

   /// @notice Tracks the address of a delegatee with a delegator contract address
   mapping(address => address) public delegatorToDelegatee;

   /// @notice Tracks the delegator contract address from delegatee address
   mapping(address => address) public delegateeToDelegator;

   /// @notice Tracks if address is an official delegator
   mapping(address => bool) public delegators;

   /// @notice Tracks minimum wait time the account has to wait before removing stake
   mapping(address => mapping(address => uint256)) public stakerWaitTime;

   /// @dev Tracks the total supply of staked tokens
   uint256 private _totalSupply;

   /// @dev Tracks the amount of staked tokens per user
   mapping(address => uint256) private _balances;

   /* ========== EVENTS ========== */

   /// @notice An event emitted when a Delegator is created
   event DelegatorCreated(address indexed delegator, address indexed delegatee);

   /// @notice An event emitted when an user has staked and delegated
   event Staked(
      address indexed delegator,
      address indexed delegatee,
      uint256 amount
   );

   /// @notice An event emitted when an user removes stake and undelegated
   event Withdrawn(
      address indexed delegator,
      address indexed delegatee,
      uint256 amount
   );

   /// @notice An event emitted when the minimum wait time is updated
   event WaitTimeUpdated(uint256 waitTime);

   /// @notice An event emitted when a reward is added
   event RewardAdded(uint256 reward);

   /// @notice An event emitted when reward is paid to a user
   event RewardPaid(address indexed user, uint256 reward);

   /// @notice An event emitted when the rewards duration is updated
   event RewardsDurationUpdated(uint256 newDuration);

   /* ========== CONSTRUCTOR ========== */

   /**
    * @notice Constructor
    * @param stakingToken_ address
    * @param rewardsToken_ address
    * @param waitTime_ uint256
    * @param timelock_ address
    * @dev transfers ownership to timelock
    */
   constructor(
      address stakingToken_,
      address rewardsToken_,
      uint256 waitTime_,
      address timelock_
   ) {
      require(
         stakingToken_ != address(0) &&
            rewardsToken_ != address(0) &&
            timelock_ != address(0),
         "Address can't be 0"
      );
      require(
         IGovernanceToken(stakingToken_).decimals() == 18 &&
            IGovernanceToken(rewardsToken_).decimals() == 18,
         "Decimals must be 18"
      );
      stakingToken = stakingToken_;
      rewardsToken = rewardsToken_;
      waitTime = waitTime_;
      transferOwnership(timelock_);
   }

   /* ========== MUTATIVE FUNCTIONS ========== */

   /**
    * @notice Updates the reward and time on call.
    * @param account_ address
    */
   function updateReward(address account_) private {
      rewardPerTokenStored = rewardPerToken();
      lastUpdateTime = lastTimeRewardApplicable();

      if (account_ != address(0)) {
         rewards[account_] = currentEarned(account_);
         userRewardPerTokenPaid[account_] = rewardPerTokenStored;
      }
   }

   /**
    * @notice Notifies the contract that reward has been added to be given.
    * @param reward_ uint
    * @dev Only owner  can call it
    * @dev Increases duration of rewards
    */
   function notifyRewardAmount(uint256 reward_) external onlyOwner {
      updateReward(address(0));
      if (block.timestamp >= periodFinish) {
         rewardRate = reward_ / rewardsDuration;
      } else {
         uint256 remaining = periodFinish - block.timestamp;
         uint256 leftover = remaining * rewardRate;
         rewardRate = (reward_ + leftover) / rewardsDuration;
      }

      lastUpdateTime = block.timestamp;
      periodFinish = block.timestamp + rewardsDuration;

      // Ensure the provided reward amount is not more than the balance in the contract.
      // This keeps the reward rate in the right range, preventing overflows due to
      // very high values of rewardRate in the earned and rewardsPerToken functions;
      // Reward + leftover must be less than 2^256 / 10^18 to avoid overflow.
      uint256 balance = IGovernanceToken(rewardsToken).balanceOf(address(this));
      require(
         rewardRate <= balance / rewardsDuration,
         "Provided reward too high"
      );
      emit RewardAdded(reward_);
   }

   /**
    * @notice  Updates the reward duration
    * @param rewardsDuration_ uint
    * @dev Only owner can call it
    * @dev Previous rewards must be complete
    */
   function setRewardsDuration(uint256 rewardsDuration_) external onlyOwner {
      require(
         block.timestamp > periodFinish,
         "Previous rewards period must be complete before changing the duration for the new period"
      );
      rewardsDuration = rewardsDuration_;
      emit RewardsDurationUpdated(rewardsDuration);
   }

   /**
    * @notice Transfers to the caller the current amount of rewards tokens earned.
    * @dev updates rewards on call
    */
   function getReward() external nonReentrant {
      updateReward(msg.sender);
      uint256 reward = rewards[msg.sender];
      if (reward > 0) {
         rewards[msg.sender] = 0;
         require(
            IGovernanceToken(rewardsToken).transfer(msg.sender, reward),
            "Transfer Failed"
         );
         emit RewardPaid(msg.sender, reward);
      }
   }

   /**
    * @notice Creates a new delegator contract that delegates all votes to delegatee_
    * @param delegatee_ address that will be receiving all votes
    * @dev only one delegator contract pointing to the same delegatee can exist
    */
   function createDelegator(address delegatee_) external {
      require(delegatee_ != address(0), "Delegatee can't be 0");
      require(
         delegateeToDelegator[delegatee_] == address(0),
         "Delegator already created"
      );
      Delegator delegator = new Delegator(delegatee_, stakingToken);
      delegateeToDelegator[delegatee_] = address(delegator);
      delegatorToDelegatee[address(delegator)] = delegatee_;
      delegators[address(delegator)] = true;
      emit DelegatorCreated(address(delegator), delegatee_);
   }

   /**
    * @notice Stakes to delegator_ the amount_ specified
    * @param delegator_ contract address where to send the amount_
    * @param amount_ uint to be staked and delegated
    * @dev Delegator must be valid and amount has to be greater than 0
    * @dev amount_ is transferred to the delegator contract and staker starts earning rewards if active
    * @dev updates rewards on call
    */
   function stake(address delegator_, uint256 amount_) external nonReentrant {
      require(delegators[delegator_], "Not a valid delegator");
      require(amount_ > 0, "Amount must be greater than 0");
      updateReward(msg.sender);
      _totalSupply = _totalSupply + amount_;
      _balances[msg.sender] = _balances[msg.sender] + amount_;
      Delegator d = Delegator(delegator_);
      d.stake(msg.sender, amount_);
      stakerWaitTime[msg.sender][delegator_] = block.timestamp + waitTime;
      require(
         IGovernanceToken(stakingToken).transferFrom(
            msg.sender,
            delegator_,
            amount_
         ),
         "Transfer Failed"
      );
      emit Staked(delegator_, msg.sender, amount_);
   }

   /**
    * @notice Removes amount_ from delegator_
    * @param delegator_ contract address where to remove the stake from
    * @param amount_ uint to be removed from stake and undelegated
    * @dev Delegator must be valid and amount has to be greater than 0
    * @dev amount_ must be <= that current user stake
    * @dev amount_ is transferred from the  delegator contract to the staker
    * @dev updates rewards on call
    * @dev requires that at least waitTime has passed since delegation to unDelegate
    */
   function withdraw(address delegator_, uint256 amount_)
      external
      nonReentrant
   {
      require(delegators[delegator_], "Not a valid delegator");
      require(amount_ > 0, "Amount must be greater than 0");
      require(
         block.timestamp >= stakerWaitTime[msg.sender][delegator_],
         "Need to wait the minimum staking period"
      );
      updateReward(msg.sender);
      _totalSupply = _totalSupply - amount_;
      _balances[msg.sender] = _balances[msg.sender] - amount_;
      Delegator d = Delegator(delegator_);
      d.removeStake(msg.sender, amount_);
      emit Withdrawn(delegator_, msg.sender, amount_);
   }

   /**
    * @notice updates the min wait time between delegation and unDelegation
    * @param waitTime_ uint new wait time
    * @dev only the owner can call it
    */
   function updateWaitTime(uint256 waitTime_) external onlyOwner {
      waitTime = waitTime_;
      emit WaitTimeUpdated(waitTime_);
   }

   /* ========== VIEWS ========== */

   /**
    * @notice Returns the amount of reward tokens a user has earned.
    * @param account_ address
    */
   function currentEarned(address account_) private view returns (uint256) {
      return
         (_balances[account_] *
            (rewardPerTokenStored - userRewardPerTokenPaid[account_])) /
         1e18 +
         rewards[account_];
   }

   /// @notice Returns the total amount of staked tokens.
   function totalSupply() external view returns (uint256) {
      return _totalSupply;
   }

   /**
    * @notice Returns the amount of staked tokens from specific user
    * @param account_ address
    */
   function balanceOf(address account_) external view returns (uint256) {
      return _balances[account_];
   }

   /// @notice Returns reward rate for a duration
   function getRewardForDuration() external view returns (uint256) {
      return rewardRate * rewardsDuration;
   }

   /// @notice Returns the minimum between current block timestamp or the finish period of rewards.
   function lastTimeRewardApplicable() public view returns (uint256) {
      return min(block.timestamp, periodFinish);
   }

   /// @notice Returns the calculated reward per token deposited.
   function rewardPerToken() public view returns (uint256) {
      if (_totalSupply == 0) {
         return rewardPerTokenStored;
      }

      return
         rewardPerTokenStored +
         ((lastTimeRewardApplicable() - lastUpdateTime) * rewardRate * 1e18) /
         _totalSupply;
   }

   /**
    * @notice Returns the amount of reward tokens a user has earned.
    * @param account_ address
    */
   function earned(address account_) public view returns (uint256) {
      return
         (_balances[account_] *
            (rewardPerToken() - userRewardPerTokenPaid[account_])) /
         1e18 +
         rewards[account_];
   }

   /**
    * @notice Returns the minimum between two variables
    * @param a_ uint
    * @param b_ uint
    */
   function min(uint256 a_, uint256 b_) public pure returns (uint256) {
      return a_ < b_ ? a_ : b_;
   }
}
IGovernanceToken.sol 20 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.8.6;

interface IGovernanceToken {
   function delegate(address delegatee) external;

   function delegates(address delegator) external returns (address);

   function transfer(address dst, uint256 rawAmount) external returns (bool);

   function transferFrom(
      address src,
      address dst,
      uint256 rawAmount
   ) external returns (bool);

   function balanceOf(address src) external returns (uint256);

   function decimals() external returns (uint8);
}
Context.sol 23 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}
Ownable.sol 75 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}
ReentrancyGuard.sol 62 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

Read Contract

balanceOf 0x70a08231 → uint256
delegateeToDelegator 0x2d8dea94 → address
delegatorToDelegatee 0xd4f8faa7 → address
delegators 0x8d23fc61 → bool
earned 0x008cc262 → uint256
getRewardForDuration 0x1c1f78eb → uint256
lastTimeRewardApplicable 0x80faa57d → uint256
lastUpdateTime 0xc8f33c91 → uint256
min 0x7ae2b5c7 → uint256
owner 0x8da5cb5b → address
periodFinish 0xebe2b12b → uint256
rewardPerToken 0xcd3daf9d → uint256
rewardPerTokenStored 0xdf136d65 → uint256
rewardRate 0x7b0a47ee → uint256
rewards 0x0700037d → uint256
rewardsDuration 0x386a9525 → uint256
rewardsToken 0xd1af0c7d → address
stakerWaitTime 0xd7f5c900 → uint256
stakingToken 0x72f702f3 → address
totalSupply 0x18160ddd → uint256
userRewardPerTokenPaid 0x8b876347 → uint256
waitTime 0xccca123b → uint256

Write Contract 9 functions

These functions modify contract state and require a wallet transaction to execute.

createDelegator 0x07d97918
address delegatee_
getReward 0x3d18b912
No parameters
notifyRewardAmount 0x3c6b16ab
uint256 reward_
renounceOwnership 0x715018a6
No parameters
setRewardsDuration 0xcc1a378f
uint256 rewardsDuration_
stake 0xadc9772e
address delegator_
uint256 amount_
transferOwnership 0xf2fde38b
address newOwner
updateWaitTime 0x6e372ef8
uint256 waitTime_
withdraw 0xf3fef3a3
address delegator_
uint256 amount_

Recent Transactions

No transactions found for this address