S Price: $0.457414 (-0.49%)

Contract

0xb61915609e6Dc7A7261b678073c53BaC5875a8B4

Overview

S Balance

Sonic LogoSonic LogoSonic Logo0 S

S Value

$0.00

Multichain Info

No addresses found
Amount:Between 1-100
Reset Filter

Transaction Hash
Method
Block
From
To

There are no matching entries

Update your filters to view other transactions

Parent Transaction Hash Block From To
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Simple Vesting Escrow

Compiler Version
vyper:0.3.10

Optimization Enabled:
N/A

Other Settings:
default evmVersion, MIT license

Contract Source Code (Vyper language format)

# @version 0.3.10

"""
@title Simple Vesting Escrow
@author Curve Finance, Yearn Finance
@license MIT
@notice Vests ERC20 tokens for a single address
@dev Intended to be deployed many times via `VotingEscrowFactory`
"""

from vyper.interfaces import ERC20


event Claim:
    recipient: indexed(address)
    claimed: uint256


event Revoked:
    recipient: address
    owner: address
    rugged: uint256
    ts: uint256


event Disowned:
    owner: address


event SetOpenClaim:
    state: bool


recipient: public(address)
token: public(ERC20)
start_time: public(uint256)
end_time: public(uint256)
cliff_length: public(uint256)
total_locked: public(uint256)
total_claimed: public(uint256)
disabled_at: public(uint256)
open_claim: public(bool)
initialized: public(bool)

owner: public(address)


@external
def __init__():
    # ensure that the original contract cannot be initialized
    self.initialized = True


@external
def initialize(
    owner: address,
    token: ERC20,
    recipient: address,
    amount: uint256,
    start_time: uint256,
    end_time: uint256,
    cliff_length: uint256,
    open_claim: bool,
) -> bool:
    """
    @notice Initialize the contract
    @dev This function is seperate from `__init__` because of the factory pattern
         used in `VestingEscrowFactory.deploy_vesting_contract`. It may be called
         once per deployment
    @param owner Owner address
    @param token Address of the ERC20 token being distributed
    @param recipient Address to vest tokens for
    @param amount Amount of tokens being vested for `recipient`
    @param start_time Epoch time at which token distribution starts
    @param end_time Time until everything should be vested
    @param cliff_length Duration (in seconds) after which the first portion vests
    @param open_claim Switch if anyone can claim for `recipient`
    """
    assert not self.initialized  # dev: can only initialize once
    self.initialized = True

    self.token = token
    self.owner = owner
    self.start_time = start_time
    self.end_time = end_time
    self.cliff_length = cliff_length

    self.recipient = recipient
    self.disabled_at = end_time  # Set to maximum time
    self.total_locked = amount
    self.open_claim = open_claim

    return True


@internal
@view
def _total_vested_at(time: uint256 = block.timestamp) -> uint256:
    start: uint256 = self.start_time
    end: uint256 = self.end_time
    locked: uint256 = self.total_locked
    if time < start + self.cliff_length:
        return 0
    return min(locked * (time - start) / (end - start), locked)


@internal
@view
def _unclaimed(time: uint256 = block.timestamp) -> uint256:
    return self._total_vested_at(time) - self.total_claimed


@external
@view
def unclaimed() -> uint256:
    """
    @notice Get the number of unclaimed, vested tokens for recipient
    @dev If `revoke` is activated, limit by the activation timestamp
    """
    return self._unclaimed(min(block.timestamp, self.disabled_at))


@internal
@view
def _locked(time: uint256 = block.timestamp) -> uint256:
    return self._total_vested_at(self.disabled_at) - self._total_vested_at(time)


@external
@view
def locked() -> uint256:
    """
    @notice Get the number of locked tokens for recipient
    @dev If `revoke` is activated, limit by the activation timestamp
    """
    return self._locked(min(block.timestamp, self.disabled_at))


