示例#1
0
class ProxyRegistry(Contract):
    """A client for the `ProxyRegistry` contract.

    Ref. <https://github.com/reflexer-labs/geb-proxy-actions/blob/master/src/GebProxyRegistry.sol>
    """

    abi = Contract._load_abi(__name__, 'abi/ProxyRegistry.abi')
    bin = Contract._load_bin(__name__, 'abi/ProxyRegistry.bin')

    def __init__(self, web3: Web3, address: Address):
        assert isinstance(web3, Web3)
        assert isinstance(address, Address)

        self.web3 = web3
        self.address = address
        self._contract = self._get_contract(web3, self.abi, address)

    def build(self, owner: Address) -> Transact:
        assert isinstance(owner, Address)
        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'build(address)', [owner.address])

    def proxies(self, owner: Address) -> Address:
        assert isinstance(owner, Address)
        return Address(self._contract.functions.proxies(owner.address).call())

    def __repr__(self):
        return f"ProxyRegistry('{self.address}')"
示例#2
0
class DSAuth(Contract):

    abi = Contract._load_abi(__name__, 'abi/DSAuth.abi')
    bin = Contract._load_bin(__name__, 'abi/DSAuth.bin')

    def __init__(self, web3: Web3, address: Address):
        assert (isinstance(web3, Web3))
        assert (isinstance(address, Address))

        self.web3 = web3
        self.address = address
        self._contract = self._get_contract(web3, self.abi, address)

    @staticmethod
    def deploy(web3: Web3):
        return DSAuth(web3=web3,
                      address=Contract._deploy(web3, DSAuth.abi, DSAuth.bin,
                                               []))

    def get_owner(self) -> Address:
        return Address(self._contract.functions.owner().call())

    def set_owner(self, owner: Address) -> Transact:
        assert isinstance(owner, Address)

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, "setOwner", [owner.address])

    def set_authority(self, ds_authority: Address):
        assert isinstance(ds_authority, Address)

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, "setAuthority", [ds_authority.address])
示例#3
0
class DSPause(Contract):
    """A client for the `DSPause` contract, which schedules function calls after a predefined delay.

    You can find the source code of the `DSPause` contract here:
    <https://github.com/dapphub/ds-pause>.

    Attributes:
        web3: An instance of `Web` from `web3.py`.
        address: Ethereum address of the `DSPause` contract.
    """

    class Plan:
        def __init__(self, usr: Address, fax: bytes, eta: datetime):
            """Creates a plan to be executed later.

            Args:
            usr: Address of the caller
            fax: Identifies the calldata
            eta: Identifies the earliest time of execution
            """
            assert isinstance(usr, Address)
            assert isinstance(fax, bytes)
            assert isinstance(eta, datetime.datetime)

            self.usr = usr
            self.fax = fax
            self.eta = eta.timestamp()

    abi = Contract._load_abi(__name__, 'abi/DSPause.abi')
    bin = Contract._load_bin(__name__, 'abi/DSPause.bin')

    def __init__(self, web3: Web3, address: Address):
        assert (isinstance(web3, Web3))
        assert (isinstance(address, Address))

        self.web3 = web3
        self.address = address
        self._contract = self._get_contract(web3, self.abi, address)

    @staticmethod
    def deploy(web3: Web3, delay: int, owner: Address, ds_auth: DSAuth):
        return DSPause(web3=web3, address=Contract._deploy(web3, DSPause.abi, DSPause.bin,
                                                           [delay, owner.address, ds_auth.address.address]))

    # TODO: Awaiting updated ABI/BIN from geb-deploy
    # def plot(self, plan: Plan):
    #     return self._transact(plan, "plot")

    def drop(self, plan: Plan):
        return self._transact(plan, "drop")

    def exec(self, plan: Plan) -> Transact:
        return self._transact(plan, "exec")

    def _transact(self, plan: Plan, function_name: str) -> Transact:
        assert isinstance(plan, DSPause.Plan)
        assert isinstance(function_name, str)

        return Transact(self, self.web3, self.abi, self.address, self._contract, function_name,
                        [plan.usr.address, plan.fax, int(plan.eta)])
示例#4
0
class DSVault(Contract):
    """A client for the `DSVault` contract.

    You can find the source code of the `DSVault` contract here:
    <https://github.com/dapphub/ds-vault>.

    Attributes:
        web3: An instance of `Web` from `web3.py`.
        address: Ethereum address of the `DSVault` contract.
    """

    abi = Contract._load_abi(__name__, 'abi/DSVault.abi')
    bin = Contract._load_bin(__name__, 'abi/DSVault.bin')

    def __init__(self, web3: Web3, address: Address):
        assert (isinstance(web3, Web3))
        assert (isinstance(address, Address))

        self.web3 = web3
        self.address = address
        self._contract = self._get_contract(web3, self.abi, address)

    @staticmethod
    def deploy(web3: Web3):
        """Deploy a new instance of the `DSVault` contract.

        Args:
            web3: An instance of `Web` from `web3.py`.

        Returns:
            A `DSVault` class instance.
        """
        return DSVault(web3=web3,
                       address=Contract._deploy(web3, DSVault.abi, DSVault.bin,
                                                []))

    def authority(self) -> Address:
        """Return the current `authority` of a `DSAuth`-ed contract.

        Returns:
            The address of the current `authority`.
        """
        return Address(self._contract.functions.authority().call())

    def set_authority(self, address: Address) -> Transact:
        """Set the `authority` of a `DSAuth`-ed contract.

        Args:
            address: The address of the new `authority`.

        Returns:
            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(address, Address))
        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'setAuthority', [address.address])

    def __repr__(self):
        return f"DSVault('{self.address}')"
示例#5
0
class DSGuard(Contract):
    """A client for the `DSGuard` contract.

    You can find the source code of the `DSGuard` contract here:
    <https://github.com/dapphub/ds-guard>.

    Attributes:
        web3: An instance of `Web` from `web3.py`.
        address: Ethereum address of the `DSGuard` contract.
    """

    abi = Contract._load_abi(__name__, 'abi/DSGuard.abi')
    bin = Contract._load_bin(__name__, 'abi/DSGuard.bin')

    ANY = int_to_bytes32(2**256 - 1)

    def __init__(self, web3: Web3, address: Address):
        assert (isinstance(web3, Web3))
        assert (isinstance(address, Address))

        self.web3 = web3
        self.address = address
        self._contract = self._get_contract(web3, self.abi, address)

    @staticmethod
    def deploy(web3: Web3):
        return DSGuard(web3=web3,
                       address=Contract._deploy(web3, DSGuard.abi, DSGuard.bin,
                                                []))

    def permit(self, src, dst, sig: bytes) -> Transact:
        """Grant access to a function call.

        Args:
            src: Address of the caller, or `ANY`.
            dst: Address of the called contract, or `ANY`.
            sig: Signature of the called function, or `ANY`.

        Returns:
            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(src, Address) or isinstance(src, bytes))
        assert (isinstance(dst, Address) or isinstance(dst, bytes))
        assert (isinstance(sig, bytes) and len(sig) in (4, 32))

        if isinstance(src, Address) and isinstance(dst, Address):
            method = 'permit(address,address,bytes32)'
            src = src.address
            dst = dst.address

        else:
            method = 'permit(bytes32,bytes32,bytes32)'

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, method, [src, dst, sig])

    def __repr__(self):
        return f"DSGuard('{self.address}')"
示例#6
0
class DSProxyCache(Contract):
    """A client for the `DSProxyCache` contract.

    Ref. <https://github.com/dapphub/ds-proxy/blob/master/src/proxy.sol#L120>
    """

    abi = Contract._load_abi(__name__, 'abi/DSProxyCache.abi')
    bin = Contract._load_bin(__name__, 'abi/DSProxyCache.bin')

    def __init__(self, web3: Web3, address: Address):
        assert (isinstance(web3, Web3))
        assert (isinstance(address, Address))

        self.web3 = web3
        self.address = address
        self._contract = self._get_contract(web3, self.abi, address)

    @classmethod
    def deploy(cls, web3: Web3):
        return cls(web3=web3,
                   address=Contract._deploy(web3, cls.abi, cls.bin, []))

    def read(self, code: str) -> Optional[Address]:
        assert (isinstance(code, str))

        if code.startswith('0x'):
            b32_code = hexstring_to_bytes(code)
        else:
            b32_code = hexstring_to_bytes('0x' + code)
        address = Address(self._contract.functions.read(b32_code).call())

        if address == Address('0x0000000000000000000000000000000000000000'):
            return None
        else:
            return address

    def write(self, code: str):
        assert (isinstance(code, str))

        if code.startswith('0x'):
            b32_code = hexstring_to_bytes(code)
        else:
            b32_code = hexstring_to_bytes('0x' + code)

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'write', [b32_code])

    def __repr__(self):
        return f"DSProxyCache('{self.address}')"
示例#7
0
class GebProxyActions(Contract):
    """A client for the `GebProxyActionsDsr` contract.

    Ref. <https://github.com/reflexer-labs/geb-proxy-actions/blob/master/src/GebProxyActions.sol>
    """

    abi = Contract._load_abi(__name__, 'abi/GebProxyActions.abi')
    bin = Contract._load_bin(__name__, 'abi/GebProxyActions.bin')

    def __init__(self, web3: Web3, address: Address):
        assert isinstance(web3, Web3)
        assert isinstance(address, Address)

        self.web3 = web3
        self.address = address
        self._contract = self._get_contract(web3, self.abi, address)
示例#8
0
class DSRoles(Contract):
    """A client for the `DSRoles` contract, which manages lists of user roles and capabilities.

    You can find the source code of the `DSRoles` contract here:
    <https://github.com/dapphub/ds-roles>.

    Attributes:
        web3: An instance of `Web` from `web3.py`.
        address: Ethereum address of the `DSRoles` contract.
    """

    abi = Contract._load_abi(__name__, 'abi/DSRoles.abi')
    bin = Contract._load_bin(__name__, 'abi/DSRoles.bin')

    def __init__(self, web3: Web3, address: Address):
        assert (isinstance(web3, Web3))
        assert (isinstance(address, Address))

        self.web3 = web3
        self.address = address
        self._contract = self._get_contract(web3, self.abi, address)

    def is_root_user(self, who: Address) -> bool:
        assert isinstance(who, Address)

        return bool(self._contract.functions.isUserRoot(who.address).call())

    def set_root_user(self, who: Address, enabled=True) -> Transact:
        assert isinstance(who, Address)

        return Transact(self, self.web3, self.abi, self.address, self._contract,
                        "setRootUser", [who.address, enabled])

    def has_user_role(self, who: Address, role: int) -> bool:
        assert isinstance(who, Address)
        assert isinstance(role, int)
        assert 0 <= role <= int('0xFFFFFFFF')

        return bool(self._contract.functions.hasUserRole(who.address, role).call())

    def set_user_role(self, who: Address, role: int, enabled=True) -> Transact:
        assert isinstance(who, Address)
        assert isinstance(role, int)
        assert 0 <= role <= int('0xFFFFFFFF')

        return Transact(self, self.web3, self.abi, self.address, self._contract,
                        "setUserRole", [who.address, role, enabled])
