Ejemplo n.º 1
0
    def deposit_ether(self, leverjobj: LeverjAPI, amount: Wad, gluon_block_number):
        assert(isinstance(leverjobj, LeverjAPI))
        assert(isinstance(amount, Wad))

        custodian_account = self.address
        app_id = leverjobj.get_spot_exchange_id()
        if gluon_block_number is None:
            gluon_block_number = leverjobj._http_authenticated("GET", "/api/v1", f"/plasma/{app_id}", None)['number'] + 2
            receipt = Transact(self, self.web3, self.abi, self.address, self._contract, "depositEther",[app_id], {'value': int(amount.value)}).transact(from_address=self.middle_account)
            return (gluon_block_number, receipt)
        else:
            current_gluon_block = leverjobj._http_authenticated("GET", "/api/v1", f"/plasma/{app_id}", None)['number']
            if (current_gluon_block < gluon_block_number):
                return (gluon_block_number, None)
            else:
                return (None, None)
Ejemplo n.º 2
0
    def cancel_order(self, order: Order) -> Transact:
        """Cancels an order.

        Args:
            order: Order you want to cancel.

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

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'cancelOrder', [
                            self._order_addresses(order),
                            self._order_values(order), order.buy_amount.value
                        ])
Ejemplo n.º 3
0
    def kill(self, order_id: int) -> Transact:
        """Cancels an existing order.

        Orders can be cancelled only by their owners. In addition to that, in case of expiring markets,
        after the market has expired all orders can be cancelled by anyone.

        Args:
            order_id: Id of the order you want to cancel.

        Returns:
            A :py:class:`pymaker.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(order_id, int))

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'kill', [int_to_bytes32(order_id)])
Ejemplo n.º 4
0
    def withdraw_token(self, token: Address, amount: Wad) -> Transact:
        """Withdraws `amount` of ERC20 token `token` from IDEX.

        Tokens will get transferred to the calling account.

        Args:
            token: Address of the ERC20 token to be withdrawn.
            amount: Amount of token `token` to be withdrawn from IDEX.

        Returns:
            A :py:class:`pymaker.Transact` instance, which can be used to trigger the transaction.
        """
        assert(isinstance(token, Address))
        assert(isinstance(amount, Wad))
        return Transact(self, self.web3, self.abi, self.address, self._contract, 'withdraw',
                        [token.address, amount.value])
Ejemplo n.º 5
0
    def bump(self, order_id: int) -> Transact:
        """Bumps an order.

        Bumping an order generates a `LogBump` event, which can make the order reappear
        in some front-ends relying on the events.

        Args:
            order_id: Id of the order you want to bump.

        Returns:
            A :py:class:`pymaker.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(order_id, int))

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'bump', [int_to_bytes32(order_id)])
Ejemplo n.º 6
0
    def flux(self, ilk: Ilk, src: Address, dst: Address, wad: Wad) -> Transact:
        """Move Ilk balance in Vat from source address to destiny address

        Args:
            ilk: Identifies the type of collateral.
            src: Source of the collateral (address of the source).
            dst: Destiny of the collateral (address of the recipient).
            wad: Amount of collateral to move.
        """
        assert isinstance(ilk, Ilk)
        assert isinstance(src, Address)
        assert isinstance(dst, Address)
        assert isinstance(wad, Wad)

        flux_args = [ilk.toBytes(), src.address, dst.address, wad.value]
        return Transact(self, self.web3, self.abi, self.address, self._contract, 'flux', flux_args)
