コード例 #1
0
ファイル: test_transfer.py プロジェクト: pradeeptry/nftoken
    class StateMachine(BaseStateMachine):

        st_amount = strategy("uint256", max_value=1000000)
        st_sender = strategy("address")
        st_receiver = strategy("address")

        def setup(self):
            self.balances = {i: 0 for i in self.accounts}
            self.balances[self.accounts[0]] = self.total_supply

        # transfers an arbitrary amount
        def rule_transfer(self, st_sender, st_receiver, st_amount):
            self._transfer(st_sender, st_receiver, st_amount)

        # transfers the entire balance of an account
        def rule_transfer_all(self, st_sender, st_receiver):
            self._transfer(st_sender, st_receiver, self.balances[st_sender])

        # transfers a single token
        def rule_transfer_one(self, st_sender, st_receiver):
            self._transfer(st_sender, st_receiver, 1)

        # internal shared transfer logic
        def _transfer(self, sender, receiver, amount):
            if amount <= self.balances[sender]:
                self.nft.transfer(receiver, amount, {"from": sender})
                self.balances[sender] -= amount
                self.balances[receiver] += amount
            else:
                with brownie.reverts("dev: underflow"):
                    self.nft.transfer(receiver, amount, {"from": sender})
コード例 #2
0
    class StateMachine(BaseStateMachine):

        st_amount = strategy("uint256", max_value=1000000)
        st_sender = strategy("address")
        st_receiver = strategy("address")

        def __init__(cls, NFToken, accounts):
            super().__init__(cls, NFToken, accounts, len(accounts))
            for account in accounts[1:]:
                cls.nft.transfer(account, 1, {"from": accounts[0]})

        def setup(self):
            self.balances = {i: 1 for i in self.accounts}

        # transfers a single token
        def rule_transfer_one(self, st_sender, st_receiver):
            if self.balances[st_sender]:
                self.nft.transfer(st_receiver, 1, {"from": st_sender})
                self.balances[st_sender] -= 1
                self.balances[st_receiver] += 1
            else:
                with brownie.reverts("dev: underflow"):
                    self.nft.transfer(st_receiver, 1, {"from": st_sender})

        # transfers a single token using transferRange
        def rule_transfer_range_one(self, st_sender, st_receiver):
            if self.balances[st_sender]:
                start = self.nft.rangesOf(st_sender)[-1][0]
                self.nft.transferRange(st_receiver, start, start + 1,
                                       {"from": st_sender})
                self.balances[st_sender] -= 1
                self.balances[st_receiver] += 1
            else:
                with brownie.reverts("dev: underflow"):
                    self.nft.transfer(st_receiver, 1, {"from": st_sender})
コード例 #3
0
    class StateMachine(BaseStateMachine):

        st_idx = strategy("decimal", min_value=0, max_value="0.9999999999")
        st_amount = strategy("decimal", min_value=0, max_value="0.5")
        st_sender = strategy("address")
        st_receiver = strategy("address")

        def __init__(cls, NFToken, accounts):
            super().__init__(cls, NFToken, accounts, 1000)
            for account in accounts[1:]:
                cls.nft.transfer(account, 1000 // len(accounts),
                                 {"from": accounts[0]})

        def setup(self):
            initial = self.total_supply // len(self.accounts)
            self.balances = {i: initial for i in self.accounts}

        # transfers a portion of a range starting from the first token in the range
        def rule_from_start(self, st_sender, st_receiver, st_idx, st_amount):
            start, stop, length = self._get_range(st_sender, st_idx)
            stop = start + int(length * st_amount)
            self._transfer(st_sender, st_receiver, start, stop)

        # transfers a portion of a range, ending with the last token in the range
        def rule_from_end(self, st_sender, st_receiver, st_idx, st_amount):
            start, stop, length = self._get_range(st_sender, st_idx)
            start = stop - int(length * st_amount)
            self._transfer(st_sender, st_receiver, start, stop)

        # transfers a portion of a range, from the middle of an existing range
        def rule_from_middle(self, st_sender, st_receiver, st_idx, st_amount):
            start, stop, length = self._get_range(st_sender, st_idx)
            offset = (length - int(length * st_amount)) // 2
            self._transfer(st_sender, st_receiver, start + offset,
                           stop - offset)

        # transfers an entire range
        def rule_full_range(self, st_sender, st_receiver, st_idx):
            start, stop, length = self._get_range(st_sender, st_idx)
            self._transfer(st_sender, st_receiver, start, stop)

        def _get_range(self, address, pct):
            ranges = self.nft.rangesOf(address)
            if not ranges:
                return 0, 0, 0
            range_ = ranges[int(len(ranges) * pct)]
            return range_[0], range_[1], range_[1] - range_[0]

        def _transfer(self, sender, receiver, start, stop):
            if stop <= start:
                with brownie.reverts():
                    self.nft.transferRange(receiver, start, stop,
                                           {"from": sender})
            else:
                self.nft.transferRange(receiver, start, stop, {"from": sender})
                self.balances[sender] -= stop - start
                self.balances[receiver] += stop - start