示例#9
0
class ESM(Contract):
    """A client for the `ESM` contract, which allows users to call `global_settlement.shutdown_system()` and thereby trigger a shutdown.

    Ref. <https://github.com/reflexer-labs/esm/blob/master/src/ESM.sol>

    Attributes:
      web3: An instance of `Web` from `web3.py`.
      address: Ethereum address of the `ESM` contract."""

    abi = Contract._load_abi(__name__, 'abi/ESM.abi')
    bin = Contract._load_bin(__name__, 'abi/ESM.bin')

    def __init__(self, web3: Web3, address: Address):
        assert isinstance(web3, Web3)
        assert isinstance(address, Address)

        self.web3 = web3
        self.address = address
        self._contract = self._get_contract(web3, self.abi, address)

    def authorized_accounts(self, address: Address) -> bool:
        """True if address is authorized"""

        return bool(
            self._contract.functions.authorizedAccounts(
                address.address).call())

    def token_burner(self) -> Address:
        """ Return tokenBurner """

        return Address(self._contract.functions.tokenBurner().call())

    def trigger_threshold(self) -> Wad:
        """Minimum amount of Gov required to call `shutdown`"""
        return Wad(self._contract.functions.triggerThreshold().call())

    def settled(self) -> bool:
        """True if `settle` has been called"""
        return bool(self._contract.functions.settled().call())

    def shutdown(self):
        """Calls `shutdownSystem` on the `GlobalSettlement` contract, initiating a shutdown."""
        logger.info("Calling shutdown to shutdown the global settlement")

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'shutdown', [])
示例#10
0
class UniswapV2(Contract):
    """
    UniswapV2 Python Client

    Each UniswapV2 instance is intended to be used with a single pool at a time.

    Documentation is available here: https://uniswap.org/docs/v2/
    """

    pair_abi = Contract._load_abi(__name__, 'abi/IUniswapV2Pair.abi')
    Irouter_abi = Contract._load_abi(__name__,
                                     'abi/IUniswapV2Router02.abi')['abi']
    router_abi = Contract._load_abi(__name__, 'abi/UniswapV2Router02.abi')
    router_bin = Contract._load_bin(__name__, 'abi/UniswapV2Router02.bin')
    Ifactory_abi = Contract._load_abi(__name__,
                                      'abi/IUniswapV2Factory.abi')['abi']
    factory_abi = Contract._load_abi(__name__, 'abi/UniswapV2Factory.abi')
    factory_bin = Contract._load_bin(__name__, 'abi/UniswapV2Factory.bin')

    def __init__(self, web3: Web3, token_a: Token, token_b: Token,
                 keeper_address: Address, router_address: Address,
                 factory_address: Address):
        assert (isinstance(web3, Web3))
        assert (isinstance(token_a, Token))
        assert (isinstance(token_b, Token))
        assert (isinstance(keeper_address, Address))
        assert (isinstance(router_address, Address))
        assert (isinstance(factory_address, Address))

        self.web3 = web3
        self.token_a = token_a
        self.token_b = token_b
        self.router_address = router_address
        self.factory_address = factory_address
        self._router_contract = self._get_contract(web3, self.Irouter_abi,
                                                   self.router_address)
        self._factory_contract = self._get_contract(web3, self.Ifactory_abi,
                                                    self.factory_address)

        self.pair_address = self.get_pair_address(self.token_a.address,
                                                  self.token_b.address)
        self.is_new_pool = self.pair_address == Address(
            "0x0000000000000000000000000000000000000000")
        if not self.is_new_pool:
            self.set_and_approve_pair_token(self.pair_address)

        self.account_address = keeper_address

    def set_and_approve_pair_token(self, pair_address: Address):
        self.pair_address = pair_address
        self._pair_contract = self._get_contract(self.web3,
                                                 self.pair_abi['abi'],
                                                 self.pair_address)
        self.pair_token = Token('Liquidity', self.pair_address, 18)
        self.is_new_pool = False

    def get_account_token_balance(self, token: Token) -> Wad:
        assert (isinstance(token, Token))

        return token.normalize_amount(
            ERC20Token(web3=self.web3,
                       address=token.address).balance_of(self.account_address))

    def get_account_eth_balance(self) -> Wad:
        return Wad.from_number(
            Web3.fromWei(
                self.web3.eth.getBalance(self.account_address.address),
                'ether'))

    def get_exchange_balance(self, token: Token, pair_address: Address) -> Wad:
        assert (isinstance(token, Token))
        assert (isinstance(pair_address, Address))

        return token.normalize_amount(
            ERC20Token(web3=self.web3,
                       address=token.address).balance_of(pair_address))

    def get_our_exchange_balance(self, token: Token,
                                 pair_address: Address) -> Wad:
        assert (isinstance(token, Token))
        assert (isinstance(pair_address, Address))

        if self.is_new_pool:
            return Wad.from_number(0)

        current_liquidity = self.get_current_liquidity()
        if current_liquidity == Wad.from_number(0):
            return Wad.from_number(0)

        total_liquidity = self.get_total_liquidity()
        exchange_balance = self.get_exchange_balance(token, pair_address)

        return current_liquidity * exchange_balance / total_liquidity

    # retrieve exchange rate for the instance's pair token
    def get_exchange_rate(self) -> Wad:
        token_a_reserve = self.get_exchange_balance(self.token_a,
                                                    self.pair_address)
        token_b_reserve = self.get_exchange_balance(self.token_b,
                                                    self.pair_address)

        if token_a_reserve == Wad.from_number(
                0) or token_b_reserve == Wad.from_number(0):
            return Wad.from_number(0)
        else:
            return token_b_reserve / token_a_reserve

    # Return the total number of liquidity tokens minted for a given pair
    def get_total_liquidity(self) -> Wad:
        return Wad(self._pair_contract.functions.totalSupply().call())

    # Return our liquidity token balance
    def get_current_liquidity(self) -> Wad:
        return Wad(
            self._pair_contract.functions.balanceOf(
                self.account_address.address).call())

    # Return a pools minimum liquidity token balance
    def get_minimum_liquidity(self) -> Wad:
        return Wad(
            self._pair_contract.functions.MINIMUM_LIQUIDITY(
                self.account_address.address).call())

    def get_pair_address(self, token_a_address: Address,
                         token_b_address: Address) -> Address:
        assert (isinstance(token_a_address, Address))
        assert (isinstance(token_b_address, Address))

        return Address(
            self._factory_contract.functions.getPair(
                token_a_address.address, token_b_address.address).call())

    def approve(self, token: Token):
        assert (isinstance(token, Token))

        erc20_token = ERC20Token(self.web3, token.address)

        approval_function = directly()
        return approval_function(erc20_token, self.router_address,
                                 'UniswapV2Router02')

    @staticmethod
    def _to_32byte_hex(val):
        return Web3.toHex(Web3.toBytes(val).rjust(32, b'\0'))

    def get_amounts_out(self, amount_in: Wad,
                        tokens: List[Token]) -> List[Wad]:
        """ Calculate maximum output amount of a given input.

        Desired amount_in must be less than available liquidity or call will fail.

        Args:
            amounts_in: Desired amount of tokens out.
            tokens: List of tokens used to form a path for swap and normalize amounts for token decimals
        Returns:
            A list of uint256 reserve amounts required.
        """
        assert (isinstance(amount_in, Wad))
        assert (isinstance(tokens, List))

        token_addresses = list(map(lambda token: token.address.address,
                                   tokens))
        amounts = self._router_contract.functions.getAmountsOut(
            amount_in.value, token_addresses).call()
        wad_amounts = list(
            map(lambda amount: Wad.from_number(Web3.fromWei(amount, 'ether')),
                amounts))

        for index, token in enumerate(tokens):
            wad_amounts[index] = token.normalize_amount(wad_amounts[index])

        return wad_amounts

    def get_amounts_in(self, amount_out: Wad, path: List) -> List[Wad]:
        """ Calculate amount of given inputs to achieve an exact output amount.
        
        Desired amount_out must be less than available liquidity or call will fail.

        Args:
            amount_out: Desired amount of tokens out.
            path: List of addresses used to form a path for swap 
        Returns:
            A list of uint256 reserve amounts required.
        """
        assert (isinstance(amount_out, Wad))
        assert (isinstance(path, List))

        amounts = self._router_contract.functions.getAmountsIn(
            amount_out.value, path).call()
        return list(
            map(lambda amount: Wad.from_number(Web3.fromWei(amount, 'ether')),
                amounts))

    def add_liquidity(self, amounts: dict, token_a: Token,
                      token_b: Token) -> Transact:
        """ Add liquidity to arbitrary token pair.

        Args:
            amounts: dictionary[Wad, Wad, Wad, Wad]
            token_a: First token in the pool
            token_b: Second token in the pool
        Returns:
            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(amounts, dict))
        assert (isinstance(token_a, Token))
        assert (isinstance(token_b, Token))

        addLiquidityArgs = [
            token_a.address.address, token_b.address.address,
            amounts['amount_a_desired'].value,
            amounts['amount_b_desired'].value, amounts['amount_a_min'].value,
            amounts['amount_b_min'].value, self.account_address.address,
            self._deadline()
        ]

        return Transact(self, self.web3, self.router_abi, self.router_address,
                        self._router_contract, 'addLiquidity',
                        addLiquidityArgs)

    def add_liquidity_eth(self, amounts: dict, token: Token,
                          eth_position: int) -> Transact:
        """ Add liquidity to token-weth pair.

        It is assumed that eth will always be token_a

        Args:
            amounts: dictionary[Wad, Wad, Wad, Wad]
            token_b: Token side of the pool
        Returns:
            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(amounts, dict))
        assert (isinstance(token, Token))
        assert (isinstance(eth_position, int))

        if eth_position == 0:
            token_desired = amounts['amount_b_desired'].value
            token_min = amounts['amount_b_min'].value
            eth_desired = amounts['amount_a_desired'].value
            eth_min = amounts['amount_a_min'].value
        elif eth_position == 1:
            token_desired = amounts['amount_a_desired'].value
            token_min = amounts['amount_a_min'].value
            eth_desired = amounts['amount_b_desired'].value
            eth_min = amounts['amount_b_min'].value

        addLiquidityArgs = [
            token.address.address, token_desired, token_min, eth_min,
            self.account_address.address,
            self._deadline()
        ]

        return Transact(self, self.web3, self.router_abi, self.router_address,
                        self._router_contract, 'addLiquidityETH',
                        addLiquidityArgs, {'value': eth_desired})

    def remove_liquidity(self, amounts: dict, token_a: Token,
                         token_b: Token) -> Transact:
        """ Remove liquidity from arbitrary token pair.

        Args:
            token_a: Address of pool token A.
            token_b: Address of pool token B.
            amounts: dictionary[uint256, uint256, uint256]
        Returns:
            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(token_a, Token))
        assert (isinstance(token_b, Token))
        assert (isinstance(amounts, dict))

        # Will approve Uniswap Liquidity token if allowance not already set
        self.approve(self.pair_token)

        removeLiquidityArgs = [
            token_a.address.address, token_b.address.address,
            amounts['liquidity'].value, amounts['amountAMin'].value,
            amounts['amountBMin'].value, self.account_address.address,
            self._deadline()
        ]

        return Transact(self, self.web3, self.router_abi, self.router_address,
                        self._router_contract, 'removeLiquidity',
                        removeLiquidityArgs)

    def remove_liquidity_eth(self, amounts: dict, token: Token,
                             eth_position: int) -> Transact:
        """ Remove liquidity from token-weth pair.

        Args:
            token_a: Address of pool token.
            amounts: dictionary[uint256, uint256, uint256]
        Returns:
            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(amounts, dict))
        assert (isinstance(token, Token))
        assert (isinstance(eth_position, int))

        # Will approve Uniswap Liquidity token if allowance not already set
        self.approve(self.pair_token)

        if eth_position == 0:
            token_min = amounts['amountBMin'].value
            eth_min = amounts['amountAMin'].value
        elif eth_position == 1:
            token_min = amounts['amountAMin'].value
            eth_min = amounts['amountBMin'].value

        removeLiquidityArgs = [
            token.address.address, amounts['liquidity'].value, token_min,
            eth_min, self.account_address.address,
            self._deadline()
        ]

        return Transact(self, self.web3, self.router_abi, self.router_address,
                        self._router_contract,
                        'removeLiquidityETHSupportingFeeOnTransferTokens',
                        removeLiquidityArgs)

    def swap_exact_eth_for_tokens(self, eth_to_swap: Wad, min_amount_out: Wad,
                                  path: List) -> Transact:
        """Convert ETH to Tokens.

        Requires Approval to have already been called on the token to swap

        Args:
            eth_to_swap: Amount of ETH to swap for token.
            min_amount_out: Minimum amount of output token to set price
            path: array of token addresses used to form swap route
        Returns:
            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(eth_to_swap, Wad))
        assert (isinstance(min_amount_out, Wad))
        assert (isinstance(path, List))

        swapArgs = [
            min_amount_out.value, path, self.account_address.address,
            self._deadline()
        ]

        return Transact(self, self.web3, self.router_abi, self.router_address,
                        self._router_contract, 'swapExactETHForTokens',
                        swapArgs, {'value': eth_to_swap.value})

    def swap_exact_tokens_for_tokens(self, tokens_to_swap: Wad,
                                     min_amount_out: Wad,
                                     path: List) -> Transact:
        """Convert ERC20 to ERC20.

        Requires Approval to have already been called on the token to swap

        Args:
            tokens_to_swap: Amount of given token to swap for token.
            min_amount_out: Minimum amount of output token to set price
            path: array of token addresses used to form swap route
        Returns:
            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(tokens_to_swap, Wad))
        assert (isinstance(min_amount_out, Wad))
        assert (isinstance(path, List))

        swapArgs = [
            tokens_to_swap.value, min_amount_out.value, path,
            self.account_address.address,
            self._deadline()
        ]

        return Transact(self, self.web3, self.router_abi, self.router_address,
                        self._router_contract, 'swapExactTokensForTokens',
                        swapArgs)

    def _deadline(self) -> int:
        """Get a predefined deadline."""
        return int(time.time()) + 1000

    def __eq__(self, other):
        assert (isinstance(other, UniswapExchange))
        return self.address == other.address

    def __repr__(self):
        return f"UniswapV2"
