def _get_effective_share_info(self, share_token_items, total_share_token_amount, db_session):
        effective_share_dict = {}
        position_holder_dict = {}
        share_token_dict = {}
        total_effective_share_amount = Decimal(0)
        for item in share_token_items:
            share_token_dict[item.holder] = item.balance
           
        token_map = self._get_token_map(db_session)
        perp_addr = token_map[self._share_token_address].get('perp_addr')
        amm_proxy_addr = token_map[self._share_token_address].get('amm_proxy_addr')
        position_items = db_session.query(PositionBalance)\
            .filter(PositionBalance.perpetual_address == perp_addr)\
            .all()
        for item in position_items:
            position_holder_dict[item.holder] = item.balance
        amm_position = position_holder_dict[amm_proxy_addr]

        for holder, holder_position_in_margin_account in position_holder_dict.items():
            holder_share_token_amount = share_token_dict.get(holder)
            if holder_share_token_amount == Decimal(0) or holder_share_token_amount is None:
                continue
            holder_position_in_amm = Wad.from_number(amm_position) * Wad.from_number(holder_share_token_amount) / Wad.from_number(total_share_token_amount)
            holder_portfolio_position = holder_position_in_amm + Wad.from_number(holder_position_in_margin_account)
            imbalance_rate = abs(holder_portfolio_position / holder_position_in_amm)
            imbalance_rate = Decimal(str(imbalance_rate))
            if imbalance_rate <= Decimal(0.1):
                holder_effective_share = holder_share_token_amount
            elif imbalance_rate >= Decimal(0.9):
                holder_effective_share = holder_share_token_amount * Decimal(0.1)
            else:
                holder_effective_share = holder_share_token_amount * (Decimal(89/80) - imbalance_rate * Decimal(9/8))
            effective_share_dict[holder] = holder_effective_share
            total_effective_share_amount += holder_effective_share
        return effective_share_dict, total_effective_share_amount
Exemple #2
0
 def _get_keeper_liquidate_amount(self, keeper_account):
     markPrice = self.perp.markPrice()
     availableMargin = self.perp.getAvailableMargin(keeper_account)
     if config.INVERSE:
         markPrice = Wad.from_number(1)/markPrice
     amount = int(availableMargin * Wad.from_number(config.LEVERAGE) * markPrice)
     amount = math.floor(amount/config.LOT_SIZE)*config.LOT_SIZE
     return Wad.from_number(amount)
Exemple #3
0
    def _get_holder_reward_weight(self, block_number, pool_value_info,
                                  db_session):
        holder_amms_weight_dict = {}
        holder_amms_reward_dict = {}
        amms_pool_total_reward = Decimal(0)

        for pool_name in pool_value_info.keys():
            total_share_token_amount = pool_value_info[pool_name][
                'total_share_token_amount']
            if total_share_token_amount == 0:
                continue
            share_token_items = pool_value_info[pool_name]['share_token_items']
            pool_type = pool_value_info[pool_name]['pool_type']
            pool_reward = pool_value_info[pool_name]['pool_reward']
            amms_pool_total_reward += Decimal(str(pool_reward))

            for item in share_token_items:
                holder = item.holder
                if item.balance == Decimal(0):
                    continue
                # amm pool, use effective share after xia_rebalance_hard_fork block number
                if pool_type == 'AMM' and block_number >= self._xia_rebalance_hard_fork_block_number:
                    total_effective_share_amount = pool_value_info[pool_name][
                        'total_effective_share_amount']
                    holder_effective_share_amount = pool_value_info[pool_name][
                        'effective_share_dict'].get(holder, Decimal(0))
                    wad_reward = pool_reward * Wad.from_number(
                        holder_effective_share_amount) / Wad.from_number(
                            total_effective_share_amount)
                    reward = Decimal(str(wad_reward))
                    if holder not in holder_amms_reward_dict:
                        holder_amms_reward_dict[holder] = reward
                    else:
                        holder_amms_reward_dict[holder] += reward

        self._save_theory_mining_reward('AMM', holder_amms_reward_dict,
                                        db_session)

        holder_mcb_balance_dict = self._get_holder_mcb_balance(db_session)
        total_holder_reward_weight = Decimal(0)
        for holder, reward in holder_amms_reward_dict.items():
            holder_reward_percent = reward / amms_pool_total_reward
            holder_mcb_balance = holder_mcb_balance_dict.get(
                holder, Decimal(0))
            reward_factor = self._get_holder_reward_factor(
                holder, reward, holder_mcb_balance)
            total_holder_reward_weight += holder_reward_percent * reward_factor

        for holder, reward in holder_amms_reward_dict.items():
            holder_mcb_balance = holder_mcb_balance_dict.get(
                holder, Decimal(0))
            reward_factor = self._get_holder_reward_factor(
                holder, reward, holder_mcb_balance)
            holder_amms_weight_dict[
                holder] = reward_factor / total_holder_reward_weight

        return holder_amms_weight_dict