コード例 #4
0
ファイル: test_crowdsale.py プロジェクト: deepyr/DreamFrames
class StateMachine:
    st_eth = strategy('uint256', max_value="10 ether")
    st_usd = strategy('uint256', max_value="1000000 ether")
    st_sleep = strategy('uint256', max_value=60000)
    st_address = strategy('address')

    def __init__(cls, accounts, contract):
        # deploy the contract at the start of the test
        cls.accounts = accounts
        cls.contract = contract

    def setup(self):
        # zero the deposit amounts at the start of each test run
        self.contributed_usd = 0
        self.hardcap_usd = 3000000 * 10 ** 18  # in USD with 18 decimals
        self.frame_usd = self.contract.frameUsd({'from': accounts[1]})

    def rule_buy_with_eth(self, st_address, st_eth):
        # make a deposit and adjust the local record
        tx = self.contract.calculateEthFrames(st_eth, st_address, {'from': st_address})
        frames = tx[0]
        if frames > 0 :
            self.contract.buyFramesEth({'from': st_address, 'value': st_eth})
            self.contributed_usd += frames * self.contract.frameUsdWithBonus(st_address, {'from': st_address})
        else: 
            with brownie.reverts():
                self.contract.buyFramesEth({'from': st_address, 'value': st_eth})

    def rule_buy_offchain(self, st_address, st_usd):
        # convert dollars into number of frames available to purchase
        tx = self.contract.calculateUsdFrames(st_usd, st_address, {'from': accounts[1]})
        frames = tx[0]
        usd_to_contribute = tx[1] 
        if frames > 0:
            self.contract.offlineFramesPurchase(st_address,frames, {'from': accounts[1]})
            self.contributed_usd += usd_to_contribute
        else:
            with brownie.reverts():
                self.contract.offlineFramesPurchase(st_address,frames, {'from': accounts[1]})         

    def rule_sleep(self, st_sleep):
        rpc.sleep(st_sleep)

    def rule_finalise(self):
        finalised = self.contract.finalised( {'from': accounts[1]})
        if (not finalised and self.contributed_usd + self.frame_usd > self.hardcap_usd):
            self.contract.finalise(accounts[9],{'from': accounts[1]})

    def invariant(self):
        # compare the contract deposit amounts with the local record
        assert (self.contract.contributedUsd() - self.contributed_usd) *2 < 1 * 10 ** 10  # err^2 < 10-8 dp
コード例 #5
0
ファイル: test_rule.py プロジェクト: samwerner/brownie-v2
    class StateMachine(SMTestBase):
        st_int = strategy("uint8")
        st_bool = strategy("bool")
        foobar = strategy("bytes4")

        def rule_one(self, st_int):
            assert type(st_int) is int
            assert 0 <= st_int <= 255

        def rule_two(self, st_bool, foobar):
            assert type(st_bool) is bool
            assert type(foobar) is bytes

        def rule_three(self, foo="st_bool"):
            assert type(foo) is bool
コード例 #6
0
class StateMachine:

    st_addr = strategy("address")
    st_random = strategy("uint256")

    def __init__(cls, accounts: Accounts, CallProxy: ContractContainer,
                 Xhibit: ContractContainer):
        cls.alice = accounts[0]
        call_proxy = cls.alice.deploy(CallProxy)

        cls.accounts = accounts
        cls.xhibit: Contract = cls.alice.deploy(Xhibit, call_proxy)

    def setup(self):
        self.total_supply = 0
        self.ownership = defaultdict(set)

    def rule_mint(self, st_addr):
        to = str(st_addr)
        self.xhibit.mint(to, {"from": self.alice})

        self.ownership[to].add(self.total_supply)
        self.total_supply += 1

    def rule_transfer(self, st_addr, st_random):
        if self.total_supply == 0:
            return
        to = str(st_addr)
        token_id = st_random % self.total_supply
        _from = str(self.xhibit.ownerOf(token_id))

        self.xhibit.transferFrom(_from, to, token_id, {"from": _from})

        self.ownership[_from].remove(token_id)
        self.ownership[to].add(token_id)

    def invariant_balanceOf(self):
        for acct in self.ownership.keys():
            assert self.xhibit.balanceOf(acct) == len(self.ownership[acct])

    def invariant_tokenOfOwnerByIndex(self):

        for acct in self.ownership.keys():
            tokens = {
                self.xhibit.tokenOfOwnerByIndex(acct, i)
                for i in range(len(self.ownership[acct]))
            }
            assert tokens == self.ownership[acct]
コード例 #7
0
ファイル: test_rule.py プロジェクト: samwerner/brownie-v2
    class StateMachine(SMTestBase):
        @sf.rule(st_int=strategy("uint8"))
        def rule_one(self, st_int):
            pass

        @sf.rule()
        def invariant_horrible_name_for_a_rule(self):
            pass
コード例 #8
0
ファイル: test_integers.py プロジェクト: jeffywu/brownie
def test_invalid_bits(type_str):
    with pytest.raises(ValueError):
        strategy(f"{type_str}1")
    with pytest.raises(ValueError):
        strategy(f"{type_str}264")
    with pytest.raises(ValueError):
        strategy(f"{type_str}69")
コード例 #9
0
class StateMachine:

    value = strategy('uint256', max_value="1 ether")
    address = strategy('address')

    def __init__(cls, accounts, contract):
        # deploy the contract at the start of the test
        cls.accounts = accounts
        cls.contract = contract

    def setup(self):
        # zero the deposit amounts at the start of each test run
        self.deposits = {i: 0 for i in self.accounts}
        self.total = 0

    def rule_deposit(self, address, value):
        # make a deposit and adjust the local record
        self.contract.depositDividends({'from': address, 'value': value})
        self.deposits[address] += value
        self.total += value

    def rule_withdraw(self, address, value):
        if self.deposits[address] >= value:
            # make a withdrawal and adjust the local record
            self.contract.withdrawDividends({'from': address})
            self.deposits[address] -= value
            self.total -= value

        else:
            # attempting to withdraw beyond your balance should revert
            with brownie.reverts():
                self.contract.withdrawDividends({'from': address})

    def invariant(self):
        # compare the contract deposit amounts with the local record
        for address, amount in self.deposits.items():
            assert self.contract.dividendsOwing(address) == amount
コード例 #10
0
class StateMachine:
    st_eth = strategy('uint256', min_value="1 ether", max_value="100 ether")
    st_owner = strategy('address')
    st_alice = strategy('address')
    st_bob = strategy('address')
    st_charlie = strategy('address')

    def __init__(cls, accounts, contract):
        # deploy the contract at the start of the test
        cls.accounts = accounts
        cls.contract = contract

    def setup(self):
        # zero the deposit amounts at the start of each test run
        self.total_supply = SUPPLY

    def rule_transfer(self, st_owner, st_alice, st_eth):
        balance = self.contract.balanceOf(st_owner, {'from': st_owner})
        if balance >= st_eth:
            self.contract.transfer(st_alice, st_eth, {'from': st_owner})

    def invariant(self):
        # compare the contract deposit amounts with the local record
        assert self.contract.totalSupply() == self.total_supply