Ejemplo n.º 7
0
    def kill(self, order_id: int) -> Transact:
        """Cancels an existing order.

        Orders can be cancelled only by their owners.

        Args:
            order_id: Id of the order you want to cancel.

        Returns:
            A :py:class:`pymaker.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(order_id, int))

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'kill(bytes32)',
                        [int_to_bytes32(order_id)])
Ejemplo n.º 8
0
    def transfer(self, address: Address, value: Wad) -> Transact:
        """Transfers tokens to a specified address.

        Args:
            address: Destination address to transfer the tokens to.
            value: The value of tokens to transfer.

        Returns:
            A :py:class:`pymaker.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(address, Address))
        assert (isinstance(value, Wad))

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'transfer',
                        [address.address, value.value])
Ejemplo n.º 9
0
    def frob(self,
             ilk: Ilk,
             urn_address: Address,
             dink: Wad,
             dart: Wad,
             collateral_owner=None,
             dai_recipient=None):
        """Adjust amount of collateral and reserved amount of Dai for the CDP

        Args:
            ilk: Identifies the type of collateral.
            urn_address: CDP holder (address of the Urn).
            dink: Amount of collateral to add/remove.
            dart: Adjust CDP debt (amount of Dai available for borrowing).
            collateral_owner: Holder of the collateral used to fund the CDP.
            dai_recipient: Party receiving the Dai.
        """
        assert isinstance(ilk, Ilk)
        assert isinstance(urn_address, Address)
        assert isinstance(dink, Wad)
        assert isinstance(dart, Wad)
        assert isinstance(collateral_owner,
                          Address) or (collateral_owner is None)
        assert isinstance(dai_recipient, Address) or (dai_recipient is None)

        # Usually these addresses are the same as the account holding the urn
        v = collateral_owner or urn_address
        w = dai_recipient or urn_address
        assert isinstance(v, Address)
        assert isinstance(w, Address)

        self.validate_frob(ilk, urn_address, dink, dart)

        if v == urn_address and w == urn_address:
            logger.info(
                f"frobbing {ilk.name} urn {urn_address.address} with dink={dink}, dart={dart}"
            )
        else:
            logger.info(f"frobbing {ilk.name} urn {urn_address.address} "
                        f"with dink={dink} from {v.address}, "
                        f"dart={dart} for {w.address}")

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'frob', [
                            ilk.toBytes(), urn_address.address, v.address,
                            w.address, dink.value, dart.value
                        ])
Ejemplo n.º 10
0
    def add_token_pair_whitelist(self, base_token: Address, quote_token: Address) -> Transact:
        """Adds a token pair to the whitelist.

        All newly created orders are checked against the whitelist.

        Args:
            base_token: Address of the ERC20 token.
            quote_token: Address of the ERC20 token.

        Returns:
            A :py:class:`pymaker.Transact` instance, which can be used to trigger the transaction.
        """
        assert(isinstance(base_token, Address))
        assert(isinstance(quote_token, Address))

        return Transact(self, self.web3, self.abi, self.address, self._contract,
                        'addTokenPairWhitelist', [base_token.address, quote_token.address])
Ejemplo n.º 11
0
    def make(self, pay_token: Address, pay_amount: Wad, buy_token: Address, buy_amount: Wad, pos: int = None) -> Transact:
        """Create a new order.

        The `have_amount` of `have_token` token will be taken from you on order creation and deposited
        in the market contract. Allowance needs to be set first. Refer to the `approve()` method
        in the `ERC20Token` class.

        The `MatchingMarket` contract maintains an internal ordered linked list of orders, which allows the contract
        to do automated matching. Client placing a new order can either let the contract find the correct
        position in the linked list (by passing `0` as the `pos` argument of `make`) or calculate the position
        itself and just pass the right value to the contract (this will happen if you omit the `pos`
        argument of `make`). The latter should always use less gas. If the client decides not to calculate the
        position or it does get it wrong and the number of open orders is high at the same time, the new order
        may not even be placed at all as the attempt to calculate the position by the contract will likely fail
        due to high gas usage.

        Args:
            pay_token: Address of the ERC20 token you want to put on sale.
            pay_amount: Amount of the `pay_token` token you want to put on sale.
            buy_token: Address of the ERC20 token you want to be paid with.
            buy_amount: Amount of the `buy_token` you want to receive.
            pos: The position to insert the order at in the sorted list.
                If `None`, the optimal position will automatically get calculated.

        Returns:
            A :py:class:`pymaker.Transact` instance, which can be used to trigger the transaction.
        """
        assert(isinstance(pay_token, Address))
        assert(isinstance(pay_amount, Wad))
        assert(isinstance(buy_token, Address))
        assert(isinstance(buy_amount, Wad))
        assert(isinstance(pos, int) or (pos is None))
        assert(pay_amount > Wad(0))
        assert(buy_amount > Wad(0))

        if pos is None:
            pos = self.position(pay_token=pay_token,
                                pay_amount=pay_amount,
                                buy_token=buy_token,
                                buy_amount=buy_amount)
        else:
            assert(pos >= 0)

        return Transact(self, self.web3, self.abi, self.address, self._contract,
                        'offer', [pay_amount.value, pay_token.address, buy_amount.value, buy_token.address, pos])
Ejemplo n.º 12
0
    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:`pymaker.Transact` instance, which can be used to trigger the transaction.
        """
        assert(isinstance(order, Order))
        assert(isinstance(fill_buy_amount, Wad))

        return Transact(self, self.web3, self.abi, self.address, self._contract, 'fillOrder',
                        [self._order_addresses(order), self._order_values(order), fill_buy_amount.value,
                         True, order.ec_signature_v,
                         hexstring_to_bytes(order.ec_signature_r),
                         hexstring_to_bytes(order.ec_signature_s)])
Ejemplo n.º 13
0
    def fork(self, ilk: Ilk, src: Address, dst: Address, dink: Wad, dart: Wad) -> Transact:
        """Split a Vault - binary approval or splitting/merging Vault's

        Args:
            ilk: Identifies the type of collateral.
            src: Address of the source Urn.
            dst: Address of the destiny Urn.
            dink: Amount of collateral to exchange.
            dart: Amount of stable coin debt to exchange.
        """
        assert isinstance(ilk, Ilk)
        assert isinstance(src, Address)
        assert isinstance(dst, Address)
        assert isinstance(dink, Wad)
        assert isinstance(dart, Wad)

        fork_args = [ilk.toBytes(), src.address, dst.address, dink.value, dart.value]
        return Transact(self, self.web3, self.abi, self.address, self._contract, 'fork', fork_args)
Ejemplo n.º 14
0
    def bite(self, ilk: Ilk, urn: Urn) -> Transact:
        """ Initiate liquidation of a vault, kicking off a flip auction

        Args:
            ilk: Identifies the type of collateral.
            urn: Address of the vault holder.
        """
        assert isinstance(ilk, Ilk)
        assert isinstance(urn, Urn)

        ilk = self.vat.ilk(ilk.name)
        urn = self.vat.urn(ilk, urn.address)
        rate = self.vat.ilk(ilk.name).rate
        logger.info(f'Biting {ilk.name} vault {urn.address.address} with ink={urn.ink} spot={ilk.spot} '
                    f'art={urn.art} rate={rate}')

        return Transact(self, self.web3, self.abi, self.address, self._contract,
                        'bite', [ilk.toBytes(), urn.address.address])
Ejemplo n.º 15
0
    def deposit_token(self, token: Address, amount: Wad) -> Transact:
        """Deposits `amount` of ERC20 token `token` to IDEX.

        Tokens will be pulled from the calling account, so the IDEX contract needs
        to have appropriate allowance. Either call `approve()` or set the allowance manually
        before trying to deposit tokens.

        Args:
            token: Address of the ERC20 token to be deposited.
            amount: Amount of token `token` to be deposited to IDEX.

        Returns:
            A :py:class:`pymaker.Transact` instance, which can be used to trigger the transaction.
        """
        assert(isinstance(token, Address))
        assert(isinstance(amount, Wad))
        return Transact(self, self.web3, self.abi, self.address, self._contract, 'depositToken',
                        [token.address, amount.value])
Ejemplo n.º 16
0
    def take(self, order_id: int, quantity: Wad) -> Transact:
        """Takes (buys) an order.

        If `quantity` is equal to `pay_amount`, the whole order will be taken (bought) which will make it
        disappear from the order book. If you want to buy a fraction of the order, set `quantity` to a number
        lower than `pay_amount`.

        Args:
            order_id: Id of the order you want to take (buy).
            quantity: Quantity of `pay_token` that you want to buy.

        Returns:
            A :py:class:`pymaker.Transact` instance, which can be used to trigger the transaction.
        """
        assert(isinstance(order_id, int))
        assert(isinstance(quantity, Wad))

        return Transact(self, self.web3, self.abi, self.address, self._contract, 'take',
                        [int_to_bytes32(order_id), quantity.value])
Ejemplo n.º 17
0
    def cancel_order(self, order: Order) -> Transact:
        """Cancels an order.

        Args:
            order: Order you want to cancel.

        Returns:
            A :py:class:`pymaker.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])