Exemple #4
0
    def __init__(self, side: int, size: int, entry_value: int,
                 entry_social_loss: int, entry_funding_loss: int,
                 cash_balance: int):
        assert (isinstance(side, int))
        assert (isinstance(size, int))
        assert (isinstance(entry_value, int))
        assert (isinstance(entry_social_loss, int))
        assert (isinstance(entry_funding_loss, int))

        self.side = PositionSide(side)
        self.size = Wad(size)
        self.entry_value = Wad(entry_value)
        self.entry_social_loss = Wad(entry_social_loss)
        self.entry_funding_loss = Wad(entry_funding_loss)
        self.cash_balance = Wad(cash_balance)
Exemple #5
0
    def allowance(self, address: Address, guy: Address) -> Wad:
        assert (isinstance(address, Address))
        assert (isinstance(guy, Address))

        return Wad(
            self.contract.functions.allowance(address.address,
                                              guy.address).call())
Exemple #6
0
 def _check_redeeming_accounts(self):
     fund_state = self.fund.state()
     if fund_state == State.Normal:
         try:
             fundMarginAccount = self.perp.getMarginAccount(Address(config.FUND_ADDRESS))
             redeeming_accounts = self._get_redeeming_accounts()
             for account in redeeming_accounts:
                 price_limit = self._get_redeem_trade_price(fundMarginAccount.side)
                 share_amount = self.fund.redeemingBalance(account)
                 if share_amount > Wad(0):
                     side = 2 if fundMarginAccount.side == PositionSide.LONG else 1
                     tx_hash = self.fund.bidRedeemingShare(account, share_amount, price_limit, side , self.keeper_account, self.gas_price)
                     transaction_status = self._wait_transaction_receipt(tx_hash, 10)
                     if transaction_status:
                         self.logger.info(f"bidRedeemingShare success. amount:{share_amount}")
                     else:
                         self.logger.info(f"bidRedeemingShare fail. amount:{share_amount}")
         except Exception as e:
             self.logger.fatal(f"_check_redeeming_accounts bidRedeemingShare fail. error:{e}")
     elif fund_state == State.Emergency:
         try:
             fundMarginAccount = self.perp.getMarginAccount(Address(config.FUND_ADDRESS))
             # price_limit = self._get_redeem_trade_price(fundMarginAccount.side)
             price_limit = self.perp.markPrice()
             total_supply = self.fund.total_supply()
             self.get_gas_price()
             side = 2 if fundMarginAccount.side == PositionSide.LONG else 1
             tx_hash = self.fund.bidSettledShare(total_supply, price_limit, side, self.keeper_account, self.gas_price)
             transaction_status = self._wait_transaction_receipt(tx_hash, 10)
             if transaction_status:
                 self.logger.info(f"bidSettledShare success. amount:{total_supply}")
             else:
                 self.logger.info(f"bidSettledShare fail. amount:{total_supply}")
         except Exception as e:
             self.logger.fatal(f"_check_redeeming_accounts emergency fail. error:{e}")