コード例 #11
0
ファイル: test_decimal.py プロジェクト: jeffywu/brownie
def test_invalid_min_max():
    # min too low
    with pytest.raises(ValueError):
        strategy("decimal", min_value=-(2**128))
    # max too high
    with pytest.raises(ValueError):
        strategy("decimal", max_value=2**128)
    # min > max
    with pytest.raises(ValueError):
        strategy("decimal", min_value=42, max_value=12)
コード例 #12
0
class TokenSupply:
    st_minter = strategy("address")

    def __init__(self):
        pass

    def rule_mint(self, st_receiver, st_minter, st_amount):
        print(st_amount)
        if self.contract.owner() == st_minter:
            self.contract.mintToken(st_receiver, st_amount,
                                    {"from": st_minter})
            self.totalSupply += st_amount
            self.balances[st_receiver] += st_amount
        else:
            with brownie.reverts():
                self.contract.mintToken(st_receiver, st_amount,
                                        {"from": st_minter})

    """
コード例 #13
0
class Edgecases:
    st_minter = strategy("address")

    def __init__(self):
        pass

    def rule_totalSupply_overflows(self, st_minter, st_receiver):
        uint256max = 2**256 - 1
        if self.contract.owner == st_minter:
            tx = self.contract.mintToken(st_receiver, uint256max,
                                         {"from": st_minter})
            self.totalSupply += uint256max
            self.balances[st_receiver] += uint256max
        else:
            with brownie.reverts():
                self.contract.mintToken(st_receiver, uint256max,
                                        {"from": st_minter})

    """
コード例 #14
0
ファイル: test_integers.py プロジェクト: jeffywu/brownie
        strategy("int", min_value=-(2**255) - 1)

    # max too high
    with pytest.raises(ValueError):
        strategy("uint", max_value=2**256)

    # min > max
    with pytest.raises(ValueError):
        strategy("int", min_value=42, max_value=12)
    with pytest.raises(ValueError):
        strategy("uint8", min_value=1024)
    with pytest.raises(ValueError):
        strategy("int8", max_value=-129)


@given(value=strategy("uint"))
def test_uint_given(value):
    assert type(value) is int
    assert 0 <= value <= 2**256 - 1


@given(value=strategy("uint8"))
def test_uint8_given(value):
    assert type(value) is int
    assert 0 <= value <= 255


@given(value=strategy("int"))
def test_int_given(value):
    assert -(2**255) <= value <= 2**255 - 1
コード例 #15
0
ファイル: test_integers.py プロジェクト: jeffywu/brownie
def test_strategy(bits):
    type_str = f"uint{bits}"
    assert isinstance(strategy(type_str), SearchStrategy)

    type_str = f"int{bits}"
    assert isinstance(strategy(type_str), SearchStrategy)
コード例 #16
0
    #         "rtol": 1e-4,
    #     }
    # },
    {
        "entry": {
            "timestamp": 1633554032,
            "micro_price": 326752400804053,
            "macro_price": 326749496496389,
            "rtol": 1e-4,
        }
    },
]


@given(
    collateral=strategy('uint256', min_value=1e18, max_value=(OI_CAP-1e4)/100),
    leverage=strategy('uint8', min_value=1, max_value=100),
    is_long=strategy('bool'))
def test_build_success_zero_impact(ovl_collateral, token, mothership, market,
                                   bob, start_time, collateral, leverage,
                                   is_long):

    brownie.chain.mine(timestamp=start_time)

    oi = collateral * leverage

    trade_fee = oi * mothership.fee() / FEE_RESOLUTION

    # Get prior state of collateral manager
    fee_bucket = ovl_collateral.fees()
コード例 #17
0
class StateMachine:
    """
    Validate gauge weights and gauge weight sum.

    Strategies
    ----------
    st_type : Decimal
        Gauge type, multiplied by `len(self.gauges)` to choose a value
    st_gauge_weight : int
        Gauge weight
    st_type_wiehgt : int
        Type weight
    """

    st_type = strategy("decimal", min_value=0, max_value="0.99999999")
    st_gauge_weight = strategy("uint", min_value=10**17, max_value=10**19)
    st_type_weight = strategy("uint", min_value=10**17, max_value=10**19)

    def __init__(self, LiquidityGauge, accounts, gauge_controller,
                 mock_lp_token, minter):
        self.LiquidityGauge = LiquidityGauge
        self.accounts = accounts

        self.lp_token = mock_lp_token
        self.minter = minter
        self.controller = gauge_controller

    def setup(self):
        self.type_weights = []
        self.gauges = []

    def initialize_add_type(self, st_type_weight):
        """
        Add a new gauge type.

        This is also included as an intialize to increase the number of types early in the test.
        """
        self.rule_add_type(st_type_weight)

    def rule_add_type(self, st_type_weight):
        """
        Add a new gauge type.
        """
        self.controller.add_type(b"Type!", st_type_weight,
                                 {"from": self.accounts[0]})
        self.type_weights.append(st_type_weight)

    def rule_add_gauge(self, st_type, st_gauge_weight):
        """
        Add a new gauge.

        If no types have been added, this rule has not effect.
        """
        if not self.type_weights:
            return

        gauge_type = int(st_type * (len(self.type_weights)))
        gauge = self.LiquidityGauge.deploy(self.lp_token, self.minter,
                                           {"from": self.accounts[0]})

        self.controller.add_gauge(gauge, gauge_type, st_gauge_weight,
                                  {"from": self.accounts[0]})
        self.gauges.append({
            "contract": gauge,
            "type": gauge_type,
            "weight": st_gauge_weight
        })

    def _gauge_weight(self, idx):
        return sum(i["weight"] for i in self.gauges if i["type"] == idx)

    def invariant_gauge_weight_sums(self):
        """
        Validate the gauge weight sums per type.
        """
        for idx in range(len(self.type_weights)):
            gauge_weight_sum = self._gauge_weight(idx)

            assert self.controller.weight_sums_per_type(
                idx) == gauge_weight_sum

    def invariant_total_type_weight(self):
        """
        Validate the total weight.
        """
        total_weight = sum(
            self._gauge_weight(idx) * weight
            for idx, weight in enumerate(self.type_weights))

        assert self.controller.get_total_weight() == total_weight

    def invariant_relative_gauge_weight(self):
        """
        Validate the relative gauge weights.
        """
        total_weight = sum(
            self._gauge_weight(idx) * weight
            for idx, weight in enumerate(self.type_weights))

        for gauge, weight, idx in [(i["contract"], i["weight"], i["type"])
                                   for i in self.gauges]:
            expected = 10**18 * self.type_weights[idx] * weight // total_weight

            assert self.controller.gauge_relative_weight(gauge) == expected