@external
def claim(beneficiary: address = msg.sender, amount: uint256 = max_value(uint256)) -> uint256:
    """
    @notice Claim tokens which have vested
    @param beneficiary Address to transfer claimed tokens to
    @param amount Amount of tokens to claim
    """
    recipient: address = self.recipient
    assert msg.sender == recipient or self.open_claim and recipient == beneficiary  # dev: not authorized

    claim_period_end: uint256 = min(block.timestamp, self.disabled_at)
    claimable: uint256 = min(self._unclaimed(claim_period_end), amount)
    self.total_claimed += claimable

    assert self.token.transfer(beneficiary, claimable, default_return_value=True)
    log Claim(beneficiary, claimable)

    return claimable


@external
def revoke(ts: uint256 = block.timestamp, beneficiary: address = msg.sender):
    """
    @notice Disable further flow of tokens and clawback the unvested part to `beneficiary`
            Revoking more than once is futile
    @dev Owner is set to zero address
    @param ts Timestamp of the clawback
    @param beneficiary Recipient of the unvested part
    """
    owner: address = self.owner
    assert msg.sender == owner  # dev: not owner
    assert ts >= block.timestamp and ts < self.end_time  # dev: no back to the future

    ruggable: uint256 = self._locked(ts)
    self.disabled_at = ts
    self.owner = empty(address)

    assert self.token.transfer(beneficiary, ruggable, default_return_value=True)

    log Disowned(owner)
    log Revoked(self.recipient, owner, ruggable, ts)


@external
def disown():
    """
    @notice Renounce owner control of the escrow
    """
    owner: address = self.owner
    assert msg.sender == owner  # dev: not owner
    self.owner = empty(address)

    log Disowned(owner)


@external
def set_open_claim(open_claim: bool):
    """
    @notice Disallow or let anyone claim tokens for `recipient`
    """
    assert msg.sender == self.recipient  # dev: not recipient
    self.open_claim = open_claim

    log SetOpenClaim(open_claim)


@external
def collect_dust(token: ERC20, beneficiary: address = msg.sender):
    recipient: address = self.recipient
    assert msg.sender == recipient or self.open_claim and recipient == beneficiary  # dev: not authorized

    amount: uint256 = token.balanceOf(self)
    if token == self.token:
        amount = amount + self.total_claimed - self._total_vested_at(self.disabled_at)

    assert token.transfer(beneficiary, amount, default_return_value=True)
    assert self.token.balanceOf(self) >= (self._total_vested_at(self.disabled_at) - self.total_claimed)

Contract Security Audit

Contract ABI