Exemple #7
0
    def run(self):
        if self._check_account_from_key() is False:
            return
        
        # approve MCB token to disperse for multiple transaction
        if self._MCBToken.allowance(self._payer_account, self._disperse.address) == Wad(0):
            self._MCBToken.approve(self._disperse.address, self._payer_account)

        # restore pending transaction if need
        # unpaid_rewards = self._restore_pending_data()

        # check pending transactions
        if self._check_pending_transactions() is False:
            return
        
        # get all miners unpaid rewards
        unpaid_rewards = self._get_miner_unpaid_reward()
        miners_count = len(unpaid_rewards["miners"])
        if miners_count == 0:
            self._logger.info(f"no miner need to be payed")
            return

        total_amount = Decimal(0)
        for reward in unpaid_rewards['amounts']:
            total_amount += reward

        self._logger.info(f"total_amount: {total_amount*(Decimal(10)**18)}")
        admin_input = input("yes or no: ")
        if admin_input != "yes":
            self._logger.info(f"input is {admin_input}. payer stop!")
            return

        # get gas price for transaction
        self._get_gas_price()
        # send MCB to all accounts
        for i in range(math.ceil(miners_count/config.MAX_PATCH_NUM)):
            start_idx = i*config.MAX_PATCH_NUM
            end_idx = min((i+1)*config.MAX_PATCH_NUM, miners_count)
            self._logger.info(f"miners count: {miners_count}, send from {start_idx} to {end_idx}")

            miners = unpaid_rewards["miners"][start_idx:end_idx]
            amounts = unpaid_rewards["amounts"][start_idx:end_idx]
            try:
                tx_hash = self._disperse.disperse_token(self._MCBToken.address, miners, amounts,
                    self._payer_account, self._gas_price)
                self._save_payment_transaction(self._web3.toHex(tx_hash), miners, amounts)
            except Exception as e:
                self._logger.fatal(f"disperse transaction fail! Exception:{e}")
                continue

            try:
                tx_receipt = self._web3.eth.waitForTransactionReceipt(tx_hash, timeout=config.WAIT_TIMEOUT)
                self._save_payments_info(tx_receipt, miners, amounts)
            except Exception as e:
                self._logger.fatal(
                    f"get trasaction receipt fail! tx_hash:{tx_hash}, err:{e}")
                continue

        return
Exemple #8
0
    def __init__(self, needRebalance: bool, amount: int, side: int):
        assert (isinstance(needRebalance, bool))
        assert (isinstance(amount, int))
        assert (isinstance(side, int))

        self.needRebalance = needRebalance
        self.amount = Wad(amount)
        self.side = PositionSide(side)
Exemple #9
0
 def approve(self,
             address: Address,
             user: Address,
             limit: Wad = Wad(2**256 - 1)):
     assert (isinstance(address, Address))
     assert (isinstance(limit, Wad))
     tx_hash = self.contract.functions.approve(
         address.address, limit.value).transact({'from': user.address})
     tx_receipt = self.web3.eth.waitForTransactionReceipt(tx_hash)
     #self.logger.info(tx_receipt)
     return tx_receipt
Exemple #10
0
 def disperse_token(self, token: Address, addresses: list, amounts: list,
                    user: Address, gasPrice: int):
     amounts_toWad = []
     for amount in amounts:
         amounts_toWad.append(Wad.from_number(amount).value)
     tx_hash = self.contract.functions.disperseToken(
         token.address, addresses, amounts_toWad).transact({
             'from':
             user.address,
             'gasPrice':
             gasPrice
         })
     return tx_hash