コード例 #18
0

@pytest.fixture(scope="module")
def airdrop_tokens(ERC20_Revert, accounts, airdrop_token, escrow):
    token_list = [airdrop_token]
    for i in range(2):
        token = ERC20_Revert.deploy("Airdrop", "AD", 18, {'from': accounts[0]})
        token._mint_for_testing(10**24, {'from': accounts[3]})
        escrow.add_token(token, {'from': accounts[0]})
        token_list.append(token)

    yield token_list


@given(st_deposits=strategy("uint256[3]",
                            min_value=10**17,
                            max_value=10**21,
                            unique=True),
       st_airdrops=strategy("uint256[10]",
                            min_value=10**10,
                            max_value=10**18,
                            unique=True))
@settings(max_examples=10, phases=[Phase.generate, Phase.target])
def test_many_airdrops_single_claim(accounts, rpc, escrow, airdrop_token,
                                    st_deposits, st_airdrops):
    """
    Verify correct claim amount from a single claim of many airdrops.
    """

    # initial deposits of `lp_token`
    total_deposited = sum(st_deposits)
    for i in range(3):
コード例 #19
0
class StateMachine:

    # account to perform a deposit / withdrawal from
    st_account = strategy("address", length=10)

    # amount to deposit / withdraw
    st_value = strategy("uint64")

    # number of weeks to lock a deposit
    st_lock_duration = strategy("uint8")

    # number of weeks to advance the clock
    st_sleep_duration = strategy("uint", min_value=1, max_value=4)

    def __init__(self, accounts, token, voting_escrow):
        self.accounts = accounts
        self.token = token
        self.voting_escrow = voting_escrow

        for acct in accounts:
            token._mint_for_testing(acct, 10 ** 40)
            token.approve(voting_escrow, 2 ** 256 - 1, {"from": acct})

    def setup(self):
        self.token_balances = {i: 10 ** 40 for i in self.accounts}
        self.voting_balances = {i: {"value": 0, "unlock_time": 0} for i in self.accounts}

    def rule_create_lock(self, st_account, st_value, st_lock_duration):
        unlock_time = (chain.time() + st_lock_duration * WEEK) // WEEK * WEEK

        if st_value == 0:
            with brownie.reverts("dev: need non-zero value"):
                self.voting_escrow.create_lock(
                    st_value, unlock_time, {"from": st_account, "gas": GAS_LIMIT}
                )

        elif self.voting_balances[st_account]["value"] > 0:
            with brownie.reverts("Withdraw old tokens first"):
                self.voting_escrow.create_lock(
                    st_value, unlock_time, {"from": st_account, "gas": GAS_LIMIT}
                )

        elif unlock_time <= chain.time():
            with brownie.reverts("Can only lock until time in the future"):
                self.voting_escrow.create_lock(
                    st_value, unlock_time, {"from": st_account, "gas": GAS_LIMIT}
                )

        elif unlock_time > chain.time() + 86400 * 365 * 4:
            with brownie.reverts("Voting lock can be 4 years max"):
                self.voting_escrow.create_lock(
                    st_value, unlock_time, {"from": st_account, "gas": GAS_LIMIT}
                )

        else:
            tx = self.voting_escrow.create_lock(
                st_value, unlock_time, {"from": st_account, "gas": GAS_LIMIT}
            )
            self.voting_balances[st_account] = {
                "value": st_value,
                "unlock_time": tx.events["Deposit"]["locktime"],
            }

    def rule_increase_amount(self, st_account, st_value):
        if st_value == 0:
            with brownie.reverts("dev: need non-zero value"):
                self.voting_escrow.increase_amount(st_value, {"from": st_account, "gas": GAS_LIMIT})

        elif self.voting_balances[st_account]["value"] == 0:
            with brownie.reverts("No existing lock found"):
                self.voting_escrow.increase_amount(st_value, {"from": st_account, "gas": GAS_LIMIT})

        elif self.voting_balances[st_account]["unlock_time"] <= chain.time():
            with brownie.reverts("Cannot add to expired lock. Withdraw"):
                self.voting_escrow.increase_amount(st_value, {"from": st_account, "gas": GAS_LIMIT})

        else:
            self.voting_escrow.increase_amount(st_value, {"from": st_account, "gas": GAS_LIMIT})
            self.voting_balances[st_account]["value"] += st_value

    def rule_increase_unlock_time(self, st_account, st_lock_duration):
        unlock_time = (chain.time() + st_lock_duration * WEEK) // WEEK * WEEK

        if self.voting_balances[st_account]["unlock_time"] <= chain.time():
            with brownie.reverts("Lock expired"):
                self.voting_escrow.increase_unlock_time(
                    unlock_time, {"from": st_account, "gas": GAS_LIMIT}
                )

        elif self.voting_balances[st_account]["value"] == 0:
            with brownie.reverts("Nothing is locked"):
                self.voting_escrow.increase_unlock_time(
                    unlock_time, {"from": st_account, "gas": GAS_LIMIT}
                )

        elif unlock_time <= self.voting_balances[st_account]["unlock_time"]:
            with brownie.reverts("Can only increase lock duration"):
                self.voting_escrow.increase_unlock_time(
                    unlock_time, {"from": st_account, "gas": GAS_LIMIT}
                )

        elif unlock_time > chain.time() + 86400 * 365 * 4:
            with brownie.reverts("Voting lock can be 4 years max"):
                self.voting_escrow.increase_unlock_time(
                    unlock_time, {"from": st_account, "gas": GAS_LIMIT}
                )

        else:
            tx = self.voting_escrow.increase_unlock_time(
                unlock_time, {"from": st_account, "gas": GAS_LIMIT}
            )
            self.voting_balances[st_account]["unlock_time"] = tx.events["Deposit"]["locktime"]

    def rule_withdraw(self, st_account):
        """
        Withdraw tokens from the voting escrow.
        """
        if self.voting_balances[st_account]["unlock_time"] > chain.time():
            # fail path - before unlock time
            with brownie.reverts("The lock didn't expire"):
                self.voting_escrow.withdraw({"from": st_account, "gas": GAS_LIMIT})

        else:
            # success path - specific amount
            self.voting_escrow.withdraw({"from": st_account, "gas": GAS_LIMIT})
            self.voting_balances[st_account]["value"] = 0

    def rule_checkpoint(self, st_account):
        self.voting_escrow.checkpoint({"from": st_account, "gas": GAS_LIMIT})

    def rule_advance_time(self, st_sleep_duration):
        """
        Advance the clock.
        """
        chain.sleep(st_sleep_duration * WEEK)

        # check the balance as a transaction, to ensure a block is mined after time travel
        self.token.balanceOf.transact(self.accounts[0], {"from": self.accounts[0]})

    def invariant_token_balances(self):
        """
        Verify that token balances are correct.
        """
        for acct in self.accounts:
            assert self.token.balanceOf(acct) == 10 ** 40 - self.voting_balances[acct]["value"]

    def invariant_escrow_current_balances(self):
        """
        Verify the sum of all escrow balances is equal to the escrow totalSupply.
        """
        total_supply = 0
        timestamp = chain[-1].timestamp

        for acct in self.accounts:
            data = self.voting_balances[acct]

            balance = self.voting_escrow.balanceOf(acct)
            total_supply += balance

            if data["unlock_time"] > timestamp and data["value"] // MAX_TIME > 0:
                assert balance
            elif not data["value"] or data["unlock_time"] <= timestamp:
                assert not balance

        assert self.voting_escrow.totalSupply() == total_supply

    def invariant_historic_balances(self):
        """
        Verify the sum of historic escrow balances is equal to the historic totalSupply.
        """
        total_supply = 0
        block_number = history[-4].block_number

        for acct in self.accounts:
            total_supply += self.voting_escrow.balanceOfAt(acct, block_number)

        assert self.voting_escrow.totalSupplyAt(block_number) == total_supply