示例#11
0
class GlobalSettlement(Contract):
    """A client for the `GlobalSettlement` contract, used to orchestrate a shutdown.

    Ref. <https://github.com/reflexer-labs/geb/blob/master/src/GlobalSettlement.sol>

    Attributes:
      web3: An instance of `Web` from `web3.py`.
      address: Ethereum address of the `ESM` contract."""

    abi = Contract._load_abi(__name__, 'abi/GlobalSettlement.abi')
    bin = Contract._load_bin(__name__, 'abi/GlobalSettlement.bin')

    def __init__(self, web3: Web3, address: Address):
        assert isinstance(web3, Web3)
        assert isinstance(address, Address)

        self.web3 = web3
        self.address = address
        self._contract = self._get_contract(web3, self.abi, address)

    def contract_enabled(self) -> bool:
        """True when enabled, false when disabled"""
        return self._contract.functions.contractEnabled().call() > 0

    def authorized_accounts(self, address: Address) -> bool:
        """True if address is authorized"""

        return bool(
            self._contract.functions.authorizedAccounts(
                address.address).call())

    def stability_fee_treasury(self) -> Address:
        """Return stabilityFeeTreasury"""

        return Address(self._contract.functions.stabilityFeeTreasury().call())

    def shutdown_time(self) -> datetime:
        """Time of disable_contract"""
        timestamp = self._contract.functions.shutdownTime().call()
        return datetime.utcfromtimestamp(timestamp)

    def shutdown_cooldown(self) -> int:
        """Processing cooldown length, in seconds"""
        return int(self._contract.functions.shutdownCooldown().call())

    def outstanding_coin_supply(self) -> Rad:
        """total outstanding system coin following processing"""
        return Rad(self._contract.functions.outstandingCoinSupply().call())

    def final_coin_per_collateral_price(
            self, collateral_type: CollateralType) -> Ray:
        """Shutdown price for the collateral"""
        assert isinstance(collateral_type, CollateralType)
        return Ray(
            self._contract.functions.finalCoinPerCollateralPrice(
                collateral_type.toBytes()).call())

    def collateral_shortfall(self, collateral_type: CollateralType) -> Wad:
        """Collateral shortfall (difference of debt and collateral"""
        assert isinstance(collateral_type, CollateralType)
        return Wad(
            self._contract.functions.collateralShortfall(
                collateral_type.toBytes()).call())

    def collateral_total_debt(self, collateral_type: CollateralType) -> Wad:
        """Total debt for the collateral"""
        assert isinstance(collateral_type, CollateralType)
        return Wad(
            self._contract.functions.collateralTotalDebt(
                collateral_type.toBytes()).call())

    def collateral_cash_price(self, collateral_type: CollateralType) -> Ray:
        """Final cash price for the collateral"""
        assert isinstance(collateral_type, CollateralType)
        return Ray(
            self._contract.functions.collateralCashPrice(
                collateral_type.toBytes()).call())

    def coin_bag(self, address: Address) -> Wad:
        """Amount of system `prepare_coins_for_redeeming`ed for retrieving collateral in return"""
        assert isinstance(address, Address)
        return Wad(self._contract.functions.coinBag(address.address).call())

    def coins_used_to_redeem(self, collateral_type: CollateralType,
                             address: Address) -> Wad:
        assert isinstance(collateral_type, CollateralType)
        assert isinstance(address, Address)
        return Wad(
            self._contract.functions.coinsUsedToRedeem(
                collateral_type.toBytes(), address.address).call())

    def freeze_collateral_type(self,
                               collateral_type: CollateralType) -> Transact:
        """Set the `shutdownSystem` price for the collateral"""
        assert isinstance(collateral_type, CollateralType)

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'freezeCollateralType(bytes32)',
                        [collateral_type.toBytes()])

    def fast_track_auction(self, collateral_type: CollateralType,
                           collateral_auction_id: int) -> Transact:
        """Cancel a collateral auction and seize it's collateral"""
        assert isinstance(collateral_type, CollateralType)
        assert isinstance(collateral_auction_id, int)
        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'fastTrackAuction',
                        [collateral_type.toBytes(), collateral_auction_id])

    def process_safe(self, collateral_type: CollateralType,
                     address: Address) -> Transact:
        """Cancels undercollateralized SAFE debt to determine collateral shortfall"""
        assert isinstance(collateral_type, CollateralType)
        assert isinstance(address, Address)
        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'processSAFE',
                        [collateral_type.toBytes(), address.address])

    def free_collateral(self, collateral_type: CollateralType) -> Transact:
        """Releases excess collateral after `process_safe`ing"""
        assert isinstance(collateral_type, CollateralType)
        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'freeCollateral',
                        [collateral_type.toBytes()])

    def set_outstanding_coin_supply(self):
        """Fix the total outstanding supply of system coin"""
        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'setOutstandingCoinSupply', [])

    def calculate_cash_price(self,
                             collateral_type: CollateralType) -> Transact:
        """Calculate the `fix`, the cash price for a given collateral"""
        assert isinstance(collateral_type, CollateralType)
        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'calculateCashPrice',
                        [collateral_type.toBytes()])

    def prepare_coins_for_redeeming(self, system_coin: Wad) -> Transact:
        """Deposit system coin into the `coin_bag`, from which it cannot be withdrawn"""
        assert isinstance(system_coin, Wad)
        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'prepareCoinsForRedeeming',
                        [system_coin.value])

    def redeem_collateral(self, collateral_type: CollateralType,
                          system_coin: Wad):
        """Exchange an amount of system coin (already `prepare_coins_for_redeemin`ed in the `coin_bag`) for collateral"""
        assert isinstance(collateral_type, CollateralType)
        assert isinstance(system_coin, Wad)
        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'redeemCollateral',
                        [collateral_type.toBytes(), system_coin.value])
示例#12
0
class TxManager(Contract):
    """A client for the `TxManager` contract.

    `TxManager` allows to invoke multiple contract methods in one Ethereum transaction.
    Each invocation is represented as an instance of the `Invocation` class, containing a
    contract address and a calldata.

    In addition to that, these invocations can use ERC20 token balances. In order to do that,
    the entire allowance of each token involved is transferred from the caller to the `TxManager`
    contract at the beginning of the transaction and all the remaining balances are returned
    to the caller at the end of it. In order to use this feature, ERC20 token allowances
    have to be granted to the `TxManager`.

    You can find the source code of the `TxManager` contract here:
    <https://github.com/reflexer-labs/geb-tx-manager>.

    Attributes:
        web3: An instance of `Web` from `web3.py`.
        address: Ethereum address of the `TxManager` contract.
    """

    abi = Contract._load_abi(__name__, 'abi/TxManager.abi')
    bin = Contract._load_bin(__name__, 'abi/TxManager.bin')

    def __init__(self, web3: Web3, address: Address):
        assert(isinstance(web3, Web3))
        assert(isinstance(address, Address))

        self.web3 = web3
        self.address = address
        self._contract = self._get_contract(web3, self.abi, address)

    @staticmethod
    def deploy(web3: Web3):
        return TxManager(web3=web3, address=Contract._deploy(web3, TxManager.abi, TxManager.bin, []))

    def approve(self, tokens: List[ERC20Token], approval_function):
        """Approve the TxManager contract to fully access balances of specified tokens.

        For available approval functions (i.e. approval modes) see `directly` and `via_tx_manager`
        in `pyflex.approval`.

        Args:
            tokens: List of :py:class:`pyflex.token.ERC20Token` class instances.
            approval_function: Approval function (i.e. approval mode).
        """
        assert(isinstance(tokens, list))
        assert(callable(approval_function))

        for token in tokens:
            approval_function(token, self.address, 'TxManager')

    def owner(self) -> Address:
        return Address(self._contract.functions.owner().call())

    def execute(self, tokens: List[Address], invocations: List[Invocation]) -> Transact:
        """Executes multiple contract methods in one Ethereum transaction.

        Args:
            tokens: List of addresses of ERC20 token the invocations should be able to access.
            invocations: A list of invocations (contract methods) to be executed.

        Returns:
            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """
        def token_addresses() -> list:
            return list(map(lambda address: address.address, tokens))

        def script() -> bytes:
            return reduce(operator.add, map(lambda invocation: script_entry(invocation), invocations), bytes())

        def script_entry(invocation: Invocation) -> bytes:
            address = invocation.address.as_bytes()
            calldata = invocation.calldata.as_bytes()
            calldata_length = len(calldata).to_bytes(32, byteorder='big')
            return address + calldata_length + calldata

        assert(isinstance(tokens, list))
        assert(isinstance(invocations, list))

        return Transact(self, self.web3, self.abi, self.address, self._contract, 'execute', [token_addresses(), script()])

    def __repr__(self):
        return f"TxManager('{self.address}')"