Exemple #11
0
 def _get_pool_usd_value(self, block_number, pool_name,
                         pool_share_token_address, inverse, db_session):
     amm_usd_value = Decimal(0)
     amm_position = Decimal(0)
     token_map = self._get_token_map(pool_share_token_address, db_session)
     perp_addr = token_map[pool_share_token_address].get('perp_addr')
     amm_proxy_addr = token_map[pool_share_token_address].get(
         'amm_proxy_addr')
     amm_proxy_item = db_session.query(PositionBalance)\
         .filter(PositionBalance.perpetual_address == perp_addr)\
         .filter(PositionBalance.holder == amm_proxy_addr)\
         .first()
     if amm_proxy_item:
         amm_position = amm_proxy_item.balance
     if inverse:
         amm_usd_value = abs(Wad.from_number(amm_position))
     else:
         chain_link_price = self._get_chain_link_price(
             block_number, pool_name, db_session)
         # vanilla contract
         amm_usd_value = abs(
             Wad.from_number(amm_position) *
             Wad.from_number(chain_link_price))
     return amm_usd_value
Exemple #12
0
    def _close_position_in_AMM(self):
        margin_account = self.perp.getMarginAccount(self.keeper_account)
        size = int(margin_account.size)
        if size < config.POSITION_LIMIT:
            return

        deadline = int(time.time()) + config.DEADLINE
        amm_available_margin = self.AMM.current_available_margin()
        self.logger.info(f"amm_available_margin:{amm_available_margin}")
        amm_position_size = self.AMM.position_size()
        self.logger.info(f"amm_position_size:{amm_position_size}")

        trade_side = PositionSide.LONG if margin_account.side == PositionSide.SHORT else PositionSide.SHORT
        try:
            trade_price = compute_AMM_price(amm_available_margin, amm_position_size, trade_side, margin_account.size)
            self.logger.info(f"compute_price:{trade_price}")
        except Exception as e:
            self.logger.fatal(f"compute amm price failed. error:{e}")
            return
        trade_price = trade_price*Wad.from_number(1 - config.PRICE_SLIPPAGE) if trade_side == PositionSide.SHORT else trade_price*Wad.from_number(1 + config.PRICE_SLIPPAGE)

        tx_hash = None
        try:
            if trade_side == PositionSide.LONG:
               tx_hash = self.AMM.buy(margin_account.size, trade_price, deadline, self.keeper_account, self.gas_price)
            else:
               tx_hash = self.AMM.sell(margin_account.size, trade_price, deadline, self.keeper_account, self.gas_price)
            self.logger.info(f"close in AMM success. price:{trade_price} size{margin_account.size}")
            # wait transaction times is 1, cause amm transaction deadline is 120s, if wait timeout, transaction will fail, no need to add gas price
            transaction_status = self._wait_transaction_receipt(tx_hash, 1)
            if transaction_status:
                self.logger.info(f"close position in AMM success. price:{trade_price} size:{margin_account.size}")
            else:
                self.logger.info(f"close position in AMM fail. price:{trade_price} amount:{margin_account.size}")
        except Exception as e:
                self.logger.fatal(f"close position in AMM failed. price:{trade_price} size:{margin_account.size} error:{e}")
Exemple #13
0
 def _get_calculate_liquidate_amount(self, address):
     markPrice = self.perp.markPrice()
     cal_amount = int(self.perp.calculateLiquidateAmount(address, markPrice))
     cal_amount = math.ceil(cal_amount/config.LOT_SIZE)*config.LOT_SIZE
     return Wad.from_number(cal_amount)