コード例 #20
0
ファイル: test_integers.py プロジェクト: jeffywu/brownie
def test_exclude_repr():
    st = strategy("uint8", exclude=42)
    assert repr(st) == "integers(min_value=0, max_value=255, exclude=(42,))"
コード例 #21
0
import pytest

from brownie.test import given, strategy
from collections import deque
from hypothesis import settings
from itertools import permutations
from simulation import Curve

pytestmark = pytest.mark.skip_meta


@given(st_pct=strategy('decimal[50]',
                       min_value="0.001",
                       max_value=1,
                       unique=True,
                       places=3),
       st_seed_amount=strategy("decimal", min_value=5, max_value=12, places=1))
@settings(max_examples=5)
def test_curve_in_contract(
    alice,
    swap,
    wrapped_coins,
    wrapped_decimals,
    underlying_decimals,
    n_coins,
    approx,
    st_seed_amount,
    st_pct,
):
    st_seed_amount = int(10**st_seed_amount)
コード例 #22
0
class ReleaseTest:

    st_bool = strategy("bool")

    def __init__(self, gov, registry, create_token, create_vault):
        self.gov = gov
        self.registry = registry
        self.create_token = lambda s: create_token()

        def create_vault_adaptor(self, *args, **kwargs):
            return create_vault(*args, **kwargs)

        self.create_vault = create_vault_adaptor

    def setup(self):
        self.latest_version = Version("1.0.0")
        token = self.create_token()
        vault = self.create_vault(token, version=str(self.latest_version))
        self.vaults = {token: [vault]}
        self.registry.newRelease(vault, {"from": self.gov})
        self.experiments = {}

    def rule_new_release(self, new_token="st_bool"):
        if new_token or len(self.vaults.keys()) == 0:
            token = self.create_token()
        else:
            token = list(self.vaults.keys())[-1]

        self.latest_version = self.latest_version.next_patch()

        vault = self.create_vault(token, version=str(self.latest_version))
        print(f"Registry.newRelease({token}, {self.latest_version})")
        self.registry.newRelease(vault, {"from": self.gov})

        if token in self.vaults:
            self.vaults[token].append(vault)
        else:
            self.vaults[token] = [vault]

    def rule_new_deployment(self, new_token="st_bool"):
        tokens_with_stale_deployments = [
            token for token, deployments in self.vaults.items()
            if Version(deployments[-1].apiVersion()) < self.latest_version
        ]
        if new_token or len(tokens_with_stale_deployments) == 0:
            token = self.create_token()
        else:
            token = tokens_with_stale_deployments[-1]

        print(f"Registry.newVault({token}, {self.latest_version})")
        vault = Vault.at(
            self.registry.newVault(token, self.gov, self.gov, "",
                                   "").return_value)

        if token in self.vaults:
            self.vaults[token].append(vault)
        else:
            self.vaults[token] = [vault]

    def rule_new_experiment(self):
        token = self.create_token()
        print(f"Registry.newExperimentalVault({token}, {self.latest_version})")

        vault = Vault.at(
            self.registry.newExperimentalVault(token, self.gov, self.gov,
                                               self.gov, "", "").return_value)

        self.experiments[token] = [vault]

    def rule_endorse_experiment(self):
        experiments_with_latest_api = [
            (token, deployments[-1])
            for token, deployments in self.experiments.items()
            if (Version(deployments[-1].apiVersion()) == self.latest_version
                and (token not in self.vaults
                     or Version(self.vaults[token][-1].apiVersion()) < Version(
                         deployments[-1].apiVersion())))
        ]
        if len(experiments_with_latest_api) > 0:
            token, vault = experiments_with_latest_api[-1]
            print(f"Registry.endorseVault({token}, {self.latest_version})")
            self.registry.endorseVault(vault, {"from": self.gov})

            if token in self.vaults:
                self.vaults[token].append(vault)
            else:
                self.vaults[token] = [vault]

    def invariant(self):
        for token, deployments in self.vaults.items():
            # Check that token matches up
            assert deployments[0].token() == token
            # Strictly linearly increasing versions
            last_version = Version(deployments[0].apiVersion())
            assert last_version <= self.latest_version

            for vault in deployments[1:]:
                # Check that token matches up
                assert vault.token() == token
                # Strictly linearly increasing versions
                assert last_version < Version(
                    vault.apiVersion()) <= self.latest_version