Ejemplo n.º 18
0
    def take(self, id: int, amt: Wad, max: Ray, who: Address = None, data=b'') -> Transact:
        """Buy amount of collateral from auction indexed by id.
        Args:
            id:     Auction id
            amt:    Upper limit on amount of collateral to buy
            max:    Maximum acceptable price (DAI / collateral)
            who:    Receiver of collateral and external call address
            data:   Data to pass in external call; if length 0, no call is done
        """
        assert isinstance(id, int)
        assert isinstance(amt, Wad)
        assert isinstance(max, Ray)

        if who:
            assert isinstance(who, Address)
        else:
            who = Address(self.web3.eth.defaultAccount)

        return Transact(self, self.web3, self.abi, self.address, self._contract, 'take',
                        [id, amt.value, max.value, who.address, data])
Ejemplo n.º 19
0
    def claim_funds(self, leverjobj: LeverjAPI, asset: str, quantity: int,
                    gluon_block_number):
        assert (isinstance(leverjobj, LeverjAPI))
        assert (isinstance(asset, str))
        assert (isinstance(quantity, int))

        app_id = leverjobj.get_spot_exchange_id()
        current_block = leverjobj._http_authenticated("GET", "/api/v1",
                                                      f"/plasma/{app_id}",
                                                      None)['number']

        if gluon_block_number is None:
            return self.withdraw_token(leverjobj, asset, int(quantity))

        else:
            if current_block >= gluon_block_number:
                ethereum_account = leverjobj.account_id
                custodian_account = self.address
                self.logger.info(
                    f"ethereum_account: {ethereum_account}, custodian_account: {custodian_account}, asset: {asset}"
                )
                response = leverjobj._http_authenticated(
                    "GET", "/api/v1",
                    f"/plasma/{app_id}/evmparams/withdrawals/account/{ethereum_account}/asset/{asset}",
                    None)
                response_app_id = int(response[0])
                response_bytes = response[1]
                self.logger.info(
                    f"finally gluon_block_number reached {gluon_block_number} and we are running final transact"
                )
                Transact(self, self.web3, self.abi, self.address,
                         self._contract, "withdraw",
                         [response_app_id, response_bytes],
                         {}).transact(from_address=self.middle_account)
                return None

        self.logger.info(
            f'does not look like gluon_block_number reached {gluon_block_number} and we are currently at {current_block}'
        )
        return gluon_block_number