Exemple #14
0
    def _get_pool_value_info(self, block_number, pool_info,
                             pool_reward_percent, db_session):
        if self._mining_round == 'QIN' and block_number < self._qin_reduce_reward_block_number:
            self._reward_per_block = 2
        elif self._mining_round == 'QIN' and block_number >= self._qin_reduce_reward_block_number:
            self._reward_per_block = 0.2
        # support vote https://vote.mcdex.io/mainnet/proposal/14,  blocknumber >=11601000 && blocknumber <11685000 reward 0.1875
        elif block_number >= 11601000 and block_number < 11685000:
            self._reward_per_block = 0.1875
        # update uniswap_pool_proportion, every block update
        self._update_uniswap_pool_proportion(pool_info, db_session)

        pool_value_info = {}
        pools_total_effective_value = Wad(0)
        for pool_name in pool_info.keys():
            pool_share_token_address = pool_info[pool_name].get(
                'pool_share_token_address')
            if pool_name not in pool_value_info.keys():
                pool_value_info[pool_name] = {}
            pool_value_info[pool_name][
                'pool_share_token_address'] = pool_share_token_address

            # use for amm pools reward distribute
            amm_pool_proportion = pool_info[pool_name].get(
                'amm_pool_proportion', 1)
            pool_value_info[pool_name][
                'amm_pool_proportion'] = amm_pool_proportion

            # use for uniswap pools reward distribute
            uniswap_pool_proportion = pool_info[pool_name].get(
                'uniswap_pool_proportion', 1)
            pool_value_info[pool_name][
                'uniswap_pool_proportion'] = uniswap_pool_proportion

            pool_type = pool_info[pool_name].get('pool_type')
            pool_contract_inverse = pool_info[pool_name].get(
                'pool_contract_inverse', True)
            pool_value_info[pool_name]['pool_type'] = pool_type

            total_share_token_amount = self._get_total_share_token_amount(
                pool_share_token_address, db_session)
            pool_value_info[pool_name][
                'total_share_token_amount'] = total_share_token_amount

            share_token_items = self._get_share_token_items(
                pool_share_token_address, db_session)
            pool_value_info[pool_name]['share_token_items'] = share_token_items

            if pool_type == 'AMM' and block_number >= self._xia_rebalance_hard_fork_block_number:
                # pool_type is AMM, use effective share calc reward:
                # 1) period XIA and block_number >=_xia_rebalance_hard_fork_block_number;
                # 2) period SHANG;
                # 3) FROM period ZHOU, effective share eq to holder share
                effective_share_dict, total_effective_share_amount = self._get_effective_share_info(
                    block_number, pool_share_token_address, share_token_items,
                    total_share_token_amount, db_session)
                pool_value_info[pool_name][
                    'effective_share_dict'] = effective_share_dict
                pool_value_info[pool_name][
                    'total_effective_share_amount'] = total_effective_share_amount
                pool_usd_value = self._get_pool_usd_value(
                    block_number, pool_name, pool_share_token_address,
                    pool_contract_inverse, db_session)
                if total_share_token_amount != 0:
                    pool_effective_usd_value = pool_usd_value * Wad.from_number(
                        total_effective_share_amount) / Wad.from_number(
                            total_share_token_amount)
                else:
                    self._logger.warning(
                        f'opps, pool:{pool_name}, share_token total amount is zero, skip it!'
                    )
                    pool_effective_usd_value = Wad(0)
                pool_value_info[pool_name][
                    'pool_effective_usd_value'] = pool_effective_usd_value
                pools_total_effective_value += pool_effective_usd_value
            else:
                # include two case:
                # 1) pool_type is UNISWAP;
                # 2) pool_type is AMM and block number before _xia_rebalance_hard_fork_block_number;
                pool_reward = Wad.from_number(
                    pool_reward_percent) * Wad.from_number(
                        self._reward_per_block) * Wad.from_number(
                            uniswap_pool_proportion)
                pool_value_info[pool_name]['pool_reward'] = pool_reward

        # update AMM pool reward
        if pool_type == 'AMM' and block_number >= self._xia_rebalance_hard_fork_block_number:
            for pool_name in pool_value_info.keys():
                amm_pool_proportion = pool_value_info[pool_name].get(
                    'amm_pool_proportion', 1)
                pool_effective_usd_value = pool_value_info[pool_name][
                    'pool_effective_usd_value']
                if block_number >= self._qin_begin_block_number:
                    pool_reward = Wad.from_number(
                        pool_reward_percent) * Wad.from_number(
                            self._reward_per_block) * Wad.from_number(
                                amm_pool_proportion)
                else:
                    pool_reward = Wad.from_number(
                        pool_reward_percent) * Wad.from_number(
                            self._reward_per_block
                        ) * pool_effective_usd_value / Wad.from_number(
                            pools_total_effective_value)
                pool_value_info[pool_name]['pool_reward'] = pool_reward

        return pool_value_info