コード例 #23
0
ファイル: test_integers.py プロジェクト: jeffywu/brownie
def test_invalid_min_max():
    # min too low
    with pytest.raises(ValueError):
        strategy("uint", min_value=-1)
    with pytest.raises(ValueError):
        strategy("int", min_value=-(2**255) - 1)

    # max too high
    with pytest.raises(ValueError):
        strategy("uint", max_value=2**256)

    # min > max
    with pytest.raises(ValueError):
        strategy("int", min_value=42, max_value=12)
    with pytest.raises(ValueError):
        strategy("uint8", min_value=1024)
    with pytest.raises(ValueError):
        strategy("int8", max_value=-129)
コード例 #24
0
class StateMachine:
    """
    Stateful test that performs a series of deposits, swaps and withdrawals
    and confirms that the virtual price only goes up.
    """

    st_pct = strategy("decimal", min_value="0.5", max_value="1", places=2)
    st_rates = strategy("decimal[8]",
                        min_value="1.001",
                        max_value="1.004",
                        places=4,
                        unique=True)

    def __init__(cls, alice, swap, wrapped_coins, wrapped_decimals):
        cls.alice = alice
        cls.swap = swap
        cls.coins = wrapped_coins
        cls.decimals = wrapped_decimals
        cls.n_coins = len(wrapped_coins)

    def setup(self):
        # reset the virtual price between each test run
        self.virtual_price = self.swap.get_virtual_price()

    def _min_max(self):
        # get index values for the coins with the smallest and largest balances in the pool
        balances = [
            self.swap.balances(i) / (10**self.decimals[i])
            for i in range(self.n_coins)
        ]
        min_idx = balances.index(min(balances))
        max_idx = balances.index(max(balances))
        if min_idx == max_idx:
            min_idx = abs(min_idx - 1)

        return min_idx, max_idx

    def rule_ramp_A(self, st_pct):
        """
        Increase the amplification coefficient.

        This action happens at most once per test. If A has already
        been ramped, a swap is performed instead.
        """
        if not hasattr(self.swap, "ramp_A") or self.swap.future_A_time():
            return self.rule_exchange_underlying(st_pct)

        new_A = int(self.swap.A() * (1 + st_pct))
        self.swap.ramp_A(new_A, chain.time() + 86410, {'from': self.alice})

    def rule_increase_rates(self, st_rates):
        """
        Increase the stored rate for each wrapped coin.
        """
        for rate, coin in zip(self.coins, st_rates):
            if hasattr(coin, "set_exchange_rate"):
                coin.set_exchange_rate(int(coin.get_rate() * rate),
                                       {'from': self.alice})

    def rule_exchange(self, st_pct):
        """
        Perform a swap using wrapped coins.
        """
        send, recv = self._min_max()
        amount = int(10**self.decimals[send] * st_pct)
        value = amount if self.coins[send] == ETH_ADDRESS else 0
        self.swap.exchange(send, recv, amount, 0, {
            'from': self.alice,
            'value': value
        })

    def rule_exchange_underlying(self, st_pct):
        """
        Perform a swap using underlying coins.
        """
        if not hasattr(self.swap, "exchange_underlying"):
            # if underlying coins aren't available, use wrapped instead
            return self.rule_exchange(st_pct)

        send, recv = self._min_max()
        amount = int(10**self.decimals[send] * st_pct)
        value = amount if self.coins[send] == ETH_ADDRESS else 0
        self.swap.exchange_underlying(send, recv, amount, 0, {
            'from': self.alice,
            'value': value
        })

    def rule_remove_one_coin(self, st_pct):
        """
        Remove liquidity from the pool in only one coin.
        """
        if not hasattr(self.swap, "remove_liquidity_one_coin"):
            # not all pools include `remove_liquidity_one_coin`
            return self.rule_remove_imbalance(st_pct)

        idx = self._min_max()[1]
        amount = int(10**self.decimals[idx] * st_pct)
        self.swap.remove_liquidity_one_coin(amount, idx, 0,
                                            {'from': self.alice})

    def rule_remove_imbalance(self, st_pct):
        """
        Remove liquidity from the pool in an imbalanced manner.
        """
        idx = self._min_max()[1]
        amounts = [0] * self.n_coins
        amounts[idx] = 10**self.decimals[idx] * st_pct
        self.swap.remove_liquidity_imbalance(amounts, 2**256 - 1,
                                             {'from': self.alice})

    def rule_remove(self, st_pct):
        """
        Remove liquidity from the pool.
        """
        amount = int(10**18 * st_pct)
        self.swap.remove_liquidity(amount, [0] * self.n_coins,
                                   {'from': self.alice})

    def invariant_check_virtual_price(self):
        """
        Verify that the pool's virtual price has either increased or stayed the same.
        """
        virtual_price = self.swap.get_virtual_price()
        assert virtual_price >= self.virtual_price
        self.virtual_price = virtual_price

    def invariant_advance_time(self):
        """
        Advance the clock by 1 hour between each action.
        """
        chain.sleep(3600)