示例#13
0
class DSValue(DSAuth):
    """A client for the `DSValue` contract, a single-value data feed.

    `DSValue` is a single-value data feed, which means it can be in one of two states.
    It can either contain a value (in which case `has_value()` returns `True` and the read methods
    return that value) or be empty (in which case `has_value()` returns `False` and the read
    methods throw exceptions).

    `DSValue` can be populated with a new value using `updateResult()` and cleared using `void()`.

    Everybody can read from a `DSValue`.
    Calling `updateResult()` and `void()` is usually whitelisted to some addresses only.
    upda

    The `DSValue` contract keeps the value as a 32-byte array (Ethereum `bytes32` type).
    Methods have been provided to cast it into `int`, read as hex etc.

    You can find the source code of the `DSValue` contract here:
    <https://github.com/dapphub/ds-value>.

    Attributes:
        web3: An instance of `Web` from `web3.py`.
        address: Ethereum address of the `DSValue` contract.
    """

    abi = Contract._load_abi(__name__, 'abi/DSValue.abi')
    bin = Contract._load_bin(__name__, 'abi/DSValue.bin')

    @staticmethod
    def deploy(web3: Web3):
        return DSValue(web3=web3,
                       address=Contract._deploy(web3, DSValue.abi, DSValue.bin,
                                                []))

    def __init__(self, web3: Web3, address: Address):
        assert (isinstance(web3, Web3))
        assert (isinstance(address, Address))

        self.web3 = web3
        self.address = address
        self._contract = self._get_contract(web3, self.abi, address)

    def has_value(self) -> bool:
        """Checks whether this instance contains a value.

        Returns:
            `True` if this instance contains a value, which can be read. `False` otherwise.
        """
        return self._contract.functions.getResultWithValidity().call()[1]

    def read(self) -> int:
        """Reads the current value from this instance

        If this instance does not contain a value, throws an exception.

        Returns:
            An integer with the current value of this instance.
        """
        return self._contract.functions.read().call()

    def update_result(self, new_value: int) -> Transact:
        """Populates this instance with a new value.

        Args:
            new_value: An integer of the new value to be set.

        Returns:
            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(new_value, int))
        #assert(len(new_value) == 32)
        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'updateResult', [new_value])

    def restart_value(self) -> Transact:
        """Removes the current value from this instance.

        Returns:
            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """
        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'restartValue', [])

    def __repr__(self):
        return f"DSValue('{self.address}')"
示例#14
0
class TestUniswapV2(Contract):
    """
    In order to run automated tests locally, all dependent contracts and deployable bytecode need to be available for deploying contract to local network. 
    Deployable bytecode differs from the runtime bytecode you would see on Etherscan.

    """
    pair_abi = Contract._load_abi(__name__,
                                  '../pyexchange/abi/IUniswapV2Pair.abi')
    Irouter_abi = Contract._load_abi(
        __name__, '../pyexchange/abi/IUniswapV2Router02.abi')['abi']
    router_abi = Contract._load_abi(__name__,
                                    '../pyexchange/abi/UniswapV2Router02.abi')
    router_bin = Contract._load_bin(__name__,
                                    '../pyexchange/abi/UniswapV2Router02.bin')
    factory_abi = Contract._load_abi(__name__,
                                     '../pyexchange/abi/UniswapV2Factory.abi')
    factory_bin = Contract._load_bin(__name__,
                                     '../pyexchange/abi/UniswapV2Factory.bin')
    weth_abi = Contract._load_abi(__name__, '../pyexchange/abi/WETH.abi')
    weth_bin = Contract._load_bin(__name__, '../pyexchange/abi/WETH.bin')

    def setup_method(self):

        # Use Ganache docker container
        self.web3 = Web3(HTTPProvider("http://0.0.0.0:8555"))
        self.web3.eth.defaultAccount = Web3.toChecksumAddress(
            "0x9596C16D7bF9323265C2F2E22f43e6c80eB3d943")
        register_private_key(
            self.web3,
            "0x91cf2cc3671a365fcbf38010ff97ee31a5b7e674842663c56769e41600696ead"
        )

        self.our_address = Address(self.web3.eth.defaultAccount)

        self.weth_address = self._deploy(self.web3, self.weth_abi,
                                         self.weth_bin, [])
        self.factory_address = self._deploy(self.web3, self.factory_abi,
                                            self.factory_bin,
                                            [self.our_address.address])
        self.router_address = self._deploy(
            self.web3, self.router_abi, self.router_bin,
            [self.factory_address.address, self.weth_address.address])
        self._weth_contract = self._get_contract(self.web3, self.weth_abi,
                                                 self.weth_address)

        self.ds_systemcoin = DSToken.deploy(self.web3, 'SystemCoin', 'sys')
        self.ds_usdc = DSToken.deploy(self.web3, 'USDC', 'USDC')
        self.token_systemcoin = Token("SystemCoin", self.ds_systemcoin.address,
                                      18)
        self.token_usdc = Token("USDC", self.ds_usdc.address, 6)
        self.token_weth = Token("WETH", self.weth_address, 18)

        self.systemcoin_usdc_uniswap = UniswapV2(
            self.web3, self.token_systemcoin, self.token_usdc,
            self.our_address, self.router_address, self.factory_address)
        self.systemcoin_eth_uniswap = UniswapV2(
            self.web3, self.token_systemcoin, self.token_weth,
            self.our_address, self.router_address, self.factory_address)

        ## Useful for debugging failing transactions
        logger = logging.getLogger('eth')
        logger.setLevel(8)
        # Transact.gas_estimate_for_bad_txs = 210000

    def add_liquidity_tokens(self) -> Receipt:
        self.ds_systemcoin.mint(Wad(
            17 * 10**18)).transact(from_address=self.our_address)
        self.ds_usdc.mint(
            self.token_usdc.unnormalize_amount(
                Wad.from_number(9))).transact(from_address=self.our_address)
        self.systemcoin_usdc_uniswap.approve(self.token_systemcoin)
        self.systemcoin_usdc_uniswap.approve(self.token_usdc)

        add_liquidity_tokens_args = {
            "amount_a_desired":
            Wad.from_number(1.9),
            "amount_b_desired":
            self.token_usdc.unnormalize_amount(Wad.from_number(2.0)),
            "amount_a_min":
            Wad.from_number(1.8),
            "amount_b_min":
            self.token_usdc.unnormalize_amount(Wad.from_number(1.9))
        }

        return self.systemcoin_usdc_uniswap.add_liquidity(
            add_liquidity_tokens_args, self.token_systemcoin,
            self.token_usdc).transact(from_address=self.our_address)

    def add_liquidity_eth(self) -> Receipt:
        self.ds_systemcoin.mint(Wad(
            300 * 10**18)).transact(from_address=self.our_address)
        self.systemcoin_eth_uniswap.approve(self.token_systemcoin)
        self.systemcoin_eth_uniswap.approve(self.token_weth)

        add_liquidity_eth_args = {
            "amount_b_desired": Wad.from_number(28),
            "amount_a_desired": Wad.from_number(.1),
            "amount_b_min": Wad.from_number(25),
            "amount_a_min": Wad.from_number(0.01)
        }

        return self.systemcoin_eth_uniswap.add_liquidity_eth(
            add_liquidity_eth_args, self.token_systemcoin,
            0).transact(from_address=self.our_address)

    def test_approval(self):
        # given
        assert self.ds_systemcoin.allowance_of(self.our_address,
                                               self.router_address) == Wad(0)

        # when
        self.systemcoin_usdc_uniswap.approve(self.token_systemcoin)

        # then
        assert self.ds_systemcoin.allowance_of(self.our_address,
                                               self.router_address) > Wad(0)

    def test_getting_token_balances(self):
        # given
        self.ds_systemcoin.mint(Wad(17 * 10**18)).transact()
        self.ds_usdc.mint(
            self.token_usdc.unnormalize_amount(Wad.from_number(9))).transact()

        # when
        balance_systemcoin = self.systemcoin_usdc_uniswap.get_account_token_balance(
            self.token_systemcoin)
        balance_usdc = self.systemcoin_usdc_uniswap.get_account_token_balance(
            self.token_usdc)

        # then
        assert balance_systemcoin == Wad.from_number(17)
        assert balance_usdc == Wad.from_number(9)

    def test_add_liquidity_tokens(self):
        # when
        add_liquidity = self.add_liquidity_tokens()

        # then
        assert add_liquidity.successful == True

        # when
        self.systemcoin_usdc_uniswap.set_and_approve_pair_token(
            self.systemcoin_usdc_uniswap.get_pair_address(
                self.token_systemcoin.address, self.token_usdc.address))

        # then
        assert self.systemcoin_usdc_uniswap.get_current_liquidity(
        ) > Wad.from_number(0)

    def test_add_liquidity_eth(self):
        # when
        add_liquidity_eth = self.add_liquidity_eth()

        # then
        assert add_liquidity_eth.successful == True

        # when
        self.systemcoin_eth_uniswap.set_and_approve_pair_token(
            self.systemcoin_usdc_uniswap.get_pair_address(
                self.token_systemcoin.address, self.token_weth.address))

        # then
        assert self.systemcoin_eth_uniswap.get_current_liquidity(
        ) > Wad.from_number(0)

    def test_remove_liquidity_tokens(self):
        # given
        add_liquidity = self.add_liquidity_tokens()
        self.systemcoin_usdc_uniswap.set_and_approve_pair_token(
            self.systemcoin_usdc_uniswap.get_pair_address(
                self.token_systemcoin.address, self.token_usdc.address))

        current_liquidity = self.systemcoin_usdc_uniswap.get_current_liquidity(
        )
        total_liquidity = self.systemcoin_usdc_uniswap.get_total_liquidity()
        systemcoin_exchange_balance = self.systemcoin_usdc_uniswap.get_exchange_balance(
            self.token_systemcoin, self.systemcoin_usdc_uniswap.pair_address)
        usdc_exchange_balance = self.token_usdc.unnormalize_amount(
            self.systemcoin_usdc_uniswap.get_exchange_balance(
                self.token_usdc, self.systemcoin_usdc_uniswap.pair_address))

        # then
        assert current_liquidity > Wad.from_number(0)
        assert total_liquidity > Wad.from_number(0)
        assert total_liquidity > current_liquidity

        # given
        amount_a_min = current_liquidity * systemcoin_exchange_balance / total_liquidity
        amount_b_min = current_liquidity * usdc_exchange_balance / total_liquidity
        remove_liquidity_tokens_args = {
            "liquidity": current_liquidity,
            "amountAMin": amount_a_min,
            "amountBMin": amount_b_min
        }

        # when
        remove_liquidity = self.systemcoin_usdc_uniswap.remove_liquidity(
            remove_liquidity_tokens_args, self.token_systemcoin,
            self.token_usdc).transact(from_address=self.our_address)

        # then
        assert remove_liquidity.successful == True
        assert self.systemcoin_usdc_uniswap.get_current_liquidity(
        ) == Wad.from_number(0)

    def test_remove_liquidity_eth(self):
        # given
        add_liquidity_eth = self.add_liquidity_eth()
        self.systemcoin_eth_uniswap.set_and_approve_pair_token(
            self.systemcoin_eth_uniswap.get_pair_address(
                self.token_systemcoin.address, self.token_weth.address))

        current_liquidity = self.systemcoin_eth_uniswap.get_current_liquidity()
        total_liquidity = self.systemcoin_eth_uniswap.get_total_liquidity()
        systemcoin_exchange_balance = self.systemcoin_eth_uniswap.get_exchange_balance(
            self.token_systemcoin, self.systemcoin_eth_uniswap.pair_address)
        weth_exchange_balance = self.systemcoin_eth_uniswap.get_exchange_balance(
            self.token_weth, self.systemcoin_eth_uniswap.pair_address)

        # then
        assert current_liquidity > Wad.from_number(0)
        assert total_liquidity > Wad.from_number(0)
        assert total_liquidity > current_liquidity

        # given
        amount_a_min = current_liquidity * weth_exchange_balance / total_liquidity
        amount_b_min = current_liquidity * systemcoin_exchange_balance / total_liquidity
        remove_liquidity_eth_args = {
            "liquidity": current_liquidity,
            "amountBMin": amount_b_min,
            "amountAMin": amount_a_min
        }

        # when
        remove_liquidity = self.systemcoin_eth_uniswap.remove_liquidity_eth(
            remove_liquidity_eth_args, self.token_systemcoin,
            0).transact(from_address=self.our_address)

        # then
        assert remove_liquidity.successful == True
        assert self.systemcoin_eth_uniswap.get_current_liquidity(
        ) == Wad.from_number(0)

    def test_tokens_swap(self):
        # given
        add_liquidity = self.add_liquidity_tokens()

        balance_systemcoin_before_swap = self.systemcoin_usdc_uniswap.get_account_token_balance(
            self.token_systemcoin)
        balance_usdc_before_swap = self.systemcoin_usdc_uniswap.get_account_token_balance(
            self.token_usdc)

        # when
        swap = self.systemcoin_usdc_uniswap.swap_exact_tokens_for_tokens(
            Wad.from_number(.2),
            self.token_usdc.unnormalize_amount(Wad.from_number(.01)),
            [self.ds_systemcoin.address.address, self.ds_usdc.address.address
             ]).transact(from_address=self.our_address)

        # then
        assert swap.successful == True

        balance_systemcoin_after_swap = self.systemcoin_usdc_uniswap.get_account_token_balance(
            self.token_systemcoin)
        balance_usdc_after_swap = self.systemcoin_usdc_uniswap.get_account_token_balance(
            self.token_usdc)

        assert balance_systemcoin_after_swap < balance_systemcoin_before_swap
        assert balance_usdc_before_swap < balance_usdc_after_swap
示例#15
0
class EnglishCollateralAuctionHouse(AuctionContract):
    """A client for the `EnglishCollateralAuctionHouse` contract, used to interact with collateral auctions.

    You can find the source code of the `EnglishCollateralAuctionHouse` contract here:
    <https://github.com/reflexer-labs/geb/blob/master/src/CollateralAuctionHouse.sol>.

    Attributes:
        web3: An instance of `Web` from `web3.py`.
        address: Ethereum address of the `EnglishCollateralAuctionHouse` contract.

    Event signatures:
    """

    abi = Contract._load_abi(__name__, 'abi/EnglishCollateralAuctionHouse.abi')
    bin = Contract._load_bin(__name__, 'abi/EnglishCollateralAuctionHouse.bin')

    class Bid:
        def __init__(self, id: int, bid_amount: Rad, amount_to_sell: Wad,
                     high_bidder: Address, bid_expiry: int,
                     auction_deadline: int,
                     forgone_collateral_receiver: Address,
                     auction_income_recipient: Address, amount_to_raise: Rad):
            assert (isinstance(id, int))
            assert (isinstance(bid_amount, Rad))
            assert (isinstance(amount_to_sell, Wad))
            assert (isinstance(high_bidder, Address))
            assert (isinstance(bid_expiry, int))
            assert (isinstance(auction_deadline, int))
            assert (isinstance(forgone_collateral_receiver, Address))
            assert (isinstance(auction_income_recipient, Address))
            assert (isinstance(amount_to_raise, Rad))

            self.id = id
            self.bid_amount = bid_amount
            self.amount_to_sell = amount_to_sell
            self.high_bidder = high_bidder
            self.bid_expiry = bid_expiry
            self.auction_deadline = auction_deadline
            self.forgone_collateral_receiver = forgone_collateral_receiver
            self.auction_income_recipient = auction_income_recipient
            self.amount_to_raise = amount_to_raise

        def __repr__(self):
            return f"EnglishCollateralAuctionHouse.Bid({pformat(vars(self))})"

    class StartAuctionLog:
        def __init__(self, log):
            args = log['args']
            self.id = int(args['id'])
            self.amount_to_sell = Wad(args['amountToSell'])
            self.bid_amount = Rad(args['initialBid'])
            self.amount_to_raise = Rad(args['amountToRaise'])
            self.forgone_collateral_receiver = Address(
                args['forgoneCollateralReceiver'])
            self.auction_income_recipient = Address(
                args['auctionIncomeRecipient'])
            self.block = log['blockNumber']
            self.tx_hash = log['transactionHash'].hex()

        def __repr__(self):
            return f"EnglishCollateralAuctionHouse.StartAuctionLog({pformat(vars(self))})"

    class IncreaseBidSizeLog:
        def __init__(self, log):
            args = log['args']
            self.id = int(args['id'])
            self.high_bidder = Address(args['highBidder'])
            self.amount_to_buy = Wad(args['amountToBuy'])
            self.rad = Rad(args['rad'])
            self.bid_expiry = int(args['bidExpiry'])
            self.block = log['blockNumber']
            self.tx_hash = log['transactionHash'].hex()

        def __repr__(self):
            return f"EnglishCollateralAuctionHouse.IncreaseBidSizeLog({pformat(vars(self))})"

    class DecreaseSoldAmountLog:
        def __init__(self, log):
            args = log['args']
            self.id = int(args['id'])
            self.high_bidder = Address(args['highBidder'])
            self.amount_to_buy = Wad(args['amountToBuy'])
            self.rad = Rad(args['rad'])
            self.bid_expiry = int(args['bidExpiry'])
            self.block = log['blockNumber']
            self.tx_hash = log['transactionHash'].hex()

        def __repr__(self):
            return f"EnglishCollateralAuctionHouse.DecreaseSoldAmountLog({pformat(vars(self))})"

    class SettleAuctionLog:
        def __init__(self, log):
            args = log['args']
            self.id = args['id']
            self.block = log['blockNumber']
            self.tx_hash = log['transactionHash'].hex()

        def __repr__(self):
            return f"EnglishCollateralAuctionHouse.StartAuctionLog({pformat(vars(self))})"

    def __init__(self, web3: Web3, address: Address):
        assert isinstance(web3, Web3)
        assert isinstance(address, Address)

        # Set ABIs for event names that are not in AuctionContract
        self.increase_bid_size_abi = None
        self.decrease_sold_amount_abi = None

        for member in EnglishCollateralAuctionHouse.abi:
            if not self.increase_bid_size_abi and member.get(
                    'name') == 'IncreaseBidSize':
                self.increase_bid_size_abi = member
            elif not self.decrease_sold_amount_abi and member.get(
                    'name') == 'DecreaseSoldAmount':
                self.decrease_sold_amount_abi = member

        super(EnglishCollateralAuctionHouse,
              self).__init__(web3, address, EnglishCollateralAuctionHouse.abi,
                             self.bids)

        assert self._contract.functions.AUCTION_TYPE().call() == toBytes(
            'ENGLISH')

    def bid_duration(self) -> int:
        """Returns the bid lifetime.

        Returns:
            The bid lifetime (in seconds).
        """
        return int(self._contract.functions.bidDuration().call())

    def bid_increase(self) -> Wad:
        """Returns the percentage minimum bid increase.

        Returns:
            The percentage minimum bid increase.
        """
        return Wad(self._contract.functions.bidIncrease().call())

    def bids(self, id: int) -> Bid:
        """Returns the auction details.

        Args:
            id: Auction identifier.

        Returns:
            The auction details.
        """
        assert (isinstance(id, int))

        array = self._contract.functions.bids(id).call()
        return EnglishCollateralAuctionHouse.Bid(
            id=id,
            bid_amount=Rad(array[0]),
            amount_to_sell=Wad(array[1]),
            high_bidder=Address(array[2]),
            bid_expiry=int(array[3]),
            auction_deadline=int(array[4]),
            forgone_collateral_receiver=Address(array[5]),
            auction_income_recipient=Address(array[6]),
            amount_to_raise=Rad(array[7]))

    def start_auction(self, forgone_collateral_receiver: Address,
                      auction_income_recipient: Address, amount_to_raise: Rad,
                      amount_to_sell: Wad, bid_amount: Rad) -> Transact:
        assert (isinstance(forgoneCollateralReceiver, Address))
        assert (isinstance(auction_income_recipient, Address))
        assert (isinstance(amount_to_raise, Rad))
        assert (isinstance(amount_to_sell, Wad))
        assert (isinstance(bid_amount, Rad))

        return Transact(
            self, self.web3, self.abi, self.address, self._contract,
            'startAuction', [
                forgone_collateral_receiver.address,
                auction_income_recipient.address, amount_to_raise.value,
                amount_to_sell.value, bid_amount.value
            ])

    def increase_bid_size(self, id: int, amount_to_sell: Wad,
                          bid_amount: Rad) -> Transact:
        assert (isinstance(id, int))
        assert (isinstance(amount_to_sell, Wad))
        assert (isinstance(bid_amount, Rad))

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'increaseBidSize',
                        [id, amount_to_sell.value, bid_amount.value])

    def decrease_sold_amount(self, id: int, amount_to_sell: Wad,
                             bid_amount: Rad) -> Transact:
        assert (isinstance(id, int))
        assert (isinstance(amount_to_sell, Wad))
        assert (isinstance(bid_amount, Rad))

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'decreaseSoldAmount',
                        [id, amount_to_sell.value, bid_amount.value])

    def restart_auction(self, id: int) -> Transact:
        """Resurrect an auction which expired without any bids."""
        assert (isinstance(id, int))

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'restartAuction', [id])

    def parse_event(self, event):
        signature = Web3.toHex(event['topics'][0])
        codec = ABICodec(default_registry)
        if signature == "0xdf7b5cd0ee6547c7389d2ac00ee0c1cd3439542399d6c8c520cc69c7409c0990":
            event_data = get_event_data(codec, self.start_auction_abi, event)
            return EnglishCollateralAuctionHouse.StartAuctionLog(event_data)
        elif signature == "0xd87c815d5a67c2e130ad04b714d87a6fb69d5a6df0dbb0f1639cd9fe292201f9":
            event_data = get_event_data(codec, self.increase_bid_size_abi,
                                        event)
            return EnglishCollateralAuctionHouse.IncreaseBidSizeLog(event_data)
        elif signature == "0x8c63feacc784a7f735e454365ba433f17d17293b02c57d98dad113977dbf0f13":
            event_data = get_event_data(codec, self.decrease_sold_amount_abi,
                                        event)
            return EnglishCollateralAuctionHouse.DecreaseSoldAmountLog(
                event_data)
        elif signature == "0x03af424b0e12d91ea31fe7f2c199fc02c9ede38f9aa1bdc019a8087b41445f7a":
            event_data = get_event_data(codec, self.settle_auction_abi, event)
            return EnglishCollateralAuctionHouse.SettleAuctionLog(event_data)

    def __repr__(self):
        return f"EnglishCollateralAuctionHouse('{self.address}')"
示例#16
0
class DSProxy(Contract):
    """A client for the `DSProxy` contract.

    Ref. <https://github.com/dapphub/ds-proxy/blob/master/src/proxy.sol#L28>
    """

    abi = Contract._load_abi(__name__, 'abi/DSProxy.abi')
    bin = Contract._load_bin(__name__, 'abi/DSProxy.bin')

    def __init__(self, web3: Web3, address: Address):
        assert (isinstance(web3, Web3))
        assert (isinstance(address, Address))

        self.web3 = web3
        self.address = address
        self._contract = self._get_contract(web3, self.abi, address)

    def authority(self) -> Address:
        """Return the current `authority` of a `DSAuth`-ed contract.

        Returns:
            The address of the current `authority`.
        """
        return Address(self._contract.functions.authority().call())

    def set_authority(self, address: Address) -> Transact:
        """Set the `authority` of a `DSAuth`-ed contract.

        Args:
            address: The address of the new `authority`.

        Returns:
            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(address, Address))
        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'setAuthority', [address.address])

    @classmethod
    def deploy(cls, web3: Web3, cache: Address):
        return cls(web3=web3,
                   address=Contract._deploy(web3, cls.abi, cls.bin,
                                            [cache.address]))

    def execute(self, code: str, calldata: Calldata) -> Transact:
        assert (isinstance(code, str))
        assert (isinstance(calldata, Calldata))

        if code.startswith('0x'):
            b32_code = hexstring_to_bytes(code)
        else:
            b32_code = hexstring_to_bytes('0x' + code)

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'execute(bytes,bytes)',
                        [b32_code, calldata.as_bytes()])

    def call(self, code: str, calldata: Calldata) -> (Address, HexBytes):
        assert (isinstance(code, str))
        assert (isinstance(calldata, Calldata))

        fn = self._contract.get_function_by_signature('execute(bytes,bytes)')
        target, response = fn(code, calldata.value).call()

        return Address(target), HexBytes(response)

    def execute_at(self, address: Address, calldata: Calldata) -> Transact:
        assert (isinstance(address, Address))
        assert (isinstance(calldata, Calldata))

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'execute(address,bytes)',
                        [address.address, calldata.as_bytes()])

    def call_at(self, address: Address, calldata: Calldata) -> Transact:
        assert (isinstance(address, Address))
        assert (isinstance(calldata, Calldata))

        fn = self._contract.get_function_by_signature('execute(address,bytes)')
        response = fn(address.address, calldata.value).call()

        return HexBytes(response)

    def set_cache(self, address: Address) -> Transact:
        assert (isinstance(address, Address))

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'setCache', [address.address])

    def cache(self) -> Address:
        return Address(self._contract.functions.cache().call())

    def __repr__(self):
        return f"DSProxy('{self.address}')"