Exemple #15
0
 def getAvailableMargin(self, address: Address) -> Wad:
     availableMargin = self.contract.functions.availableMargin(
         address.address).call()
     return Wad(availableMargin)
Exemple #16
0
 def markPrice(self) -> Wad:
     return Wad(self.contract.functions.markPrice().call())
Exemple #17
0
    def __init__(self, price: int, amount: int):
        assert (isinstance(price, int))
        assert (isinstance(amount, int))

        self.price = Wad(price)
        self.amount = Wad(amount)
Exemple #18
0
 def current_available_margin(self) -> Wad:
     return Wad(self.contract.functions.currentAvailableMargin().call())
Exemple #19
0
 def calculateLiquidateAmount(self, guy: Address, price: Wad) -> Wad:
     return Wad(
         self.contract.functions.calculateLiquidateAmount(
             guy.address, price.value).call())
Exemple #20
0
 def netAssetValuePerShare(self) -> Wad:
     return Wad(self.contract.functions.netAssetValuePerShare().call())
Exemple #21
0
 def redeemingBalance(self, address: Address) -> Wad:
     assert isinstance(address, Address)
     return Wad(
         self.contract.functions.redeemingBalance(address.address).call())
Exemple #22
0
    def _get_effective_share_info(self, block_number, pool_share_token_address,
                                  share_token_items, total_share_token_amount,
                                  db_session):
        effective_share_dict = {}
        position_holder_dict = {}
        share_token_dict = {}
        total_effective_share_amount = Decimal(0)
        for item in share_token_items:
            share_token_dict[item.holder] = item.balance

        if block_number >= self._zhou_begin_block_number:
            # period from ZHOU, pool_effective_usd_value is pool_usd_value
            effective_share_dict = share_token_dict
            total_effective_share_amount = total_share_token_amount
            return effective_share_dict, total_effective_share_amount

        token_map = self._get_token_map(pool_share_token_address, db_session)
        perp_addr = token_map[pool_share_token_address].get('perp_addr')
        amm_proxy_addr = token_map[pool_share_token_address].get(
            'amm_proxy_addr')
        position_items = db_session.query(PositionBalance)\
            .filter(PositionBalance.perpetual_address == perp_addr)\
            .all()
        for item in position_items:
            position_holder_dict[item.holder] = item.balance
        amm_position = position_holder_dict.get(amm_proxy_addr, Decimal(0))

        for holder, holder_position_in_margin_account in position_holder_dict.items(
        ):
            holder_share_token_amount = share_token_dict.get(holder)
            if holder_share_token_amount == Decimal(
                    0) or holder_share_token_amount is None:
                continue
            holder_position_in_amm = Wad.from_number(
                amm_position) * Wad.from_number(
                    holder_share_token_amount) / Wad.from_number(
                        total_share_token_amount)
            holder_portfolio_position = holder_position_in_amm + Wad.from_number(
                holder_position_in_margin_account)
            imbalance_rate = abs(holder_portfolio_position /
                                 holder_position_in_amm)
            imbalance_rate = Decimal(str(imbalance_rate))
            if self._mining_round == 'XIA':
                if imbalance_rate <= Decimal(0.1):
                    holder_effective_share = holder_share_token_amount
                elif imbalance_rate >= Decimal(0.9):
                    holder_effective_share = holder_share_token_amount * Decimal(
                        0.1)
                else:
                    holder_effective_share = holder_share_token_amount * (
                        Decimal(89 / 80) - imbalance_rate * Decimal(9 / 8))
            elif self._mining_round == 'SHANG':
                if imbalance_rate <= Decimal(0.2):
                    holder_effective_share = holder_share_token_amount
                elif imbalance_rate >= Decimal(0.9):
                    holder_effective_share = holder_share_token_amount * Decimal(
                        0.1)
                else:
                    holder_effective_share = holder_share_token_amount * (
                        Decimal(44 / 35) - imbalance_rate * Decimal(9 / 7))
            effective_share_dict[holder] = holder_effective_share
            total_effective_share_amount += holder_effective_share
        return effective_share_dict, total_effective_share_amount
    def sync(self, watcher_id, block_number, block_hash, db_session):
        """Sync data"""
        if block_number < self._begin_block or block_number > self._end_block:
            self._logger.info(f'block_number {block_number} not in mining window!')
            return
        
        result = db_session.query(TokenBalance)\
            .filter(TokenBalance.token == self._share_token_address)\
            .with_entities(
                func.sum(TokenBalance.balance)
        ).first()
        if result[0] is None:
            self._logger.warning(f'opps, token_balance is empty!')
            return
        total_share_token_amount = result[0]

        # get all immature summary items
        immature_summary_dict = {}
        immature_summary_items = db_session.query(ImmatureMiningRewardSummary)\
            .filter(ImmatureMiningRewardSummary.mining_round == self._mining_round)\
            .all()
        for item in immature_summary_items:
            immature_summary_dict[item.holder] = item    

        share_token_items = db_session.query(TokenBalance)\
            .filter(TokenBalance.token == self._share_token_address)\
            .with_entities(
                TokenBalance.holder,
                TokenBalance.balance
        ).all()        
        self._logger.info(f'sync mining reward, block_number:{block_number}, holders:{len(share_token_items)}')
        
        # check rebalance_hard_fork block number 
        if block_number >= self._rebalance_hard_fork_block_number:
            effective_share_dict, total_effective_share_amount = self._get_effective_share_info(share_token_items, total_share_token_amount, db_session)

        for item in share_token_items:
            holder = item.holder
            if block_number >= self._rebalance_hard_fork_block_number:
                holder_effective_share_amount = effective_share_dict.get(holder, Decimal(0))
                wad_reward = Wad.from_number(self._reward_per_block) * Wad.from_number(holder_effective_share_amount) / Wad.from_number(total_effective_share_amount)
                reward = Decimal(str(wad_reward))
            else:
                holder_share_token_amount = Decimal(item.balance)
                wad_reward = Wad.from_number(self._reward_per_block) * Wad.from_number(holder_share_token_amount) / Wad.from_number(total_share_token_amount)
                reward = Decimal(str(wad_reward))

            immature_mining_reward = ImmatureMiningReward()
            immature_mining_reward.block_number = block_number
            immature_mining_reward.mining_round = self._mining_round
            immature_mining_reward.holder = holder
            immature_mining_reward.mcb_balance = reward
            db_session.add(immature_mining_reward)

            # update immature_mining_reward_summaries table, simulated materialized view
            if holder not in immature_summary_dict.keys():
                immature_summary_item = ImmatureMiningRewardSummary()
                immature_summary_item.mining_round = self._mining_round
                immature_summary_item.holder = holder
                immature_summary_item.mcb_balance = reward
            else:
                immature_summary_item = immature_summary_dict[holder]
                immature_summary_item.mcb_balance += reward
            db_session.add(immature_summary_item)