コード例 #25
0
class StateMachine:

    st_acct = strategy("address", length=5)
    st_acct2 = strategy("address", length=5)
    st_token = strategy("uint", max_value=2)
    st_synth = strategy("uint", max_value=2)
    st_idx = strategy("decimal", min_value=0, max_value="0.99", places=2)
    st_amount = strategy("decimal", min_value=1, max_value=10, places=3)

    def __init__(cls, swap):
        cls.swap = swap

    def setup(self):
        self.settlers = [i["addr"] for i in self.swap.tx.events["NewSettler"]]
        self.used_token_ids = []
        self.active_token_ids = {}
        # "Marty - you gotta come back with me!"
        # we're doing this because SNX oracle rates expire in 25 hours
        # it's weird and hacky but it works ¯\_(ツ)_/¯
        chain.mine(timestamp=1600000000)

    def _mint(self, acct, token, amount):
        token = MintableForkToken(token)
        amount = int(amount * 10**token.decimals())
        if not token.allowance(acct, self.swap):
            token.approve(self.swap, 2**256 - 1, {"from": acct})
        balance = token.balanceOf(acct)
        if balance < amount:
            token._mint_for_testing(acct, amount - balance)

        return amount

    def _all_token_ids(self):
        return ([x for v in self.active_token_ids.values() for x in v] +
                self.used_token_ids + [int(i, 16) for i in self.settlers])

    def rule_swap_into(self, st_acct, st_token, st_synth, st_idx, st_amount):
        """
        Generate a new NFT via a cross-asset swap.
        """
        idx = int(st_idx * len(TOKENS[st_token]))

        initial = TOKENS[st_token][idx]
        synth = TOKENS[st_synth][0]
        amount = self._mint(st_acct, initial, st_amount)
        if st_token == st_synth:
            # initial token and target synth come from the same asset class
            # no cross-asset swap is possible
            with brownie.reverts():
                self.swap.swap_into_synth(initial, synth, amount, 0,
                                          {"from": st_acct})
        else:
            tx = self.swap.swap_into_synth(initial, synth, amount, 0,
                                           {"from": st_acct})
            token_id = tx.events["Transfer"][-1]["token_id"]
            assert token_id != 0

            if "NewSettler" in tx.events:
                settler = tx.events["NewSettler"]["addr"]
                assert settler not in self.settlers
                self.settlers.append(settler)

            # make sure `token_id` isn't previously assigned
            assert (token_id not in list(self.active_token_ids.values()) +
                    self.used_token_ids)

            self.active_token_ids.setdefault(st_acct, []).append(token_id)
            chain.mine(timedelta=600)

    def rule_swap_into_existing(self, st_acct, st_token, st_amount, st_idx):
        """
        Increase the underyling balance of an existing NFT via a cross-asset swap.
        """
        if self.active_token_ids.get(st_acct):
            idx = int(st_idx * len(self.active_token_ids[st_acct]))
            token_id = self.active_token_ids[st_acct][idx]
        else:
            token_ids = self._all_token_ids()
            idx = int(st_idx * len(token_ids))
            token_id = token_ids[idx]

        synth = Settler.at(hex(token_id % 2**160)).synth()
        idx = int(st_idx * len(TOKENS[st_token]))
        initial = TOKENS[st_token][idx]
        amount = self._mint(st_acct, initial, st_amount)

        if self.active_token_ids.get(st_acct) and TOKENS[st_token][0] != synth:
            self.swap.swap_into_synth(initial, synth, amount, 0, st_acct,
                                      token_id, {"from": st_acct})
            chain.mine(timedelta=600)
        else:
            with brownie.reverts():
                self.swap.swap_into_synth(initial, synth, amount, 0, st_acct,
                                          token_id, {"from": st_acct})

    def rule_transfer(self, st_acct, st_acct2, st_idx):
        """
        Transfer ownership of an NFT.
        """
        if self.active_token_ids.get(st_acct):
            # choose from the caller's valid NFT token IDs, if there are any
            idx = int(st_idx * len(self.active_token_ids[st_acct]))
            token_id = self.active_token_ids[st_acct][idx]
            self.swap.transferFrom(st_acct, st_acct2, token_id,
                                   {"from": st_acct})
            self.active_token_ids[st_acct].remove(token_id)
            self.active_token_ids.setdefault(st_acct2, []).append(token_id)
        else:
            # if the caller does not own any NFTs, choose from any token ID
            token_ids = self._all_token_ids()
            idx = int(st_idx * len(token_ids))
            token_id = token_ids[idx]
            with brownie.reverts():
                self.swap.transferFrom(st_acct, st_acct2, token_id,
                                       {"from": st_acct})

    def rule_withdraw(self, st_acct, st_amount, st_idx):
        """
        Withdraw a synth from an NFT.
        """
        if self.active_token_ids.get(st_acct):
            # choose from the caller's valid NFT token IDs, if there are any
            idx = int(st_idx * len(self.active_token_ids[st_acct]))
            token_id = self.active_token_ids[st_acct][idx]
        else:
            # if the caller does not own any NFTs, choose from any token ID
            token_ids = self._all_token_ids()
            idx = int(st_idx * len(token_ids))
            token_id = token_ids[idx]

        amount = int(st_amount * 10**18)
        if self.active_token_ids.get(st_acct):
            # when the action is possible, don't exceed the max underlying balance
            balance = self.swap.token_info(token_id)["underlying_balance"]
            amount = min(amount, balance)

        if self.active_token_ids.get(st_acct):
            self.swap.withdraw(token_id, amount, {"from": st_acct})
            if balance == amount:
                self.active_token_ids[st_acct].remove(token_id)
                self.used_token_ids.append(token_id)
        else:
            with brownie.reverts():
                self.swap.withdraw(token_id, amount, {"from": st_acct})

    def rule_swap_from(self, st_acct, st_token, st_amount, st_idx):
        """
        Swap a synth out of an NFT.
        """
        if self.active_token_ids.get(st_acct):
            # choose from the caller's valid NFT token IDs, if there are any
            idx = int(st_idx * len(self.active_token_ids[st_acct]))
            token_id = self.active_token_ids[st_acct][idx]
        else:
            # if the caller does not own any NFTs, choose from any token ID
            token_ids = self._all_token_ids()
            idx = int(st_idx * len(token_ids))
            token_id = token_ids[idx]

        # choose a target coin for the swap
        synth = Settler.at(hex(token_id % 2**160)).synth()
        if synth == ZERO_ADDRESS:
            # if the token ID is not active, choose from any possible token - all should fail
            token_list = [x for v in TOKENS for x in v]
        else:
            # if the token ID is active, choose from the list of possible targets
            token_list = next(i for i in TOKENS if i[0] == synth)
        idx = int(st_idx * len(token_list))
        target = token_list[idx]

        amount = int(st_amount * 10**18)
        if self.active_token_ids.get(st_acct):
            # when the action is possible, don't exceed the max underlying balance
            balance = self.swap.token_info(token_id)["underlying_balance"]
            amount = min(amount, balance)

        if self.active_token_ids.get(st_acct) and synth != target:
            # sender own the NFT, target is not the same as the underlying synth
            self.swap.swap_from_synth(token_id, target, amount, 0,
                                      {"from": st_acct})
            if balance == amount:
                self.active_token_ids[st_acct].remove(token_id)
                self.used_token_ids.append(token_id)
        else:
            with brownie.reverts():
                self.swap.swap_from_synth(token_id, target, amount, 0,
                                          {"from": st_acct})

    def teardown(self):
        """
        Verify balances and ownership of active and burned NFTs.
        """
        for acct, token_id in [(k, x)
                               for k, v in self.active_token_ids.items()
                               for x in v]:
            token_info = self.swap.token_info(token_id)
            synth = Contract(token_info["synth"])
            settler = hex(token_id % 2**160)

            assert self.swap.ownerOf(token_id) == acct == token_info["owner"]
            assert synth.balanceOf(settler) == token_info["underlying_balance"]

        assert len(self.used_token_ids) == len(set(self.used_token_ids))

        for token_id in self.used_token_ids:
            with brownie.reverts():
                self.swap.ownerOf(token_id)

        for acct in accounts[:5]:
            assert self.swap.balanceOf(acct) == len(
                self.active_token_ids.get(acct, []))