Ejemplo n.º 20
0
    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:`pymaker.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):
            src = src.address
        if isinstance(dst, Address):
            dst = dst.address

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'permit', [src, dst, sig])
Ejemplo n.º 21
0
    def cancel_order(self, order: Order) -> Transact:
        """Cancels an existing order.

        Orders can be cancelled only by their owners.

        Args:
            order: The order you want to cancel.

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

        return Transact(
            self, self.web3, self.abi, self.address, self._contract,
            'cancelOrder', [
                order.buy_token.address, order.buy_amount.value,
                order.pay_token.address, order.pay_amount.value, order.expires,
                order.nonce, order.v if hasattr(order, 'v') else 0,
                order.r if hasattr(order, 'r') else bytes(),
                order.s if hasattr(order, 's') else bytes()
            ])
Ejemplo n.º 22
0
    def bark(self, ilk: Ilk, urn: Urn, kpr: Address = None) -> Transact:
        """ Initiate liquidation of a vault, kicking off a flip auction

        Args:
            ilk: Identifies the type of collateral.
            urn: Address of the vault holder.
            kpr: Keeper address; leave empty to use web3 default.
        """
        assert isinstance(ilk, Ilk)
        assert isinstance(urn, Urn)
        if kpr:
            assert isinstance(kpr, Address)
        else:
            kpr = Address(self.web3.eth.defaultAccount)

        ilk = self.vat.ilk(ilk.name)
        urn = self.vat.urn(ilk, urn.address)
        rate = self.vat.ilk(ilk.name).rate
        logger.info(f'Barking {ilk.name} vault {urn.address.address} with ink={urn.ink} spot={ilk.spot} '
                    f'art={urn.art} rate={rate}')

        return Transact(self, self.web3, self.abi, self.address, self._contract,
                        'bark', [ilk.toBytes(), urn.address.address, kpr.address])
Ejemplo n.º 23
0
    def approve(self, payee: Address,
                limit: Wad = Wad(2**256 - 1)) -> Transact:
        """Modifies the current allowance of a specified `payee` (delegate account).

        Allowance is an ERC20 concept allowing the `payee` (delegate account) to spend a fixed amount of tokens
        (`limit`) on behalf of the token owner.

        If `limit` is omitted, a maximum possible value is granted.

        Args:
            payee: The address of the delegate account (it's the address that can spend the tokens).
            limit: The value of the allowance i.e. the value of tokens that the `payee` (delegate account)
                can spend on behalf of their owner.

        Returns:
            A :py:class:`pymaker.Transact` instance, which can be used to trigger the transaction.
        """
        assert (isinstance(payee, Address))
        assert (isinstance(limit, Wad))

        return Transact(self, self.web3, self.abi, self.address,
                        self._contract, 'approve(address,uint256)',
                        [payee.address, limit.value])
Ejemplo n.º 24
0
    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:`pymaker.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})