Exemple #24
0
 def current_fair_price(self, user: Address) -> Wad:
     return Wad(self.contract.functions.currentFairPrice().call({'from': user.address}))
Exemple #25
0
    def _calculate_pools_reward(self, block_number, pool_info,
                                pool_reward_percent, db_session):
        pool_value_info = self._get_pool_value_info(block_number, pool_info,
                                                    pool_reward_percent,
                                                    db_session)
        self._logger.info(
            f'sync mining reward, block_number:{block_number}, pools:{",".join(pool_info.keys())}'
        )

        holder_amms_weight_dict = {}
        holder_weight_dict = {}
        if block_number >= self._qin_begin_block_number:
            holder_amms_weight_dict = self._get_holder_amms_reward_weight(
                block_number, pool_value_info, db_session)
        elif block_number >= self._zhou_begin_block_number:
            holder_weight_dict = self._get_holder_reward_weight(
                block_number, pool_value_info, db_session)

        for pool_name in pool_value_info.keys():
            if block_number >= self._qin_begin_block_number:
                holder_weight_dict = holder_amms_weight_dict.get(pool_name, {})

            # get all immature summary items of pool_name
            immature_summary_dict = {}
            immature_summary_items = db_session.query(ImmatureMiningRewardSummary)\
                .filter(ImmatureMiningRewardSummary.mining_round == self._mining_round)\
                .filter(ImmatureMiningRewardSummary.pool_name == pool_name)\
                .all()
            for item in immature_summary_items:
                immature_summary_dict[item.holder] = item

            total_share_token_amount = pool_value_info[pool_name][
                'total_share_token_amount']
            if total_share_token_amount == 0:
                self._logger.warning(
                    f'opps, pool:{pool_name}, share_token total amount is zero, skip it!'
                )
                continue

            share_token_items = pool_value_info[pool_name]['share_token_items']
            pool_type = pool_value_info[pool_name]['pool_type']
            pool_reward = pool_value_info[pool_name]['pool_reward']

            for item in share_token_items:
                holder = item.holder
                if item.balance == Decimal(0):
                    continue
                # amm pool, use effective share after xia_rebalance_hard_fork block number
                if pool_type == 'AMM' and block_number >= self._xia_rebalance_hard_fork_block_number:
                    holder_weight = holder_weight_dict.get(holder, Decimal(1))
                    total_effective_share_amount = pool_value_info[pool_name][
                        'total_effective_share_amount']
                    holder_effective_share_amount = pool_value_info[pool_name][
                        'effective_share_dict'].get(holder, Decimal(0))
                    wad_reward = Wad.from_number(
                        holder_weight) * pool_reward * Wad.from_number(
                            holder_effective_share_amount) / Wad.from_number(
                                total_effective_share_amount)
                    reward = Decimal(str(wad_reward))
                else:
                    holder_share_token_amount = Decimal(item.balance)
                    wad_reward = pool_reward * Wad.from_number(
                        holder_share_token_amount) / Wad.from_number(
                            total_share_token_amount)
                    reward = Decimal(str(wad_reward))

                immature_mining_reward = ImmatureMiningReward()
                immature_mining_reward.block_number = block_number
                immature_mining_reward.pool_name = pool_name
                immature_mining_reward.mining_round = self._mining_round
                immature_mining_reward.holder = holder
                immature_mining_reward.mcb_balance = reward
                db_session.add(immature_mining_reward)

                # update immature_mining_reward_summaries table, simulated materialized view
                if holder not in immature_summary_dict.keys():
                    immature_summary_item = ImmatureMiningRewardSummary()
                    immature_summary_item.mining_round = self._mining_round
                    immature_summary_item.pool_name = pool_name
                    immature_summary_item.holder = holder
                    immature_summary_item.mcb_balance = reward
                else:
                    immature_summary_item = immature_summary_dict[holder]
                    immature_summary_item.mcb_balance += reward
                db_session.add(immature_summary_item)
Exemple #26
0
 def total_supply(self) -> Wad:
     return Wad(self.contract.functions.totalSupply().call())
Exemple #27
0
 def position_size(self) -> Wad:
     return Wad(self.contract.functions.positionSize().call())
Exemple #28
0
 def getRebalanceSlippage(self) -> Wad:
     description = self.contract.functions.description().call()
     return Wad(description[2])
Exemple #29
0
    def balance_of(self, address: Address) -> Wad:
        assert (isinstance(address, Address))

        return Wad(self.contract.functions.balanceOf(address.address).call())