コード例 #26
0
ファイル: test_balanceOf.py プロジェクト: skellet0r/NFTXhibit
from brownie.test import given, strategy


@given(account=strategy("address"))
def test_balanceOf_queries_account_balances(account, xhibit):
    assert xhibit.balanceOf(account) == 0
コード例 #27
0
import pytest
from brownie.test import strategy, given

from tests.conftest import YEAR


@pytest.fixture(scope="module", autouse=True)
def initial_setup(chain, token):
    chain.sleep(86401)
    token.update_boost_mining_parameters({'from': accounts[0]})
    chain.mine()
    chain.sleep(86401 * 7)
    token.update_mining_parameters({'from': accounts[0]})


@given(duration=strategy('uint', min_value=86500, max_value=YEAR))
def test_mint(accounts, chain, token, duration):
    token.set_minter(accounts[0], {'from': accounts[0]})
    creation_time = token.start_epoch_time()
    initial_supply = token.totalSupply()
    rate = token.rate()
    chain.sleep(duration)

    amount = (chain.time()-creation_time) * rate
    token.mint(accounts[1], amount, {'from': accounts[0]})

    assert token.balanceOf(accounts[1]) == amount
    assert token.totalSupply() == initial_supply + amount


@given(duration=strategy('uint', min_value=86500, max_value=YEAR))
コード例 #28
0
import pytest
from brownie.test import given, strategy

ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"


@pytest.fixture(scope="module", autouse=True)
def initial_funding(vesting, accounts):
    vesting.add_tokens(10**21, {"from": accounts[0]})
    recipients = [accounts[1]] + [ZERO_ADDRESS] * 99
    vesting.fund(recipients, [10**20] + [0] * 99, {"from": accounts[0]})


@given(sleep_time=strategy("uint", max_value=100000))
def test_claim_partial(vesting, coin_a, accounts, chain, start_time,
                       sleep_time, end_time):
    chain.sleep(start_time - chain.time() + sleep_time)
    tx = vesting.claim({"from": accounts[1]})
    expected_amount = 10**20 * (tx.timestamp - start_time) // (end_time -
                                                               start_time)

    assert coin_a.balanceOf(accounts[1]) == expected_amount
コード例 #29
0
from brownie.test import strategy, given

from tests.conftest import approx
from tests.conftest import YEAR, YEAR_1_SUPPLY, INITIAL_SUPPLY


@given(time=strategy("decimal", min_value=1, max_value=7))
def test_mintable_in_timeframe(accounts, token, block_timestamp,
                               theoretical_supply, time, rpc):
    t0 = token.start_epoch_time()
    rpc.sleep(int(10**time))
    rpc.mine()
    t1 = block_timestamp()
    if t1 - t0 >= YEAR:
        token.update_mining_parameters({'from': accounts[0]})

    t1 = block_timestamp()
    available_supply = token.available_supply()
    mintable = token.mintable_in_timeframe(t0, t1)
    assert (available_supply - (INITIAL_SUPPLY * 10**18)
            ) >= mintable  # Should only round down, not up
    if t1 == t0:
        assert mintable == 0
    else:
        assert (available_supply -
                (INITIAL_SUPPLY * 10**18)) / mintable - 1 < 1e-7

    assert approx(theoretical_supply(), available_supply, 1e-16)


@given(time1=strategy('uint', max_value=YEAR),
コード例 #30
0
@pytest.fixture(scope="module", autouse=True)
def initial_setup(accounts, reward_contract, mock_lp_token,
                  liquidity_gauge_reward):
    mock_lp_token.approve(liquidity_gauge_reward, 2**256 - 1,
                          {'from': accounts[0]})
    liquidity_gauge_reward.deposit(100000, {'from': accounts[0]})

    for i in range(1, 11):
        mock_lp_token.transfer(accounts[i], 10**18, {'from': accounts[0]})
        mock_lp_token.approve(liquidity_gauge_reward, 10**18,
                              {'from': accounts[i]})


@given(
    amounts=strategy("uint256[10]",
                     min_value=10**17,
                     max_value=10**18,
                     unique=True),
    durations=strategy("uint256[10]", max_value=86400 * 30, unique=True),
)
@settings(max_examples=10)
def test_withdraw_borked_rewards(accounts, chain, reward_contract,
                                 mock_lp_token, liquidity_gauge_reward,
                                 amounts, durations):
    for i, (amount, duration) in enumerate(zip(amounts, durations), start=1):
        liquidity_gauge_reward.deposit(amount, {'from': accounts[i]})
        chain.sleep(duration)

    # Calling this method without transfering tokens breaks `CurveRewards.getReward`
    # however, it should still be possible to withdraw if `claim_rewards = False`
    reward_contract.notifyRewardAmount(10**20, {'from': accounts[0]})