示例#17
0
class DebtAuctionHouse(AuctionContract):
    """A client for the `DebtAuctionHouse` contract, used to interact with debt auctions.

    You can find the source code of the `DebtAuctionHouse` contract here:
    <https://github.com/reflexer-labs/geb/blob/master/src/DebtAuctionHouse.sol>.

    Attributes:
        web3: An instance of `Web` from `web3.py`.
        address: Ethereum address of the `DebtAuctionHouse` contract.

    """

    abi = Contract._load_abi(__name__, 'abi/DebtAuctionHouse.abi')
    bin = Contract._load_bin(__name__, 'abi/DebtAuctionHouse.bin')

    class Bid:
        def __init__(self, id: int, bid_amount: Rad, amount_to_sell: Wad,
                     high_bidder: Address, bid_expiry: int,
                     auction_deadline: int):
            assert (isinstance(id, int))
            assert (isinstance(bid_amount, Rad))
            assert (isinstance(amount_to_sell, Wad))
            assert (isinstance(high_bidder, Address))
            assert (isinstance(bid_expiry, int))
            assert (isinstance(auction_deadline, int))

            self.id = id
            self.bid_amount = bid_amount
            self.amount_to_sell = amount_to_sell
            self.high_bidder = high_bidder
            self.bid_expiry = bid_expiry
            self.auction_deadline = auction_deadline

        def __repr__(self):
            return f"DebtAuctionHouse.Bid({pformat(vars(self))})"

    class StartAuctionLog:
        def __init__(self, log):
            args = log['args']
            self.id = args['id']
            self.amount_to_sell = Wad(args['amountToSell'])
            self.initial_bid = Rad(args['initialBid'])
            self.income_receiver = Address(args['incomeReceiver'])
            self.auction_deadline = int(args['auctionDeadline'])
            self.active_debt_auctions = int(args['activeDebtAuctions'])
            self.block = log['blockNumber']
            self.tx_hash = log['transactionHash'].hex()

        def __repr__(self):
            return f"DebtAuctionHouse.StartAuctionLog({pformat(vars(self))})"

    class DecreaseSoldAmountLog:
        def __init__(self, log):
            args = log['args']
            self.id = int(args['id'])
            self.high_bidder = Address(args['highBidder'])
            self.amount_to_buy = Wad(args['amountToBuy'])
            self.bid = Rad(args['bid'])
            self.bid_expiry = int(args['bidExpiry'])
            self.block = log['blockNumber']
            self.tx_hash = log['transactionHash'].hex()

        def __repr__(self):
            return f"DebtAuctionHouse.DecreaseSoldAmountLog({pformat(vars(self))})"

    class SettleAuctionLog:
        def __init__(self, log):
            args = log['args']
            self.id = int(args['id'])
            self.active_debt_auctions = int(args['id'])
            self.block = log['blockNumber']
            self.tx_hash = log['transactionHash'].hex()

        def __repr__(self):
            return f"DebtAuctionHouse.SettleAuctionLog({pformat(vars(self))})"

    def __init__(self, web3: Web3, address: Address):
        assert isinstance(web3, Web3)
        assert isinstance(address, Address)

        # Set ABIs for event names that are not in AuctionContract
        self.decrease_sold_amount_abi = None
        for member in DebtAuctionHouse.abi:
            if not self.decrease_sold_amount_abi and member.get(
                    'name') == 'DecreaseSoldAmount':
                self.decrease_sold_amount_abi = member

        super(DebtAuctionHouse, self).__init__(web3, address,
                                               DebtAuctionHouse.abi, self.bids)

    def bid_duration(self) -> int:
        """Returns the bid lifetime.

        Returns:
            The bid lifetime (in seconds).
        """
        return int(self._contract.functions.bidDuration().call())

    def bid_decrease(self) -> Wad:
        """Returns the percentage minimum bid decrease.

        Returns:
            The percentage minimum bid decrease.
        """
        return Wad(self._contract.functions.bidDecrease().call())

    def contract_enabled(self) -> bool:
        return self._contract.functions.contractEnabled().call() > 0

    def amount_sold_increase(self) -> Wad:
        """Returns the amount_to_sell increase applied after an auction has been `restartAuction`ed."""

        return Wad(self._contract.functions.amountSoldIncrease().call())

    def bids(self, id: int) -> Bid:
        """Returns the auction details.

        Args:
            id: Auction identifier.

        Returns:
            The auction details.
        """
        assert (isinstance(id, int))

        array = self._contract.functions.bids(id).call()

        return DebtAuctionHouse.Bid(id=id,
                                    bid_amount=Rad(array[0]),
                                    amount_to_sell=Wad(array[1]),
                                    high_bidder=Address(array[2]),
                                    bid_expiry=int(array[3]),
                                    auction_deadline=int(array[4]))

    def start_auction(self, initial_bidder: Address, amount_to_sell: Wad,
                      bid_amount: Wad) -> Transact:
        assert (isinstance(initial_bidder, Address))
        assert (isinstance(amount_to_sell, Wad))
        assert (isinstance(bid_amount, Wad))

        return Transact(
            self, self.web3, self.abi, self.address, self._contract,
            'startAuction',
            [initial_bidder.address, amount_to_sell.value, bid_amount.value])

    def decrease_sold_amount(self, id: int, amount_to_sell: Wad,
                             bid_amount: Rad) -> Transact:
        assert (isinstance(id, int))
        assert (isinstance(amount_to_sell, Wad))
        assert (isinstance(bid_amount, Rad))

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'decreaseSoldAmount',
                        [id, amount_to_sell.value, bid_amount.value])

    def restart_auction(self, id: int) -> Transact:
        """Resurrect an auction which expired without any bids."""
        assert (isinstance(id, int))

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'restartAuction', [id])

    def terminate_auction_prematurely(self, id: int) -> Transact:
        """While `disableContract`d, refund current bid to the bidder"""
        assert (isinstance(id, int))

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'terminateAuctionPrematurely', [id])

    def parse_event(self, event):
        signature = Web3.toHex(event['topics'][0])
        codec = ABICodec(default_registry)
        if signature == "0x9102bd0b66dcb83f469f1122a583dc797657b114141460c59230fc1b41f48229":
            event_data = get_event_data(codec, self.start_auction_abi, event)
            return DebtAuctionHouse.StartAuctionLog(event_data)
        elif signature == "0x8c63feacc784a7f735e454365ba433f17d17293b02c57d98dad113977dbf0f13":
            event_data = get_event_data(codec, self.decrease_sold_amount_abi,
                                        event)
            return DebtAuctionHouse.DecreaseSoldAmountLog(event_data)
        elif signature == "0xef063949eb6ef5abef19139d9c75a558424ffa759302cfe445f8d2d327376fe4":
            event_data = get_event_data(codec, self.settle_auction_abi, event)
            return DebtAuctionHouse.SettleAuctionLog(event_data)

    def __repr__(self):
        return f"DebtAuctionHouse('{self.address}')"