Ejemplo n.º 25
0
    def make(self, pay_token: Address, pay_amount: Wad, buy_token: Address, buy_amount: Wad) -> Transact:
        """Create a new order.

        The `pay_amount` of `pay_token` token will be taken from you on order creation and deposited
        in the market contract. Allowance needs to be set first - refer to the `approve()` method.

        Args:
            pay_token: Address of the ERC20 token you want to put on sale.
            pay_amount: Amount of the `pay_token` token you want to put on sale.
            buy_token: Address of the ERC20 token you want to be paid with.
            buy_amount: Amount of the `buy_token` you want to receive.

        Returns:
            A :py:class:`pymaker.Transact` instance, which can be used to trigger the transaction.
        """
        assert(isinstance(pay_token, Address))
        assert(isinstance(pay_amount, Wad))
        assert(isinstance(buy_token, Address))
        assert(isinstance(buy_amount, Wad))
        assert(pay_amount > Wad(0))
        assert(buy_amount > Wad(0))

        return Transact(self, self.web3, self.abi, self.address, self._contract,
                        'make', [pay_token.address, buy_token.address, pay_amount.value, buy_amount.value])
Ejemplo n.º 26
0
    def approval_function(token: ERC20Token, spender_address: Address,
                          spender_name: str):
        address_to_check = kwargs[
            'from_address'] if 'from_address' in kwargs else Address(
                token.web3.eth.defaultAccount)

        move_contract = Contract._get_contract(web3=token.web3,
                                               abi=move_abi,
                                               address=token.address)
        if move_contract.functions.can(
                address_to_check.address,
                spender_address.address).call() is False:
            logger = logging.getLogger()
            logger.info(
                f"Approving {spender_name} ({spender_address}) to move our {token.address} directly"
            )

            hope = Transact(move_contract,
                            move_contract.web3, move_contract.abi,
                            Address(move_contract.address), move_contract,
                            'hope', [spender_address.address])

            if not hope.transact(**kwargs):
                raise RuntimeError("Approval failed!")
Ejemplo n.º 27
0
 def test_empty_tx(self):
     empty_tx = Transact(self, self.web3, None, self.keeper_address, None,
                         None,
                         [self.keeper_address, Wad(0)])
     empty_tx.transact()
Ejemplo n.º 28
0
 def drip(self) -> Transact:
     return Transact(self, self.web3, self.abi, self.address, self._contract, 'drip', [])
Ejemplo n.º 29
0
 def gulp(self, address: Address):
     return Transact(self, self.web3, self.abi, self.address, self._contract, 'gulp(address)', [address.address])
Ejemplo n.º 30
0
    def drip(self, ilk: Ilk) -> Transact:
        assert isinstance(ilk, Ilk)

        return Transact(self, self.web3, self.abi, self.address, self._contract, 'drip', [ilk.toBytes()])