API
[{"name":"Claim","inputs":[{"name":"recipient","type":"address","indexed":true},{"name":"claimed","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"Revoked","inputs":[{"name":"recipient","type":"address","indexed":false},{"name":"owner","type":"address","indexed":false},{"name":"rugged","type":"uint256","indexed":false},{"name":"ts","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"Disowned","inputs":[{"name":"owner","type":"address","indexed":false}],"anonymous":false,"type":"event"},{"name":"SetOpenClaim","inputs":[{"name":"state","type":"bool","indexed":false}],"anonymous":false,"type":"event"},{"stateMutability":"nonpayable","type":"constructor","inputs":[],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"initialize","inputs":[{"name":"owner","type":"address"},{"name":"token","type":"address"},{"name":"recipient","type":"address"},{"name":"amount","type":"uint256"},{"name":"start_time","type":"uint256"},{"name":"end_time","type":"uint256"},{"name":"cliff_length","type":"uint256"},{"name":"open_claim","type":"bool"}],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"unclaimed","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"locked","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"claim","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"claim","inputs":[{"name":"beneficiary","type":"address"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"claim","inputs":[{"name":"beneficiary","type":"address"},{"name":"amount","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"nonpayable","type":"function","name":"revoke","inputs":[],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"revoke","inputs":[{"name":"ts","type":"uint256"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"revoke","inputs":[{"name":"ts","type":"uint256"},{"name":"beneficiary","type":"address"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"disown","inputs":[],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"set_open_claim","inputs":[{"name":"open_claim","type":"bool"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"collect_dust","inputs":[{"name":"token","type":"address"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"collect_dust","inputs":[{"name":"token","type":"address"},{"name":"beneficiary","type":"address"}],"outputs":[]},{"stateMutability":"view","type":"function","name":"recipient","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"token","inputs":[],"outputs":[{"name":"","type":"address"}]},{"stateMutability":"view","type":"function","name":"start_time","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"end_time","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"cliff_length","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"total_locked","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"total_claimed","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"disabled_at","inputs":[],"outputs":[{"name":"","type":"uint256"}]},{"stateMutability":"view","type":"function","name":"open_claim","inputs":[],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"initialized","inputs":[],"outputs":[{"name":"","type":"bool"}]},{"stateMutability":"view","type":"function","name":"owner","inputs":[],"outputs":[{"name":"","type":"address"}]}]

3461001b5760016009556109e261001f610000396109e2610000f35b5f80fd5f3560e01c60026017820660011b6109b401601e395f51565b6366d003ac811861003357346109b0575f5460405260206040f35b636af904c6811861004f57346109b05760065460405260206040f35b6320c5429b81186108ae576024361034176109b0576004356101205233610140526101ed566108ae565b63fc0c546a81186108ae57346109b05760015460405260206040f36108ae565b63834ee41781186100b557346109b05760025460405260206040f35b6394abf76081186100d157346109b05760045460405260206040f35b634e71d92d81186108ae57346109b05733610100527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61012052610552566108ae565b631624335681186108ae57346109b05760035460405260206040f36108ae565b633c48a620811861015057346109b05760055460405260206040f35b631e9bf0da81186108ae57346109b057600a5460405260405133186109b0575f600a557fcf205606725a75744e28493139759507ffff2197fec2eafab0c70c8f126d819d60405160605260206060a1006108ae565b63ac1a2f6981186101c157346109b05760075460405260206040f35b6320d154da81186108ae576044361034176109b057600435610120526024358060a01c6109b057610140525b600a54610160526101605133186109b0574261012051101561020f575f610218565b60035461012051105b156109b0576101205160c05261022f6101a0610975565b6101a05161018052610120516007555f600a5560015463a9059cbb6101a052610140516101c052610180516101e05260206101a060446101bc5f855af1610278573d5f5f3e3d5ffd5b3d61028f57803b156109b0576001610200526102a8565b60203d106109b0576101a0518060011c6109b057610200525b610200905051156109b0577fcf205606725a75744e28493139759507ffff2197fec2eafab0c70c8f126d819d610160516101a05260206101a0a17f425a9d51f657355700ba416a4e9e606a23b8c5831a992441ddf42544656e3a8e5f546101a052610160516101c052610180516101e052610120516102005260806101a0a1006108ae565b632b584faa81186108ae57346109b05760085460405260206040f36108ae565b63158ef93e811861036957346109b05760095460405260206040f35b638956c98381186108ae576024361034176109b0573360e052610714566108ae565b638da5cb5b81186103a757346109b057600a5460405260206040f35b63669416b881186103dd57346109b0576020426007548082811882841002189050905060c0526103d861010061094c565b610100f35b631e83409a81186108ae576024361034176109b0576004358060a01c6109b057610100527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61012052610552566108ae565b63f586c19f81186108ae57610104361034176109b0576004358060a01c6109b0576040526024358060a01c6109b0576060526044358060a01c6109b05760805260e4358060011c6109b05760a0526009546109b0576001600955606051600155604051600a5560843560025560a43560035560c4356004556080515f5560a43560075560643560055560a051600855600160c052602060c0f36108ae565b63cf309012811861050357346109b0576020426007548082811882841002189050905060c0526104fe610120610975565b610120f35b63b6549f7581186108ae57346109b057426101205233610140526101ed566108ae565b63aad3ec9681186108ae576044361034176109b0576004358060a01c6109b05761010052602435610120525b5f5461014052610140513318610569576001610581565b600854610576575f610581565b610100516101405118155b156109b0574260075480828118828410021890509050610160526101605160c0526105ad6101a061094c565b6101a051610120518082811882841002189050905061018052600654610180518082018281106109b0579050905060065560015463a9059cbb6101a052610100516101c052610180516101e05260206101a060446101bc5f855af1610614573d5f5f3e3d5ffd5b3d61062b57803b156109b057600161020052610644565b60203d106109b0576101a0518060011c6109b057610200525b610200905051156109b057610100517f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d4610180516101a05260206101a0a26020610180f36108ae565b63ff8a013081186108ae576024361034176109b0576004358060011c6109b0576040525f5433186109b0576040516008557f4e27d92a6c1bca4eaeb233e05bac94da829072d2af2e4506ab986834d0be08f860405160605260206060a1006108ae565b639d4c2f6981186108ae576044361034176109b0576024358060a01c6109b05760e0525b6004358060a01c6109b05760c0525f5461010052610100513318610739576001610750565b600854610746575f610750565b60e0516101005118155b156109b05760c0516370a082316101405230610160526020610140602461015c845afa61077f573d5f5f3e3d5ffd5b60203d106109b0576101409050516101205260015460c051186107d957610120516006548082018281106109b057905090506007546040526107c26101406108b2565b610140518082038281116109b05790509050610120525b60c05163a9059cbb6101405260e0516101605261012051610180526020610140604461015c5f855af161080e573d5f5f3e3d5ffd5b3d61082557803b156109b05760016101a05261083e565b60203d106109b057610140518060011c6109b0576101a0525b6101a0905051156109b05760075460405261085a6101806108b2565b610180516006548082038281116109b057905090506001546370a082316101405230610160526020610140602461015c845afa610899573d5f5f3e3d5ffd5b60203d106109b057610140905051106109b057005b5f5ffd5b60025460605260035460805260055460a0526060516004548082018281106109b0579050905060405110156108ea575f81525061094a565b60a0516040516060518082038281116109b057905090508082028115838383041417156109b057905090506080516060518082038281116109b0579050905080156109b0578082049050905060a051808281188284100218905090508152505b565b60c05160405261095c60e06108b2565b60e0516006548082038281116109b05790509050815250565b60075460405261098560e06108b2565b60e05160c0516040526109996101006108b2565b610100518082038281116109b05790509050815250565b5f80fd001800990079042f08ae08ae08ae011404cd034d052608ae038b068d032d013408ae06f001a508ae08ae08ae08ae841909e281182e00a16576797065728300030a0015

Deployed Bytecode

0x5f3560e01c60026017820660011b6109b401601e395f51565b6366d003ac811861003357346109b0575f5460405260206040f35b636af904c6811861004f57346109b05760065460405260206040f35b6320c5429b81186108ae576024361034176109b0576004356101205233610140526101ed566108ae565b63fc0c546a81186108ae57346109b05760015460405260206040f36108ae565b63834ee41781186100b557346109b05760025460405260206040f35b6394abf76081186100d157346109b05760045460405260206040f35b634e71d92d81186108ae57346109b05733610100527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61012052610552566108ae565b631624335681186108ae57346109b05760035460405260206040f36108ae565b633c48a620811861015057346109b05760055460405260206040f35b631e9bf0da81186108ae57346109b057600a5460405260405133186109b0575f600a557fcf205606725a75744e28493139759507ffff2197fec2eafab0c70c8f126d819d60405160605260206060a1006108ae565b63ac1a2f6981186101c157346109b05760075460405260206040f35b6320d154da81186108ae576044361034176109b057600435610120526024358060a01c6109b057610140525b600a54610160526101605133186109b0574261012051101561020f575f610218565b60035461012051105b156109b0576101205160c05261022f6101a0610975565b6101a05161018052610120516007555f600a5560015463a9059cbb6101a052610140516101c052610180516101e05260206101a060446101bc5f855af1610278573d5f5f3e3d5ffd5b3d61028f57803b156109b0576001610200526102a8565b60203d106109b0576101a0518060011c6109b057610200525b610200905051156109b0577fcf205606725a75744e28493139759507ffff2197fec2eafab0c70c8f126d819d610160516101a05260206101a0a17f425a9d51f657355700ba416a4e9e606a23b8c5831a992441ddf42544656e3a8e5f546101a052610160516101c052610180516101e052610120516102005260806101a0a1006108ae565b632b584faa81186108ae57346109b05760085460405260206040f36108ae565b63158ef93e811861036957346109b05760095460405260206040f35b638956c98381186108ae576024361034176109b0573360e052610714566108ae565b638da5cb5b81186103a757346109b057600a5460405260206040f35b63669416b881186103dd57346109b0576020426007548082811882841002189050905060c0526103d861010061094c565b610100f35b631e83409a81186108ae576024361034176109b0576004358060a01c6109b057610100527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61012052610552566108ae565b63f586c19f81186108ae57610104361034176109b0576004358060a01c6109b0576040526024358060a01c6109b0576060526044358060a01c6109b05760805260e4358060011c6109b05760a0526009546109b0576001600955606051600155604051600a5560843560025560a43560035560c4356004556080515f5560a43560075560643560055560a051600855600160c052602060c0f36108ae565b63cf309012811861050357346109b0576020426007548082811882841002189050905060c0526104fe610120610975565b610120f35b63b6549f7581186108ae57346109b057426101205233610140526101ed566108ae565b63aad3ec9681186108ae576044361034176109b0576004358060a01c6109b05761010052602435610120525b5f5461014052610140513318610569576001610581565b600854610576575f610581565b610100516101405118155b156109b0574260075480828118828410021890509050610160526101605160c0526105ad6101a061094c565b6101a051610120518082811882841002189050905061018052600654610180518082018281106109b0579050905060065560015463a9059cbb6101a052610100516101c052610180516101e05260206101a060446101bc5f855af1610614573d5f5f3e3d5ffd5b3d61062b57803b156109b057600161020052610644565b60203d106109b0576101a0518060011c6109b057610200525b610200905051156109b057610100517f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d4610180516101a05260206101a0a26020610180f36108ae565b63ff8a013081186108ae576024361034176109b0576004358060011c6109b0576040525f5433186109b0576040516008557f4e27d92a6c1bca4eaeb233e05bac94da829072d2af2e4506ab986834d0be08f860405160605260206060a1006108ae565b639d4c2f6981186108ae576044361034176109b0576024358060a01c6109b05760e0525b6004358060a01c6109b05760c0525f5461010052610100513318610739576001610750565b600854610746575f610750565b60e0516101005118155b156109b05760c0516370a082316101405230610160526020610140602461015c845afa61077f573d5f5f3e3d5ffd5b60203d106109b0576101409050516101205260015460c051186107d957610120516006548082018281106109b057905090506007546040526107c26101406108b2565b610140518082038281116109b05790509050610120525b60c05163a9059cbb6101405260e0516101605261012051610180526020610140604461015c5f855af161080e573d5f5f3e3d5ffd5b3d61082557803b156109b05760016101a05261083e565b60203d106109b057610140518060011c6109b0576101a0525b6101a0905051156109b05760075460405261085a6101806108b2565b610180516006548082038281116109b057905090506001546370a082316101405230610160526020610140602461015c845afa610899573d5f5f3e3d5ffd5b60203d106109b057610140905051106109b057005b5f5ffd5b60025460605260035460805260055460a0526060516004548082018281106109b0579050905060405110156108ea575f81525061094a565b60a0516040516060518082038281116109b057905090508082028115838383041417156109b057905090506080516060518082038281116109b0579050905080156109b0578082049050905060a051808281188284100218905090508152505b565b60c05160405261095c60e06108b2565b60e0516006548082038281116109b05790509050815250565b60075460405261098560e06108b2565b60e05160c0516040526109996101006108b2565b610100518082038281116109b05790509050815250565b5f80fd001800990079042f08ae08ae08ae011404cd034d052608ae038b068d032d013408ae06f001a508ae08ae08ae08ae

Block Transaction Gas Used Reward
view all blocks ##produced##

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.