示例#18
0
class PreSettlementSurplusAuctionHouse(AuctionContract):
    """A client for the `PreSettlementSurplusAuctionHouse` contract, used to interact with surplus auctions.

    You can find the source code of the `PreSettlementSurplusAuctionHouse` contract here:
    <https://github.com/reflexer-labs/geb/blob/master/src/SurplusAuctionHouse.sol>.

    Attributes:
        web3: An instance of `Web` from `web3.py`.
        address: Ethereum address of the `PreSettlementSurplusAuctionHouse` contract.

    """

    abi = Contract._load_abi(__name__,
                             'abi/PreSettlementSurplusAuctionHouse.abi')
    bin = Contract._load_bin(__name__,
                             'abi/PreSettlementSurplusAuctionHouse.bin')

    class Bid:
        def __init__(self, id: int, bid_amount: Wad, amount_to_sell: Rad,
                     high_bidder: Address, bid_expiry: int,
                     auction_deadline: int):
            assert (isinstance(id, int))
            assert (isinstance(bid_amount, Wad))  # Gov
            assert (isinstance(amount_to_sell, Rad))  # System coin
            assert (isinstance(high_bidder, Address))
            assert (isinstance(bid_expiry, int))
            assert (isinstance(auction_deadline, int))

            self.id = id
            self.bid_amount = bid_amount
            self.amount_to_sell = amount_to_sell
            self.high_bidder = high_bidder
            self.bid_expiry = bid_expiry
            self.auction_deadline = auction_deadline

        def __repr__(self):
            return f"PreSettlementSurplusAuctionHouse.Bid({pformat(vars(self))})"

    class StartAuctionLog:
        def __init__(self, log):
            args = log['args']
            self.id = int(args['id'])
            self.auctions_started = int(args['auctionsStarted'])
            self.amount_to_sell = Rad(args['amountToSell'])
            self.initial_bid = Wad(args['initialBid'])
            self.auction_deadline = int(args['auctionDeadline'])
            self.block = log['blockNumber']
            self.tx_hash = log['transactionHash'].hex()

        def __repr__(self):
            return f"PreSettlementSurplusAuctionHouse.StartAuctionLog({pformat(vars(self))})"

    class IncreaseBidSizeLog:
        def __init__(self, log):
            args = log['args']
            self.id = int(args['id'])
            self.high_bidder = Address(args['highBidder'])
            self.amount_to_buy = Rad(args['amountToBuy'])
            self.bid = Wad(args['bid'])
            self.bid_expiry = int(args['bidExpiry'])
            self.block = log['blockNumber']
            self.tx_hash = log['transactionHash'].hex()

        def __repr__(self):
            return f"PreSettlementSurplusAuctionHouse.IncreaseBidSizeLog({pformat(vars(self))})"

    class SettleAuctionLog:
        def __init__(self, log):
            args = log['args']
            self.id = args['id']
            self.block = log['blockNumber']
            self.tx_hash = log['transactionHash'].hex()

        def __repr__(self):
            return f"PreSettlementSurplusAuctionHouse.SettleAuctionLog({pformat(vars(self))})"

    def __init__(self, web3: Web3, address: Address):
        assert isinstance(web3, Web3)
        assert isinstance(address, Address)

        # Set ABIs for event names that are not in AuctionContract
        self.increase_bid_size_abi = None
        for member in PreSettlementSurplusAuctionHouse.abi:
            if not self.increase_bid_size_abi and member.get(
                    'name') == 'IncreaseBidSize':
                self.increase_bid_size_abi = member

        super(PreSettlementSurplusAuctionHouse,
              self).__init__(web3, address,
                             PreSettlementSurplusAuctionHouse.abi, self.bids)

    def bid_duration(self) -> int:
        """Returns the bid lifetime.

        Returns:
            The bid lifetime (in seconds).
        """
        return int(self._contract.functions.bidDuration().call())

    def bid_increase(self) -> Wad:
        """Returns the percentage minimum bid increase.

        Returns:
            The percentage minimum bid increase.
        """
        return Wad(self._contract.functions.bidIncrease().call())

    def contract_enabled(self) -> bool:
        return self._contract.functions.contractEnabled().call() > 0

    def protocol_token(self) -> Address:
        return Address(self._contract.functions.protocolToken().call())

    def bids(self, id: int) -> Bid:
        """Returns the auction details.

        Args:
            id: Auction identifier.

        Returns:
            The auction details.
        """
        assert (isinstance(id, int))

        array = self._contract.functions.bids(id).call()

        return PreSettlementSurplusAuctionHouse.Bid(
            id=id,
            bid_amount=Wad(array[0]),
            amount_to_sell=Rad(array[1]),
            high_bidder=Address(array[2]),
            bid_expiry=int(array[3]),
            auction_deadline=int(array[4]))

    def start_auction(self, amount_to_sell: Rad, bid_amount: Wad) -> Transact:
        assert (isinstance(amount_to_sell, Rad))
        assert (isinstance(bid_amount, Wad))

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'startAuction',
                        [amount_to_sell.value, bid_amount.value])

    def increase_bid_size(self, id: int, amount_to_sell: Rad,
                          bid_amount: Wad) -> Transact:
        assert (isinstance(id, int))
        assert (isinstance(amount_to_sell, Rad))
        assert (isinstance(bid_amount, Wad))

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'increaseBidSize',
                        [id, amount_to_sell.value, bid_amount.value])

    def restart_auction(self, id: int) -> Transact:
        """Resurrect an auction which expired without any bids."""
        assert (isinstance(id, int))

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'restartAuction', [id])

    def terminate_auction_prematurely(self, id: int) -> Transact:
        """While `disableContract`d, refund current bid to the bidder"""
        assert (isinstance(id, int))

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'terminateAuctionPrematurely', [id])

    def parse_event(self, event):
        signature = Web3.toHex(event['topics'][0])
        codec = ABICodec(default_registry)
        if signature == "0xa4863af70e77aecfe2769e0569806782ba7c6f86fc9a307290a3816fb8a563e5":
            event_data = get_event_data(codec, self.start_auction_abi, event)
            return PreSettlementSurplusAuctionHouse.StartAuctionLog(event_data)
        elif signature == "0xd87c815d5a67c2e130ad04b714d87a6fb69d5a6df0dbb0f1639cd9fe292201f9":
            event_data = get_event_data(codec, self.increase_bid_size_abi,
                                        event)
            return PreSettlementSurplusAuctionHouse.IncreaseBidSizeLog(
                event_data)
        elif signature == "0x03af424b0e12d91ea31fe7f2c199fc02c9ede38f9aa1bdc019a8087b41445f7a":
            event_data = get_event_data(codec, self.settle_auction_abi, event)
            return PreSettlementSurplusAuctionHouse.SettleAuctionLog(
                event_data)

    def __repr__(self):
        return f"PreSettlementSurplusAuctionHouse('{self.address}')"
示例#19
0
class FixedDiscountCollateralAuctionHouse(AuctionContract):
    """A client for the `FixedDiscountCollateralAuctionHouse` contract, used to interact with collateral auctions.

    You can find the source code of the `FixedDiscountCollateralAuctionHouse` contract here:
    <https://github.com/reflexer-labs/geb/blob/master/src/CollateralAuctionHouse.sol>.

    Attributes:
        web3: An instance of `Web` from `web3.py`.
        address: Ethereum address of the `FixedDiscountCollateralAuctionHouse` contract.

    Event signatures:
    """

    abi = Contract._load_abi(__name__,
                             'abi/FixedDiscountCollateralAuctionHouse.abi')
    bin = Contract._load_bin(__name__,
                             'abi/FixedDiscountCollateralAuctionHouse.bin')

    class Bid:
        def __init__(self, id: int, raised_amount: Rad, sold_amount: Wad,
                     amount_to_sell: Wad, amount_to_raise: Rad,
                     auction_deadline: int,
                     forgone_collateral_receiver: Address,
                     auction_income_recipient: Address):
            assert (isinstance(id, int))
            assert (isinstance(raised_amount, Rad))
            assert (isinstance(sold_amount, Wad))
            assert (isinstance(amount_to_sell, Wad))
            assert (isinstance(amount_to_raise, Rad))
            assert (isinstance(auction_deadline, int))
            assert (isinstance(forgone_collateral_receiver, Address))
            assert (isinstance(auction_income_recipient, Address))

            self.id = id
            self.raised_amount = raised_amount
            self.sold_amount = sold_amount
            self.amount_to_sell = amount_to_sell
            self.amount_to_raise = amount_to_raise
            self.auction_deadline = auction_deadline
            self.forgone_collateral_receiver = forgone_collateral_receiver
            self.auction_income_recipient = auction_income_recipient

        def __repr__(self):
            return f"FixedDiscountCollateralAuctionHouse.Bid({pformat(vars(self))})"

    class StartAuctionLog:
        def __init__(self, log):
            args = log['args']
            self.id = args['id']
            self.auctions_started = int(args['auctionsStarted'])
            self.amount_to_sell = Wad(args['amountToSell'])
            self.initial_bid = Rad(args['initialBid'])
            self.amount_to_raise = Rad(args['amountToRaise'])
            self.forgone_collateral_receiver = Address(
                args['forgoneCollateralReceiver'])
            self.auction_income_recipient = Address(
                args['auctionIncomeRecipient'])
            self.auction_deadline = int(args['auctionDeadline'])
            self.block = log['blockNumber']
            self.tx_hash = log['transactionHash'].hex()

        def __repr__(self):
            return f"FixedDiscountCollateralAuctionHouse.StartAuctionLog({pformat(vars(self))})"

    class BuyCollateralLog:
        def __init__(self, log):
            args = log['args']
            self.id = args['id']
            self.wad = Wad(args['wad'])
            self.bought_collateral = Wad(args['boughtCollateral'])
            self.block = log['blockNumber']
            self.tx_hash = log['transactionHash'].hex()
            self.raw = log

        def __repr__(self):
            return f"FixedDiscountCollateralAuctionHouse.BuyCollateralLog({pformat(vars(self))})"

    class SettleAuctionLog:
        def __init__(self, log):
            args = log['args']
            self.id = args['id']
            self.leftover_collateral = Wad(args['leftoverCollateral'])
            self.block = log['blockNumber']
            self.tx_hash = log['transactionHash'].hex()
            self.raw = log

        def __repr__(self):
            return f"FixedDiscountCollateralAuctionHouse.SettleAuctionLog({pformat(vars(self))})"

    def __init__(self, web3: Web3, address: Address):
        assert isinstance(web3, Web3)
        assert isinstance(address, Address)

        # Set ABIs for event names that are not in AuctionContract
        self.buy_collateral_abi = None
        for member in FixedDiscountCollateralAuctionHouse.abi:
            if not self.buy_collateral_abi and member.get(
                    'name') == 'BuyCollateral':
                self.buy_collateral_abi = member

        super(FixedDiscountCollateralAuctionHouse,
              self).__init__(web3, address,
                             FixedDiscountCollateralAuctionHouse.abi,
                             self.bids)

        assert self._contract.functions.AUCTION_TYPE().call() == toBytes(
            'FIXED_DISCOUNT')

    def active_auctions(self) -> list:
        active_auctions = []
        auction_count = self.auctions_started()
        for index in range(1, auction_count + 1):
            bid = self._bids(index)
            if bid.amount_to_sell > Wad(0) and bid.amount_to_raise > Rad(0):
                active_auctions.append(bid)

        return active_auctions

    def get_collateral_median_price(self) -> Ray:
        """Returns the market price from system coin oracle.
       

        Returns:
            System coin market price
        """
        return Ray(self._contract.functions.getCollateralMedianPrice().call())

    def get_final_token_prices(self) -> (int, int):
        return self._contract.functions.getFinalTokenPrices(
            self._contract.functions.lastReadRedemptionPrice().call()).call()

    def minimum_bid(self) -> Wad:
        """Returns the minimum bid.

        Returns:
            The minimum
        """
        return Wad(self._contract.functions.minimumBid().call())

    def discount(self) -> Wad:
        """Returns the auction discount 

        Returns:
            The auction discount
        """
        return Wad(self._contract.functions.discount().call())

    def last_read_redemption_price(self) -> Wad:
        """Returns the last read redemption price

        Returns:
            The minimum
        """
        return Wad(self._contract.functions.lastReadRedemptionPrice().call())

    def bids(self, id: int) -> Bid:
        """Returns the auction details.

        Args:
            id: Auction identifier.

        Returns:
            The auction details.
        """
        assert (isinstance(id, int))

        array = self._contract.functions.bids(id).call()

        return FixedDiscountCollateralAuctionHouse.Bid(
            id=id,
            raised_amount=Rad(array[0]),
            sold_amount=Wad(array[1]),
            amount_to_sell=Wad(array[2]),
            amount_to_raise=Rad(array[3]),
            auction_deadline=int(array[4]),
            forgone_collateral_receiver=Address(array[5]),
            auction_income_recipient=Address(array[6]))

    def start_auction(self, forgone_collateral_receiver: Address,
                      auction_income_recipient: Address, amount_to_raise: Rad,
                      amount_to_sell: Wad, bid_amount: Rad) -> Transact:
        assert (isinstance(forgoneCollateralReceiver, Address))
        assert (isinstance(auction_income_recipient, Address))
        assert (isinstance(amount_to_raise, Rad))
        assert (isinstance(amount_to_sell, Wad))
        assert (isinstance(bid_amount, Rad))

        return Transact(
            self, self.web3, self.abi, self.address, self._contract,
            'startAuction', [
                forgone_collateral_receiver.address,
                auction_income_recipient.address, amount_to_raise.value,
                amount_to_sell.value, bid_amount.value
            ])

    def buy_collateral(self, id: int, wad: Wad) -> Transact:
        assert (isinstance(id, int))
        assert (isinstance(wad, Wad))

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'buyCollateral', [id, wad.value])

    def get_collateral_bought(self, id: int, wad: Wad) -> Transact:
        assert (isinstance(id, int))
        assert (isinstance(wad, Wad))

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'getCollateralBought', [id, wad.value])

    def get_approximate_collateral_bought(self, id: int,
                                          wad: Wad) -> Tuple[Wad, Wad]:
        assert (isinstance(id, int))
        assert (isinstance(wad, Wad))

        collateral, bid = self._contract.functions.getApproximateCollateralBought(
            id, wad.value).call()

        return Wad(collateral), Wad(bid)

    def parse_event(self, event):
        signature = Web3.toHex(event['topics'][0])
        codec = ABICodec(default_registry)
        if signature == "0xdf7b5cd0ee6547c7389d2ac00ee0c1cd3439542399d6c8c520cc69c7409c0990":
            event_data = get_event_data(codec, self.start_auction_abi, event)
            return FixedDiscountCollateralAuctionHouse.StartAuctionLog(
                event_data)
        elif signature == "0xa4a1133e32fac37643a1fe1db4631daadb462c8662ae16004e67f0b8bb608383":
            event_data = get_event_data(codec, self.buy_collateral_abi, event)
            return FixedDiscountCollateralAuctionHouse.BuyCollateralLog(
                event_data)
        elif signature == "0xef063949eb6ef5abef19139d9c75a558424ffa759302cfe445f8d2d327376fe4":
            event_data = get_event_data(codec, self.settle_auction_abi, event)
            return FixedDiscountCollateralAuctionHouse.SettleAuctionLog(
                event_data)

    def __repr__(self):
        return f"FixedDiscountCollateralAuctionHouse('{self.address}')"
示例#20
0
class ZrxExchangeV2(Contract):
    """A client for the 0x V2 exchange contract.

    You can find the `0x V2` exchange contract here:
    <https://etherscan.io/address/0x4f833a24e1f95d70f028921e27040ca56e09ab0b>.

    Attributes:
        web3: An instance of `Web` from `web3.py`.
        address: Ethereum address of the _0x_ `Exchange` contract.
    """

    abi = Contract._load_abi(__name__, 'abi/ExchangeV2.abi')
    bin = Contract._load_bin(__name__, 'abi/ExchangeV2.bin')

    _ZERO_ADDRESS = Address("0x0000000000000000000000000000000000000000")

    ORDER_INFO_TYPE = '(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)'

    @staticmethod
    def deploy(web3: Web3, zrx_asset: str):
        """Deploy a new instance of the 0x `Exchange` contract.

        Args:
            web3: An instance of `Web` from `web3.py`.
            zrx_token: The address of the ZRX token this exchange will use.

        Returns:
            A `ZrxExchange` class instance.
        """
        return ZrxExchangeV2(web3=web3,
                             address=Contract._deploy(web3, ZrxExchangeV2.abi,
                                                      ZrxExchangeV2.bin, []))

    def __init__(self, web3: Web3, address: Address):
        assert (isinstance(web3, Web3))
        assert (isinstance(address, Address))

        self.web3 = web3
        self.address = address
        self._contract = self._get_contract(web3, self.abi, address)

    def zrx_asset(self) -> str:
        """Get the asset data of the ZRX token contract associated with this `ExchangeV2` contract.

        Returns:
            The asset data of the `ZRX` token.
        """
        return str(
            bytes_to_hexstring(
                self._contract.functions.ZRX_ASSET_DATA().call()))

    def zrx_token(self) -> Address:
        """Get the address of the ZRX token contract associated with this `ExchangeV2` contract.

        Returns:
            The address of the `ZRX` token.
        """
        return Address("0x" + self.zrx_asset()[-40:])

    def asset_transfer_proxy(self, proxy_id: str) -> Address:
        """Get the address of the `ERC20Proxy` contract associated with this `Exchange` contract.

        Returns:
            The address of the `ERC20Proxy` token.
        """
        assert (isinstance(proxy_id, str))

        return Address(
            self._contract.functions.getAssetProxy(
                hexstring_to_bytes(proxy_id)).call())

    def approve(self, tokens: List[ERC20Token], approval_function):
        """Approve the 0x ERC20Proxy contract to fully access balances of specified tokens.

        In case of 0x V2, it's the ERC20Proxy contract that actually gets the approvals,
        not the 0x Exchange contract itself. In addition to the tokens specified as the `tokens`
        parameter, the ZRX token always gets approved as well as without it the 0x Exchange
        contract wouldn't be able to charge maker and taker fees.

        For available approval functions (i.e. approval modes) see `directly` and `via_tx_manager`
        in `pyflex.approval`.

        Args:
            tokens: List of :py:class:`pyflex.token.ERC20Token` class instances.
            approval_function: Approval function (i.e. approval mode).
        """
        assert (isinstance(tokens, list))
        assert (callable(approval_function))

        for token in tokens:  # TODO  + [ERC20Token(web3=self.web3, address=self.zrx_token())]
            approval_function(token, self.asset_transfer_proxy(ERC20Asset.ID),
                              '0x ERC20Proxy contract')

    def past_fill(self,
                  number_of_past_blocks: int,
                  event_filter: dict = None) -> List[LogFill]:
        """Synchronously retrieve past LogFill events.

        `LogFill` events are emitted by the 0x contract every time someone fills an order.

        Args:
            number_of_past_blocks: Number of past Ethereum blocks to retrieve the events from.
            event_filter: Filter which will be applied to returned events.

        Returns:
            List of past `LogFill` events represented as :py:class:`pyflex.zrx.LogFill` class.
        """
        assert (isinstance(number_of_past_blocks, int))
        assert (isinstance(event_filter, dict) or (event_filter is None))

        return self._past_events(self._contract, 'Fill', LogFill,
                                 number_of_past_blocks, event_filter)

    def past_cancel(self,
                    number_of_past_blocks: int,
                    event_filter: dict = None) -> List[LogCancel]:
        """Synchronously retrieve past LogCancel events.

        `LogCancel` events are emitted by the 0x contract every time someone cancels an order.

        Args:
            number_of_past_blocks: Number of past Ethereum blocks to retrieve the events from.
            event_filter: Filter which will be applied to returned events.

        Returns:
            List of past `LogCancel` events represented as :py:class:`pyflex.zrx.LogCancel` class.
        """
        assert (isinstance(number_of_past_blocks, int))
        assert (isinstance(event_filter, dict) or (event_filter is None))

        return self._past_events(self._contract, 'Cancel', LogCancel,
                                 number_of_past_blocks, event_filter)

    def create_order(self, pay_asset: Asset, pay_amount: Wad, buy_asset: Asset,
                     buy_amount: Wad, expiration: int) -> Order:
        """Creates a new order.

        The `maker_fee`, `taker_fee` and `fee_recipient` fields are by default set to zero.
        Before signing the order and submitting it to the relayer, they may need to be
        populated using the `calculate_fees()` method of the `ZrxRelayerApi` class.

        Args:
            pay_asset: The asset you want to put on sale.
            pay_amount: Amount of the `pay_asset` token you want to put on sale.
            buy_asset: The asset you want to be paid with.
            buy_amount: Amount of the `buy_asset` you want to receive.
            expiration: Unix timestamp (in seconds) when the order will expire.

        Returns:
            New order as an instance of the :py:class:`pyflex.zrx.Order` class.
        """
        assert (isinstance(pay_asset, Asset))
        assert (isinstance(pay_amount, Wad))
        assert (isinstance(buy_asset, Asset))
        assert (isinstance(buy_amount, Wad))
        assert (isinstance(expiration, int))

        return Order(exchange=self,
                     sender=self._ZERO_ADDRESS,
                     maker=Address(self.web3.eth.defaultAccount),
                     taker=self._ZERO_ADDRESS,
                     maker_fee=Wad(0),
                     taker_fee=Wad(0),
                     pay_asset=pay_asset,
                     pay_amount=pay_amount,
                     buy_asset=buy_asset,
                     buy_amount=buy_amount,
                     salt=self.generate_salt(),
                     fee_recipient=self._ZERO_ADDRESS,
                     expiration=expiration,
                     exchange_contract_address=self.address,
                     signature=None)

    def _get_order_info(self, order):
        assert (isinstance(order, Order))

        method_signature = self.web3.keccak(
            text=f"getOrderInfo({self.ORDER_INFO_TYPE})")[0:4]
        method_parameters = encode_single(f"({self.ORDER_INFO_TYPE})",
                                          [self._order_tuple(order)])

        request = bytes_to_hexstring(method_signature + method_parameters)
        response = self.web3.eth.call({
            'to': self.address.address,
            'data': request
        })
        response_decoded = decode_single("((uint8,bytes32,uint256))", response)

        return response_decoded

    def get_order_hash(self, order: Order) -> str:
        """Calculates hash of an order.

        Args:
            order: Order you want to calculate the hash of.

        Returns:
            Order hash as a hex string starting with `0x`.
        """
        assert (isinstance(order, Order))

        # the hash depends on the exchange contract address as well
        assert (order.exchange_contract_address == self.address)

        return bytes_to_hexstring(self._get_order_info(order)[0][1])

    def get_unavailable_buy_amount(self, order: Order) -> Wad:
        """Return the order amount which was either taken or cancelled.

        Args:
            order: Order you want to get the unavailable amount of.

        Returns:
            The unavailable amount of the order (i.e. the amount which was either taken or cancelled),
            expressed in terms of the `buy_token` token.
        """
        assert (isinstance(order, Order))

        order_info = self._get_order_info(order)[0]

        if order_info[0] in [
                0,  # INVALID,                     // Default value
                1,  # INVALID_MAKER_ASSET_AMOUNT,  // Order does not have a valid maker asset amount
                2,  # INVALID_TAKER_ASSET_AMOUNT,  // Order does not have a valid taker asset amount
                4,  # EXPIRED,                     // Order has already expired
                5,  # FULLY_FILLED,                // Order is fully filled
                6
        ]:  # CANCELLED                    // Order has been cancelled
            return order.buy_amount

        else:
            return Wad(order_info[2])

    def sign_order(self, order: Order) -> Order:
        """Signs an order so it can be submitted to the relayer.

        Order will be signed by the `web3.eth.defaultAccount` account.

        Args:
            order: Order you want to sign.

        Returns:
            Signed order. Copy of the order passed as a parameter with the `signature` field filled with signature.
        """
        assert (isinstance(order, Order))

        signature = eth_sign(hexstring_to_bytes(self.get_order_hash(order)),
                             self.web3)
        v, r, s = to_vrs(signature)

        signed_order = copy.copy(order)
        signed_order.signature = bytes_to_hexstring(bytes([v])) + \
                                 bytes_to_hexstring(r)[2:] + \
                                 bytes_to_hexstring(s)[2:] + \
                                 "03"  # EthSign
        return signed_order

    def fill_order(self, order: Order, fill_buy_amount: Wad) -> Transact:
        """Fills an order.

        Args:
            order: The order to be filled.
            fill_buy_amount: The amount (in terms of `buy_token` of the original order) to be filled.

        Returns:
            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(order, Order))
        assert (isinstance(fill_buy_amount, Wad))

        method_signature = self.web3.keccak(
            text=f"fillOrder({self.ORDER_INFO_TYPE},uint256,bytes)")[0:4]
        method_parameters = encode_single(
            f"({self.ORDER_INFO_TYPE},uint256,bytes)", [
                self._order_tuple(order), fill_buy_amount.value,
                hexstring_to_bytes(order.signature)
            ])

        request = bytes_to_hexstring(method_signature + method_parameters)

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, None, [request])

    def cancel_order(self, order: Order) -> Transact:
        """Cancels an order.

        Args:
            order: Order you want to cancel.

        Returns:
            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(order, Order))

        method_signature = self.web3.keccak(
            text=f"cancelOrder({self.ORDER_INFO_TYPE})")[0:4]
        method_parameters = encode_single(f"({self.ORDER_INFO_TYPE})",
                                          [self._order_tuple(order)])

        request = bytes_to_hexstring(method_signature + method_parameters)

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, None, [request])

    @staticmethod
    def _order_tuple(order):
        return (order.maker.address, order.taker.address,
                order.fee_recipient.address, order.sender.address,
                order.pay_amount.value, order.buy_amount.value,
                order.maker_fee.value, order.taker_fee.value, order.expiration,
                order.salt, hexstring_to_bytes(order.pay_asset.serialize()),
                hexstring_to_bytes(order.buy_asset.serialize()))

    @staticmethod
    def generate_salt() -> int:
        return int(time.time() * 1000)

    def __repr__(self):
        return f"ZrxExchangeV2('{self.address}')"
示例#21
0
class SafeManager(Contract):
    """A client for the `GebSafeManger` contract, which is a wrapper around the safe system, for easier use.

    Ref. <https://github.com/reflexer-labs/geb-safe-manager/blob/master/src/GebSafeManager.sol>
    """

    abi = Contract._load_abi(__name__, 'abi/GebSafeManager.abi')
    bin = Contract._load_bin(__name__, 'abi/GebSafeManager.bin')

    def __init__(self, web3: Web3, address: Address):
        assert isinstance(web3, Web3)
        assert isinstance(address, Address)

        self.web3 = web3
        self.address = address
        self._contract = self._get_contract(web3, self.abi, address)
        self.safe_engine = SAFEEngine(
            self.web3, Address(self._contract.functions.safeEngine().call()))

    def open_safe(self, collateral_type: CollateralType,
                  address: Address) -> Transact:
        assert isinstance(collateral_type, CollateralType)
        assert isinstance(address, Address)

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'openSAFE',
                        [collateral_type.toBytes(), address.address])

    def safe(self, safeid: int) -> SAFE:
        '''Returns SAFE for respective SAFE ID'''
        assert isinstance(safeid, int)

        safe_address = Address(self._contract.functions.safes(safeid).call())
        collateral_type = self.collateral_type(safeid)
        safe = self.safe_engine.safe(collateral_type, Address(safe_address))

        return safe

    def owns_safe(self, safeid: int) -> Address:
        '''Returns owner Address of respective SAFE ID'''
        assert isinstance(safeid, int)

        owner = Address(self._contract.functions.ownsSAFE(safeid).call())
        return owner

    def collateral_type(self, safeid: int) -> CollateralType:
        '''Returns CollateralType for respective SAFE ID'''
        assert isinstance(safeid, int)

        collateral_type = CollateralType.fromBytes(
            self._contract.functions.collateralTypes(safeid).call())
        return collateral_type

    def first_safe_id(self, address: Address) -> int:
        '''Returns first SAFE Id created by owner address'''
        assert isinstance(address, Address)

        safeid = int(
            self._contract.functions.firstSAFEID(address.address).call())
        return safeid

    def last_safe_id(self, address: Address) -> int:
        '''Returns last SAFE Id created by owner address'''
        assert isinstance(address, Address)

        safeid = self._contract.functions.lastSAFEID(address.address).call()
        return int(safeid)

    def safe_count(self, address: Address) -> int:
        '''Returns number of SAFE's created using the Geb-Safe-Manager contract specifically'''
        assert isinstance(address, Address)

        count = int(self._contract.functions.safeCount(address.address).call())
        return count

    def __repr__(self):
        return f"SafeManager('{self.address}')"
示例#22
0
class DSEthToken(ERC20Token):
    """A client for the `DSEthToken` contract.

    `DSEthToken`, also known as ETH Wrapper or W-ETH, is a contract into which you can deposit
    raw ETH and then deal with it like with any other ERC20 token. In addition to the `deposit()`
    and `withdraw()` methods, it implements the standard ERC20 token API.

    You can find the source code of the `DSEthToken` contract here:
    <https://github.com/dapphub/ds-eth-token>.

    Attributes:
        web3: An instance of `Web` from `web3.py`.
        address: Ethereum address of the `DSEthToken` contract.
    """

    abi = Contract._load_abi(__name__, 'abi/DSEthToken.abi')
    bin = Contract._load_bin(__name__, 'abi/DSEthToken.bin')

    @staticmethod
    def deploy(web3: Web3):
        """Deploy a new instance of the `DSEthToken` contract.

        Args:
            web3: An instance of `Web` from `web3.py`.

        Returns:
            A `DSEthToken` class instance.
        """
        return DSEthToken(web3=web3,
                          address=Contract._deploy(web3, DSEthToken.abi,
                                                   DSEthToken.bin, []))

    def __init__(self, web3, address):
        super().__init__(web3, address)
        self._contract = self._get_contract(web3, self.abi, address)

    def deposit(self, amount: Wad) -> Transact:
        """Deposits `amount` of raw ETH to `DSEthToken`.

        Args:
            amount: Amount of raw ETH to be deposited to `DSEthToken`.

        Returns:
            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(amount, Wad))
        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'deposit', [], {'value': amount.value})

    def withdraw(self, amount: Wad) -> Transact:
        """Withdraws `amount` of raw ETH from `DSEthToken`.

        The withdrawn ETH will get transferred to the calling account.

        Args:
            amount: Amount of raw ETH to be withdrawn from `DSEthToken`.

        Returns:
            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(amount, Wad))
        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'withdraw', [amount.value])

    def __repr__(self):
        return f"DSEthToken('{self.address}')"
示例#23
0
class DSToken(ERC20Token):
    """A client for the `DSToken` contract.

    You can find the source code of the `DSToken` contract here:
    <https://github.com/dapphub/ds-token>.

    Attributes:
        web3: An instance of `Web` from `web3.py`.
        address: Ethereum address of the `DSToken` contract.
    """

    abi = Contract._load_abi(__name__, 'abi/DSToken.abi')
    bin = Contract._load_bin(__name__, 'abi/DSToken.bin')

    @staticmethod
    def deploy(web3: Web3, name: str, symbol: str):
        """Deploy a new instance of the `DSToken` contract.

        Args:
            web3: An instance of `Web` from `web3.py`.
            name: Name of the new token.
            symbol: Symbol of the new token.

        Returns:
            A `DSToken` class instance.
        """
        assert (isinstance(name, str))
        assert (isinstance(symbol, str))
        return DSToken(web3=web3,
                       address=Contract._deploy(
                           web3, DSToken.abi, DSToken.bin,
                           [bytes(name, "utf-8"),
                            bytes(symbol, "utf-8")]))

    def owner(self) -> Address:
        """Return the current `authority` of a `DSAuth`-ed contract.

        Returns:
            The address of the current `authority`.
        """
        return Address(self._contract.functions.owner().call())

    def authority(self) -> Address:
        """Return the current `authority` of a `DSAuth`-ed contract.

        Returns:
            The address of the current `authority`.
        """
        return Address(self._contract.functions.authority().call())

    def set_authority(self, address: Address) -> Transact:
        """Set the `authority` of a `DSAuth`-ed contract.

        Args:
            address: The address of the new `authority`.

        Returns:
            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(address, Address))
        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'setAuthority', [address.address])

    def mint(self, amount: Wad) -> Transact:
        """Increase the total supply of the token.

        Args:
            amount: The amount to increase the total supply by.

        Returns:
            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(amount, Wad))
        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'mint(uint256)', [amount.value])

    def mint_to(self, address: Address, amount: Wad) -> Transact:
        """Increase the total supply of the token.

        Args:
            address: The address to credit the new tokens to.
            amount: The amount to increase the total supply by.

        Returns:
            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(amount, Wad))
        assert (isinstance(address, Address))
        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'mint(address,uint256)',
                        [address.address, amount.value])

    def burn(self, amount: Wad) -> Transact:
        """Decrease the total supply of the token.

        Args:
            amount: The amount to decrease the total supply by.

        Returns:
            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(amount, Wad))
        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'burn(uint256)', [amount.value])

    def burn_from(self, address: Address, amount: Wad) -> Transact:
        """Decrease the total supply of the token.

        Args:
            address: The address to burn the tokens from.
            amount: The amount to decrease the total supply by.

        Returns:
            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(amount, Wad))
        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'burn(address,uint256)',
                        [address.address, amount.value])

    def __repr__(self):
        return f"DSToken('{self.address}')"
示例#24
0
class DSProxyFactory(Contract):
    """A client for the `DSProxyFactory` contract.

    Ref. <https://github.com/dapphub/ds-proxy/blob/master/src/proxy.sol#L90>
    """

    abi = Contract._load_abi(__name__, 'abi/DSProxyFactory.abi')
    bin = Contract._load_bin(__name__, 'abi/DSProxyFactory.bin')

    def __init__(self, web3: Web3, address: Address):
        assert (isinstance(web3, Web3))
        assert (isinstance(address, Address))

        self.web3 = web3
        self.address = address
        self._contract = self._get_contract(web3, self.abi, address)

    @classmethod
    def deploy(cls, web3: Web3):
        return cls(web3=web3,
                   address=Contract._deploy(web3, cls.abi, cls.bin, []))

    def build(self) -> Transact:
        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'build()', [])

    def build_for(self, address: Address) -> Transact:
        assert (isinstance(address, Address))

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'build(address)', [address.address])

    def cache(self) -> Address:
        return Address(self._contract.functions.cache().call())

    def is_proxy(self, address: Address) -> bool:
        assert (isinstance(address, Address))

        return self._contract.functions.isProxy(address.address).call()

    def past_build(self,
                   number_of_past_blocks: int,
                   event_filter: dict = None) -> List[LogCreated]:
        """Synchronously retrieve past LogCreated events.

        `LogCreated` events are emitted every time someone build a proxy from the factory.

        Args:
            number_of_past_blocks: Number of past Ethereum blocks to retrieve the events from.
            event_filter: Filter which will be applied to returned events.

        Returns:
            List of past `LogCreated` events represented as :py:class:`pyflex.proxy.LogCreated` class.
        """
        assert isinstance(number_of_past_blocks, int)
        assert isinstance(event_filter, dict) or (event_filter is None)

        return self._past_events(self._contract, 'Created', LogCreated,
                                 number_of_past_blocks, event_filter)

    @classmethod
    def log_created(cls, receipt: Receipt) -> List[LogCreated]:
        assert isinstance(receipt, Receipt)

        events = []
        for log in receipt.raw_receipt.logs:
            try:
                event = LogCreated.from_event(dict(log))
                events.append(event)
            except:
                pass
        return events

    def __repr__(self):
        return f"DSProxyFactory('{self.address}')"
示例#25
0
class OSM(Contract):
    """A client for the `OSM` contract.

    You can find the source code of the `OSM` contract here:
    <https://github.com/reflexer-labs/geb-fsm/blob/master/src/OSM.sol>.

    Attributes:
        web3: An instance of `Web` from `web3.py`.
        address: Ethereum address of the `OSM` contract.
    """

    abi = Contract._load_abi(__name__, 'abi/OSM.abi')
    bin = Contract._load_bin(__name__, 'abi/OSM.bin')

    def __init__(self, web3: Web3, address: Address):
        assert (isinstance(web3, Web3))
        assert (isinstance(address, Address))

        self.web3 = web3
        self.address = address
        self._contract = self._get_contract(web3, self.abi, address)

    def has_value(self) -> bool:
        """Checks whether this instance contains a value.

        Returns:
            `True` if this instance contains a value, which can be read. `False` otherwise.
        """
        return self._contract.functions.getResultWithValidity().call()[1]

    def last_update_time(self) -> int:
        """ Returns last update time in secs

        Returns:
            Epoch time in seconds
        """
        return self._contract.functions.lastUpdateTime().call()

    def update_delay(self) -> int:
        """ Returns number of seconds that must pass between updates

        Returns:
            Number of seconds
        """
        return self._contract.functions.updateDelay().call()

    def passed_delay(self) -> bool:
        """ Check if update delay has passed

        Returns:
            `True` if time since last update is greater than required delay. `False` otherwise.
        """
        return self._contract.functions.lastUpdateTime().call()

    def read(self) -> int:
        """Reads the current value from this instance

        If this instance does not contain a value, throws an exception.

        Returns:
            An integer with the current value of this instance.
        """
        return self._contract.functions.read().call()

    def update_result(self) -> Transact:
        """Populates this instance with a new value.

            A :py:class:`pyflex.Transact` instance, which can be used to trigger the transaction.
        """

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'updateResult', [])

    def __repr__(self):
        return f"OSM('{self.address}')"