示例#1
0
    def __init__(self, wallet_api, db_path, cdc_contract_address, account,
                 stableTokenPrecision, collateralPrecision, session, symbol,
                 logger):
        self.wallet_api = wallet_api
        self.symbol = symbol
        #Base = declarative_base()
        #Base.metadata.create_all(engine)
        self.is_running = False
        self.Session = session
        self.account = account
        self.cdc_contract_address = cdc_contract_address
        self.stableTokenPrecision = stableTokenPrecision
        self.collateralPrecision = collateralPrecision
        self.liquidator = CDCOperation(account, cdc_contract_address,
                                       self.wallet_api, self.symbol)
        self.logger = logger

        account_addr = self.wallet_api.rpc_request("get_account_addr",
                                                   [account])
        if (account_addr is None):
            raise RuntimeError("address is None, account:" + str(account))
        self.account_addr = account_addr
        rstr = self.wallet_api.rpc_request(
            'invoke_contract_offline',
            [self.account, self.cdc_contract_address, "getInfo", ""])
        cdc_contract_info = json.loads(rstr)
        self.stableTokenAddr = cdc_contract_info["stableTokenAddr"]
        self.priceFeederAddr = cdc_contract_info["priceFeederAddr"]
示例#2
0
 def __init__(self, wallet_rpc_url, db_path, cdc_contract_address, account,
              stableTokenPrecision, collateralPrecision):
     threading.Thread.__init__(self)
     self.wallet_api = HXWalletApi(name='events', rpc_url=wallet_rpc_url)
     #Base = declarative_base()
     engine = create_engine(db_path,
                            echo=True,
                            poolclass=SingletonThreadPool,
                            connect_args={'check_same_thread': False})
     #Base.metadata.create_all(engine)
     self.Session = sessionmaker(bind=engine)
     self.account = account
     self.cdc_contract_address = cdc_contract_address
     self.stableTokenPrecision = stableTokenPrecision
     self.collateralPrecision = collateralPrecision
     self.liquidator = CDCOperation(account, cdc_contract_address,
                                    self.wallet_api)
     account_addr = self.wallet_api.rpc_request("get_account_addr",
                                                [account])
     if (account_addr is None):
         raise RuntimeError("address is None, account:" + str(account))
     self.account_addr = account_addr
     rstr = self.wallet_api.rpc_request(
         'invoke_contract_offline',
         [self.account, self.cdc_contract_address, "getInfo", ""])
     cdc_contract_info = json.loads(rstr)
     self.stableTokenAddr = cdc_contract_info["stableTokenAddr"]
     self.priceFeederAddr = cdc_contract_info["priceFeederAddr"]
示例#3
0
 def _refreshAccountList(self):
     self.accountList.clear()
     accounts = self.api.rpc_request('list_my_accounts', [])
     if accounts is None:
         return
     self.accounts = accounts
     self.collector = EventsCollector(self.accounts[0]['name'], self.collateral_contract, self.api)
     self.cdcOp = CDCOperation(self.accounts[0]['name'], self.collateral_contract, self.api)
     self.accountList.currentIndexChanged.connect(self.accountChange)
     self.priceFeederExist = False
     for a in self.accounts:
         if self.priceFeederAccount == a['name']:
             self.priceFeederExist = True
         self.accountList.addItem(a['name'])
     if not self.priceFeederExist:
         self.priceFeederAccount = self.accounts[0]['name']
示例#4
0
class TestCdcOp():
    def setup_method(self, function):
        self.api = HXWalletApi(name=function.__name__, rpc_url=HX_TESTNET_RPC)
        self.cdc = CDCOperation(USER1['account'], CDC_CONTRACT_ID, self.api)

    def teardown_function(self):
        self.api = None
        self.cdc = None

    def test_info(self):
        info = self.cdc.get_contract_info()
        info = json.loads(info)
        assert(info['admin'] == 'HXNWj42PcH3Q2gEQ9GnVV2y87qsXd8MCL85W')
        assert(info['proxy'] == 'HXCexPawducWo8S5uPTtMbzoN31tpxGxwV3H')
        assert(info['state'] == 'COMMON')
        assert(info['collateralAsset'] == 'BTC')
        assert(info['priceFeederAddr'] == 'HXCGba6bUaGeBtUQRGpHUePHVXzF1ygMAxR1')
        assert(info['stableTokenAddr'] == 'HXCcuGJV3cVnwMPk4S524ADcC9PWxRA3qKR2')
        assert(info['liquidationRatio'] == '1.25')
        assert(info['annualStabilityFee'] == '0.15')
        assert(info['liquidationPenalty'] == '0.13')
        assert(info['liquidationDiscount'] == '0.03')
        assert(info['annualStabilityFeeList'] == ["1564047710,0.15"])
        assert(int(info['totalLiquidationPenalty']) >= 0)
        assert(int(info['totalCollectedStablityFee']) >= 0)
示例#5
0
 def cdcTakeAction(self, arg):
     logging.debug(arg)
     cdcOp = CDCOperation(self.accountList.currentText(), self.collateral_contract, self.api)
     ret = ''
     if arg['action'] == 'Payback':
         ret = cdcOp.pay_back(arg['cdc_id'], arg['amount'])
     elif arg['action'] == 'Generate':
         ret = cdcOp.generate_stable_coin(arg['cdc_id'], arg['amount'])
     elif arg['action'] == 'AddCollateral':
         ret = cdcOp.add_collateral(arg['cdc_id'], arg['amount'])
     elif arg['action'] == 'Withdraw':
         ret = cdcOp.withdraw_collateral(arg['cdc_id'], arg['amount'])
     elif arg['action'] == 'Close':
         ret = cdcOp.close_cdc(arg['cdc_id'])
     elif arg['action'] == 'Liquidate':
         if arg['amount'] == '' or arg['amount2'] == '':
             QMessageBox.information(self, 'Info', \
                     'The CDC (ID: %s) cannot be liquidated.' % arg['cdc_id'])
             return
         self.cdcOp.liquidate(arg['cdc_id'], arg['amount'], arg['amount2'])
     else:
         pass
     if ret is None:
         retMessage = 'Fail to %s' % arg['action']
     else:
         retMessage = 'Success to %s' % arg['action']
     QMessageBox.information(self, 'Info', retMessage)
     logging.debug(ret)
示例#6
0
class PcmMainWindow(QMainWindow, Ui_MainWindow):
    sinScanStop = pyqtSignal()

    def __init__(self, parent=None):
        super(PcmMainWindow, self).__init__(parent)
        self.setupUi(self)

        self.config_file = './pcm_config.json'
        try:
            with open(self.config_file, "r") as f:
                self.config = json.load(f)
        except:
            self.config = {
                'url_index': 0,
                'environment': 'test',
                'test': {
                    'collateral_contract': 'HXCSSGDHqaJDLto13BSZpAbrZoJf4RrGCtks',
                    'price_feeder_account': 'senator0',
                    'price_feeder_contract': 'HXCGba6bUaGeBtUQRGpHUePHVXzF1ygMAxR1',
                    'usd_contract': ''
                },
                'production': {
                    'collateral_contract': 'HXCKbMNLRv1X9wtwus9Wsnd6vkz6NporbZ5L',
                    'price_feeder_account': 'senator0',
                    'price_feeder_contract': 'HXCHfD5WiSKb57rU5BLqSbz3uHRXdBvsy19B',
                    'usd_contract': 'HXCTmGbEzqYq2LADmxQ3tDHnADp1yp5L36ih'
                }
            }
        self.priceFeederAccount = self.config[self.config['environment']]['price_feeder_account']
        self.walletUrlBox.setCurrentIndex(self.config['url_index'])
        self.currentApiUrl = self.walletUrlBox.currentText()
        self.collateral_contract = self.config[self.config['environment']]['collateral_contract']
        self.api = HXWalletApi(name='PCM', rpc_url=self.currentApiUrl)
        self.accounts = []
        self.initWidgets()
        self._refreshAccountList()
        self.priceFeeder = PriceFeeder(
            self.priceFeederAccount, \
            self.config[self.config['environment']]['price_feeder_contract'], \
            self.api)
        self.syncThread = DataSyncThread(self.api, self.collector, self.cdcOp)
        self.sinScanStop.connect(self.syncThread.stop)
        self.syncThread.sinSyncState.connect(self.syncStateChange)
        self.syncThread.start()

    def initWidgets(self):
        self.btnRefresh.clicked.connect(self.refreshCdcs)
        self.btnChangeRatio.clicked.connect(lambda: self.cdcManagementAction(0))
        self.btnChangeFee.clicked.connect(lambda: self.cdcManagementAction(1))
        self.btnChangePenalty.clicked.connect(lambda: self.cdcManagementAction(2))
        self.btnChangeDiscount.clicked.connect(lambda: self.cdcManagementAction(3))
        self.btnChangePrice.clicked.connect(lambda: self.cdcManagementAction(4))
        self.btnOpenCdc.clicked.connect(self.openCdcDialog)
        self.cdcModel = QStandardItemModel(5,6)
        self.cdcModel.setHorizontalHeaderLabels(['CDC ID','BTC','HUSD', 'Stability Fee', 'state', 'block number'])
        self.tableView.setModel(self.cdcModel)
        self.tableView.doubleClicked.connect(lambda: self.existedCdcAction(0))
        self.btnPayback.clicked.connect(lambda: self.existedCdcAction(0))#'Payback'
        self.btnGenerate.clicked.connect(lambda: self.existedCdcAction(1))#'Generate'
        self.btnAdd.clicked.connect(lambda: self.existedCdcAction(2))#'AddCollateral'
        self.btnWithdraw.clicked.connect(lambda: self.existedCdcAction(3))#'Withdraw'
        self.btnLiquidate.clicked.connect(lambda: self.existedCdcAction(4))#'Liquidate'
        self.btnCloseCdc.clicked.connect(lambda: self.existedCdcAction(5))#'Close'
        self.collateralContractList.addItem(self.collateral_contract)
        self.walletUrlBox.currentIndexChanged.connect(self.changeUrl)

    def changeUrl(self):
        self.config['url_index'] = self.walletUrlBox.currentIndex()
        if self.config['url_index'] == 2:
            self.config['environment'] = 'production'
        else:
            self.config['environment'] = 'test'
        QMessageBox.information(self, 'Info', \
                        'URL changed. Restart Application to take effect.')
        

    def _refreshAccountList(self):
        self.accountList.clear()
        accounts = self.api.rpc_request('list_my_accounts', [])
        if accounts is None:
            return
        self.accounts = accounts
        self.collector = EventsCollector(self.accounts[0]['name'], self.collateral_contract, self.api)
        self.cdcOp = CDCOperation(self.accounts[0]['name'], self.collateral_contract, self.api)
        self.accountList.currentIndexChanged.connect(self.accountChange)
        self.priceFeederExist = False
        for a in self.accounts:
            if self.priceFeederAccount == a['name']:
                self.priceFeederExist = True
            self.accountList.addItem(a['name'])
        if not self.priceFeederExist:
            self.priceFeederAccount = self.accounts[0]['name']

    def cdcManagementAction(self, op):
        if not self.priceFeederExist:
            QMessageBox.warning(self, 'Warning', \
                        'No price feeder account in wallet.')
            return
        if op == 0:
            logging.debug('btnChangeRatio clicked')
            adminOp = CDCOperation(self.priceFeederAccount, self.collateral_contract, self.api)
            adminOp.set_liquidation_ratio(self.liquidationRatio.text())
        elif op == 1:
            logging.debug('btnChangeFee clicked')
            adminOp = CDCOperation(self.priceFeederAccount, self.collateral_contract, self.api)
            adminOp.set_annual_stability_fee(self.annualStabilityFee.text())
        elif op == 2:
            logging.debug('btnChangePenalty clicked')
            adminOp = CDCOperation(self.priceFeederAccount, self.collateral_contract, self.api)
            adminOp.set_liquidation_penalty(self.liquidationPenalty.text())
        elif op == 3:
            logging.debug('btnChangeDiscount clicked')
            adminOp = CDCOperation(self.priceFeederAccount, self.collateral_contract, self.api)
            adminOp.set_liquidation_discount(self.liquidationDiscount.text())
        elif op == 4:
            logging.debug('btnChangePrice clicked')
            self.priceFeeder.feed_price(self.currentPrice.text())
        else:
            logging.warning('unknown button is clicked')

    def openCdcDialog(self):
        dlg = OpenCdcDialog()
        dlg.openCdcSignal.connect(self.openCdcAction)
        dlg.exec_()

    def openCdcAction(self, arg):
        result = self.cdcOp.open_cdc(arg['btcAmount'], arg['usdAmount'])
        if result is not None and "trxid" in result:
            QMessageBox.information(self,"Success", "Open CDC success (%s)!" % result['trxid'])
        else:
            QMessageBox.warning(self,"Error", "Open CDC fail!")

    def existedCdcAction(self, action=0):
        r = self.tableView.currentIndex().row()
        if r < 0:
            QMessageBox.information(self, 'Info', 'Please select a CDC')
            return
        liquidateInfo = self.cdcOp.get_liquidable_info(self.cdcModel.data(self.cdcModel.index(r, 0)))
        if liquidateInfo is None:
            QMessageBox.information(self, 'Info', "Cannot get liquidation info, please retry later")
            return
        liquidateInfo = json.loads(liquidateInfo)
        if action == 4:
            if self.cdcModel.data(self.cdcModel.index(r, 4)) != 'OPEN':
                QMessageBox.information(self, 'Info', \
                    'The CDC (ID: %s) is [%s].' % (self.cdcModel.data(self.cdcModel.index(r, 0)), \
                        self.cdcModel.data(self.cdcModel.index(r, 4))))
            else:
                if not liquidateInfo['isNeedLiquidation'] or liquidateInfo['isBadDebt']:
                    QMessageBox.information(self, 'Info', \
                        'The CDC (ID: %s) cannot be liquidated.' % self.cdcModel.data(self.cdcModel.index(r, 0)))
            return
        data = {
            'cdc_id': self.cdcModel.data(self.cdcModel.index(r, 0)),
            'state': self.cdcModel.data(self.cdcModel.index(r, 4)),
            'available_usd': self.hUSDLineEdit.text(),
            'available_btc': self.bTCLineEdit.text(),
            'price': self.currentPrice.text(),
            'action': action,
            'liquidate': liquidateInfo
        }
        logging.debug(str(data))
        dlg = CDCOperationsDialog(args=data, parent=self)
        dlg.cdcOpSignal.connect(self.cdcTakeAction)
        dlg.exec_()

    def cdcTakeAction(self, arg):
        logging.debug(arg)
        cdcOp = CDCOperation(self.accountList.currentText(), self.collateral_contract, self.api)
        ret = ''
        if arg['action'] == 'Payback':
            ret = cdcOp.pay_back(arg['cdc_id'], arg['amount'])
        elif arg['action'] == 'Generate':
            ret = cdcOp.generate_stable_coin(arg['cdc_id'], arg['amount'])
        elif arg['action'] == 'AddCollateral':
            ret = cdcOp.add_collateral(arg['cdc_id'], arg['amount'])
        elif arg['action'] == 'Withdraw':
            ret = cdcOp.withdraw_collateral(arg['cdc_id'], arg['amount'])
        elif arg['action'] == 'Close':
            ret = cdcOp.close_cdc(arg['cdc_id'])
        elif arg['action'] == 'Liquidate':
            if arg['amount'] == '' or arg['amount2'] == '':
                QMessageBox.information(self, 'Info', \
                        'The CDC (ID: %s) cannot be liquidated.' % arg['cdc_id'])
                return
            self.cdcOp.liquidate(arg['cdc_id'], arg['amount'], arg['amount2'])
        else:
            pass
        if ret is None:
            retMessage = 'Fail to %s' % arg['action']
        else:
            retMessage = 'Success to %s' % arg['action']
        QMessageBox.information(self, 'Info', retMessage)
        logging.debug(ret)

    def closeEvent(self, e):
        self.sinScanStop.emit()
        self.syncThread.wait()
        with open(self.config_file, 'w') as wf:
            json.dump(self.config, wf)

    def accountChange(self, i):
        account = self.accounts[i]
        self.addressLineEdit.setText(account['addr'])
        balances = self.api.rpc_request('get_account_balances', [account['name']])
        account['balances'] = balances
        for b in account['balances']:
            if b['asset_id'] == '1.3.0':
                self.hXLineEdit.setText(convertCoinWithPrecision(b['amount'], 5))
            elif b['asset_id'] == '1.3.1':
                self.bTCLineEdit.setText(convertCoinWithPrecision(b['amount']))
        usdBalance = self.api.rpc_request('invoke_contract_offline', [account['name'], 'HXCcuGJV3cVnwMPk4S524ADcC9PWxRA3qKR2', 'balanceOf', account['addr']])
        self.hUSDLineEdit.setText(convertCoinWithPrecision(0 if usdBalance is None else usdBalance ))
        cdcs = self.collector.query_cdc_by_address(account['addr'])
        self.cdcModel.removeRows(0, self.cdcModel.rowCount())
        for r in range(len(cdcs)):
            self.cdcModel.setItem(r, 0, QStandardItem(cdcs[r].cdc_id))
            self.cdcModel.setItem(r, 1, QStandardItem(convertCoinWithPrecision(cdcs[r].collateral_amount)))
            self.cdcModel.setItem(r, 2, QStandardItem(convertCoinWithPrecision(cdcs[r].stable_token_amount)))
            logging.debug("----------------------"+str(cdcs[r].stable_token_amount))
            self.cdcModel.setItem(r, 3, QStandardItem('N/A'))
            if cdcs[r].state == 1:
                self.cdcModel.setItem(r, 4, QStandardItem('OPEN'))
                #FIXME, database is not updated. The CLOSED cdc query from chain will return None.
                cdcInfo = self.cdcOp.get_cdc(cdcs[r].cdc_id)
                if cdcInfo is None:
                    continue
                cdcInfo = json.loads(cdcInfo)
                self.cdcModel.setItem(r, 3, QStandardItem(convertCoinWithPrecision(cdcInfo['stabilityFee'])))
            elif cdcs[r].state == 2:
                self.cdcModel.setItem(r, 4, QStandardItem('LIQUIDATED'))
            elif cdcs[r].state == 3:
                self.cdcModel.setItem(r, 4, QStandardItem('CLOSED'))
            self.cdcModel.setItem(r, 5, QStandardItem(str(cdcs[r].block_number)))
        self.tableView.resizeColumnsToContents()
        self.tableView.resizeRowsToContents()
    
    def refreshCdcs(self):
        self.accountChange(self.accountList.currentIndex())

    def syncStateChange(self, stateChange):
        if stateChange['syncType'] == SYNC_STATE_TYPE:
            # self.syncLabel.setText(stateChange['data'])
            # self.syncLabel.adjustSize()
            self.statusBar().showMessage(stateChange['data'])
        elif stateChange['syncType'] == SYNC_CONTRACT_TYPE:
            self.cdcContractInfo = stateChange['data']
            self.collateralAdmin.setText(self.cdcContractInfo['admin'])
            self.collateralAsset.setText(self.cdcContractInfo['collateralAsset'])
            self.liquidationRatio.setText(self.cdcContractInfo['liquidationRatio'])
            self.annualStabilityFee.setText(self.cdcContractInfo['annualStabilityFee'])
            self.liquidationPenalty.setText(self.cdcContractInfo['liquidationPenalty'])
            self.liquidationDiscount.setText(self.cdcContractInfo['liquidationDiscount'])
            self.currentPrice.setText(self.priceFeeder.get_price())
示例#7
0
 def cdcManagementAction(self, op):
     if not self.priceFeederExist:
         QMessageBox.warning(self, 'Warning', \
                     'No price feeder account in wallet.')
         return
     if op == 0:
         logging.debug('btnChangeRatio clicked')
         adminOp = CDCOperation(self.priceFeederAccount, self.collateral_contract, self.api)
         adminOp.set_liquidation_ratio(self.liquidationRatio.text())
     elif op == 1:
         logging.debug('btnChangeFee clicked')
         adminOp = CDCOperation(self.priceFeederAccount, self.collateral_contract, self.api)
         adminOp.set_annual_stability_fee(self.annualStabilityFee.text())
     elif op == 2:
         logging.debug('btnChangePenalty clicked')
         adminOp = CDCOperation(self.priceFeederAccount, self.collateral_contract, self.api)
         adminOp.set_liquidation_penalty(self.liquidationPenalty.text())
     elif op == 3:
         logging.debug('btnChangeDiscount clicked')
         adminOp = CDCOperation(self.priceFeederAccount, self.collateral_contract, self.api)
         adminOp.set_liquidation_discount(self.liquidationDiscount.text())
     elif op == 4:
         logging.debug('btnChangePrice clicked')
         self.priceFeeder.feed_price(self.currentPrice.text())
     else:
         logging.warning('unknown button is clicked')
示例#8
0
def testover(usersNum,cdc_address, mainAccount,loopnum,filepath,account_name_prefix,closeAllCdcsAtEnd):
    createAccounts(account_name_prefix,usersNum)

    if(mainAccount not in accountNames.keys()):
        raise RuntimeError('error!!! mainAccount not in accountNames')
    mainAccountAddr = accountNames[mainAccount]
    cdcUsers = []

    cdcTrxsCount = 0
    liquidateCount = 0
    contract_info = json.loads(CDCOperation(mainAccount, cdc_address, wallet_api).get_contract_info())

    cdc_admin_addr = contract_info['admin']
    priceFeederAddr = contract_info['priceFeederAddr']
    stableTokenAddr = contract_info['stableTokenAddr']
    collateralAsset = contract_info['collateralAsset']
    liquidationRatio = float(contract_info['liquidationRatio'])

    cdc_admin = accounts[cdc_admin_addr]
    cdcAdmin = CDCOperation(cdc_admin, cdc_address, wallet_api)
    priceFeederUser = PriceFeeder(cdc_admin,priceFeederAddr,wallet_api)
    feeders = json.loads(priceFeederUser.get_feeders())
    price_feeder = accounts[feeders[0]]
    priceFeeder = PriceFeeder(price_feeder,priceFeederAddr,wallet_api)

    cdcAdmin.set_annual_stability_fee("15")
    time.sleep(5)

    pricestr = priceFeeder.get_price()
    price = float(pricestr)
    initprice = price
    hign_price = initprice*2
    low_price = initprice/2
    print("initprice:" + str(initprice))

    origAdminToken = token_balanceOf(stableTokenAddr,cdc_admin)
    if(origAdminToken < 10000):
        raise RuntimeError("orig admin stable token balance must >= 10000")
    ######### add users/admin hx , empty users/tempaccount BTC
    hxAmount = 10
    mainAccountBalances = get_account_balances(mainAccount, wallet_api) # mainAccount hx must >= 1000
    if("HX" not in mainAccountBalances.keys() or mainAccountBalances["HX"] < 1000*100000):
        raise RuntimeError("mainAccount has no hx balance or balance < 1000")
    hxbalance = mainAccountBalances["HX"]
    hxAmount = int(hxbalance / (usersNum + 2))
    dhxAmount = convertCoinWithPrecision(hxAmount,5)

    origStableTokenSupply = token_supply(stableTokenAddr,mainAccount)

    cdcAdminBalances = get_account_balances(cdc_admin, wallet_api)
    if (("HX" not in cdcAdminBalances.keys()) or cdcAdminBalances["HX"] < hxAmount):
        wallet_api.rpc_request('transfer_to_address',
                               [mainAccount, cdc_admin_addr, dhxAmount, "HX", "", 0.0001, 100000, True])
    if (collateralAsset in cdcAdminBalances.keys()):
        amount = cdcAdminBalances[collateralAsset]
        if (amount > 0 and cdc_admin!= mainAccount):
            wallet_api.rpc_request('transfer_to_address',
                                   [cdc_admin, mainAccountAddr, convertCoinWithPrecision(amount), collateralAsset, "",
                                    0.0001, 100000,True])

    for i in range(0, usersNum):
        user = account_name_prefix + str(i)
        cdcUsers.append(CDCOperation(user, cdc_address, wallet_api))
        userAddr = accountNames[user]
        userBalances = get_account_balances(user,wallet_api)
        if(("HX" not in userBalances.keys()) or userBalances["HX"] < hxAmount):
            wallet_api.rpc_request('transfer_to_address',
                                   [mainAccount, userAddr, dhxAmount, "HX", "", 0.0001, 100000, True])

        if(collateralAsset in userBalances.keys()):
            amount = userBalances[collateralAsset]
            if(amount > 0):
                wallet_api.rpc_request('transfer_to_address',
                                       [user, mainAccountAddr, convertCoinWithPrecision(amount), collateralAsset, "", 0.0001, 100000,
                                        True])

    time.sleep(6)

    ############### transfer users/admin btc   mainAccount btc must >= 1
    mainAccountBalances = get_account_balances(mainAccount, wallet_api)
    if (collateralAsset not in mainAccountBalances.keys() or mainAccountBalances[collateralAsset]<100000000):
        raise RuntimeError("mainAccount has no collateralAsset balance")
    balance = mainAccountBalances[collateralAsset]
    collateralAmount = int(balance/(usersNum+2))
    if(collateralAmount <= 0):
        raise RuntimeError("collateralAmount <=0 " )
    print("avg user collateralAmount is "+str(collateralAmount))

    dCollateralAmount = convertCoinWithPrecision(collateralAmount)
    for i in range(0, usersNum):
        user = account_name_prefix + str(i)
        userAddr = accountNames[user]
        wallet_api.rpc_request('transfer_to_address',
                               [mainAccount, userAddr, dCollateralAmount, collateralAsset, "", 0.0001, 100000, True])
    if(cdc_admin != mainAccount):
        wallet_api.rpc_request('transfer_to_address',
                           [mainAccount, cdc_admin_addr, dCollateralAmount, collateralAsset, "", 0.0001, 100000, True])
    time.sleep(5)

    cdcAdmin.set_annual_stability_fee("15")

    p = pathlib.Path(filepath)
    if(not p.is_file()):
        fd = open(filepath, mode="w", encoding="utf-8")
        fd.close()
    else:
        with open(filepath, 'r') as f:
            global cdcs
            try:
                cdcs = json.load(f)
            except BaseException as e:
                logging.error(str(e))


    openCdc(cdc_admin,cdcAdmin,collateralAsset,price,liquidationRatio,filepath,True)

    # loop
    for i in range(0,loopnum):
        pricestr = priceFeeder.get_price()
        price = float(pricestr)

        # rand
        randnum = random.randint(0, usersNum - 1)
        randUser = account_name_prefix + str(randnum)
        randCdcUser = cdcUsers[randnum]

        op = random.randint(0,5)
        if(len(cdcs) < (usersnum*2/3)):
            op = 0
        opRes = False
        if(op==0):
            opRes=openCdc(randUser, randCdcUser, collateralAsset, price, liquidationRatio, filepath)
        elif(op==1):
            opRes=addCollateral(randUser, randCdcUser, collateralAsset)
        elif (op == 2):
            opRes=widrawCollateral(randUser,randCdcUser,price,liquidationRatio)
        elif (op == 3):
            opRes=pay_back(randUser,randCdcUser,stableTokenAddr,cdc_admin)
        elif(op ==4):
            opRes=expandLoan(randUser,randCdcUser,price,liquidationRatio)
        elif(op >= 5):
            opRes=close_cdc(randUser,randCdcUser,stableTokenAddr,cdc_admin,filepath)


        ##########################
        # liquidate
        '''
        if(i%4 == 3):
            time.sleep(5)
            count = checkAndLiquidate(usersnum,account_name_prefix,stableTokenAddr,filepath,cdcUsers,cdc_admin)
            liquidateCount = liquidateCount + count
        '''

        # feed price #######################################################################
        if(opRes):
            cdcTrxsCount = cdcTrxsCount + 1
            newprice = price
            if (price > hign_price):
                newprice = price * 0.92
            elif (price < low_price):
                newprice = price * 1.09
            else:
                randf = random.uniform(-0.0999, 0.0999)  # 含首尾
                newprice = price + price * randf
            newpricestr = str(newprice)

            r = priceFeeder.feed_price(newpricestr)
            if (r is not None):
                print("feed new price:" + newpricestr)
            time.sleep(5)

    cdcAdmin.set_annual_stability_fee("0.15")

    currentStableTokenSupply = token_supply(stableTokenAddr,mainAccount)
    totalCdcStableTokenAmount = 0
    for user,cdc in cdcs.items():
        result = cdcAdmin.get_cdc(cdc['trxid'])
        if result is not None:
            cdcinfo = json.loads(result)
            stableTokenAmount = int(cdcinfo['stableTokenAmount'])
            totalCdcStableTokenAmount = totalCdcStableTokenAmount + stableTokenAmount
    print("all cdcs:")
    print(cdcs)
    print("origStableTokenSupply:" + str(origStableTokenSupply))
    print("totalCdcStableTokenAmount:" + str(totalCdcStableTokenAmount))
    print("currentStableTokenSupply:"+str(currentStableTokenSupply))

    print("liquidateCount:" + str(liquidateCount))
    print("cdcTrxsCount:" + str(cdcTrxsCount))
    if((totalCdcStableTokenAmount + origStableTokenSupply) != currentStableTokenSupply):
        raise RuntimeError("error !!!!! (totalCdcStableTokenAmount + origStableTokenSupply) != currentStableTokenSupply")

    if(closeAllCdcsAtEnd):
        print("try close all cdcs at end:")
        closeAllUsersCdcs(usersnum, account_name_prefix, filepath, mainAccount)
示例#9
0
def closeAllUsersCdcs(usersNum,account_name_prefix,filepath,mainAccount):
    global cdcs
    if(len(cdcs) == 0):
        try:
            with open(filepath, 'r') as load_f:
                cdcs = json.load(load_f)
        except BaseException as e:
            logging.error(str(e))

    cdcUsers = []
    if(len(cdcs)==0):
        print("closeAllUsersCdcs , no cdcs!!!!")
        #return
    else:
        for i in range(0, usersNum):
            user = account_name_prefix + str(i)
            cdcUsers.append(CDCOperation(user, cdc_address, wallet_api))

    get_my_accounts()

    contract_info = json.loads(CDCOperation(mainAccount, cdc_address, wallet_api).get_contract_info())

    cdc_admin_addr = contract_info['admin']
    priceFeederAddr = contract_info['priceFeederAddr']
    stableTokenAddr = contract_info['stableTokenAddr']
    collateralAsset = contract_info['collateralAsset']
    liquidationRatio = float(contract_info['liquidationRatio'])
    annualStabilityFee = float(contract_info['annualStabilityFee'])

    YEARSECS = 31536000

    cdc_admin = accounts[cdc_admin_addr]
    cdcAdmin = CDCOperation(cdc_admin, cdc_address, wallet_api)
    priceFeederUser = PriceFeeder(cdc_admin, priceFeederAddr, wallet_api)
    feeders = json.loads(priceFeederUser.get_feeders())
    price_feeder = accounts[feeders[0]]
    priceFeeder = PriceFeeder(price_feeder, priceFeederAddr, wallet_api)


    fromuser = cdc_admin
    cdcFromUser = cdcAdmin

    origStableTokenSupply = token_supply(stableTokenAddr,mainAccount)

    totalDestoryedStableTokenAmount = 0
    lenPrefix = len(account_name_prefix)
    origcdcs = copy.deepcopy(cdcs)
    time.sleep(5)
    for user in origcdcs.keys():
        if(user.startswith(account_name_prefix)):
            i = int(user[lenPrefix:])
            cdcUser = cdcUsers[i]
            trxid = origcdcs[user]['trxid']
            result = cdcUser.get_cdc(trxid)
            if (result is not None):
                cdcinfo = json.loads(result)
                if(len(cdcinfo)==0):
                    continue
                collateralAmount = int(cdcinfo['collateralAmount'])
                stabilityFee = int(cdcinfo['stabilityFee'])
                stableTokenAmount = int(cdcinfo['stableTokenAmount'])
                isNeedLiquidation = cdcinfo['isNeedLiquidation']
                totalNeedPayAmount = stableTokenAmount + stabilityFee
                if (totalNeedPayAmount > 0):
                    tokenbalance = token_balanceOf(stableTokenAddr, user)
                    if (totalNeedPayAmount > tokenbalance):
                        fromusertokenbalance = token_balanceOf(stableTokenAddr, fromuser)
                        if(fromusertokenbalance <= (totalNeedPayAmount - tokenbalance)):
                            price = float(priceFeeder.get_price())
                            addCollateral(fromuser,cdcFromUser,collateralAsset)
                            #time.sleep(5)
                            expandLoan(fromuser,cdcFromUser,price,liquidationRatio)
                            #time.sleep(5)
                        r = token_transfer(stableTokenAddr, fromuser, user, (totalNeedPayAmount - tokenbalance + int(stableTokenAmount*20/YEARSECS*annualStabilityFee) ))
                        #if r is not None:
                            #time.sleep(5)
                        result = cdcUser.close_cdc(trxid)
                        if result is not None:
                            print("close_cdc txid:" + trxid + " user:"******" totalNeedPayAmount:" + str(
                                    totalNeedPayAmount)+" stableTokenAmount:"+str(stableTokenAmount))
                            totalDestoryedStableTokenAmount = totalDestoryedStableTokenAmount+stableTokenAmount
                            del cdcs[user]
                            with open(filepath, 'w') as f:
                                json.dump(cdcs, f)
                        else:
                            print("close_cdc fail !!! txid:" + trxid + " user:"******" totalNeedPayAmount:" + str(
                                totalNeedPayAmount) + " stableTokenAmount:" + str(stableTokenAmount))




    if (cdc_admin in cdcs.keys() and "trxid" in cdcs[cdc_admin].keys()):
        trxid = cdcs[cdc_admin]['trxid']
        result = cdcAdmin.get_cdc(trxid)
        if (result is not None):
            cdcinfo = json.loads(result)
            #collateralAmount = cdcinfo['collateralAmount']
            stabilityFee = int(cdcinfo['stabilityFee'])
            stableTokenAmount = int(cdcinfo['stableTokenAmount'])
            #isNeedLiquidation = cdcinfo['isNeedLiquidation']
            totalNeedPayAmount = stableTokenAmount + stabilityFee
            result = cdcAdmin.close_cdc(trxid)
            if result is not None:
                print("close_cdc admin txid:" + trxid + " user:"******" totalNeedPayAmount:" + str(
                    totalNeedPayAmount)+" stableTokenAmount:"+str(stableTokenAmount))
                totalDestoryedStableTokenAmount = totalDestoryedStableTokenAmount + stableTokenAmount
                del cdcs[cdc_admin]
                with open(filepath, 'w') as f:
                    json.dump(cdcs, f)
            else:
                print("close_cdc fail !!! txid:" + trxid + " user:"******" totalNeedPayAmount:" + str(
                    totalNeedPayAmount) + " stableTokenAmount:" + str(stableTokenAmount))


    time.sleep(5)
    for i in range(0,usersnum):
        user = account_name_prefix + str(i)
        tokenbalance = token_balanceOf(stableTokenAddr, user)
        if(tokenbalance > 0):
            r = token_transfer(stableTokenAddr, user, fromuser, tokenbalance)

    currentStableTokenSupply = token_supply(stableTokenAddr, mainAccount)
    totalCdcStableTokenAmount = 0
    for user, cdc in cdcs.items():
        result = cdcAdmin.get_cdc(cdc['trxid'])
        if result is not None:
            cdcinfo = json.loads(result)
            if(len(cdcinfo)==0):
                continue
            stableTokenAmount = int(cdcinfo['stableTokenAmount'])
            totalCdcStableTokenAmount = totalCdcStableTokenAmount + stableTokenAmount

    print(cdcs)
    print("totalDestoryedStableTokenAmount:"+str(totalDestoryedStableTokenAmount))
    print("origStableTokenSupply:" + str(origStableTokenSupply))
    print("now totalCdcStableTokenAmount:" + str(totalCdcStableTokenAmount))
    print("currentStableTokenSupply:" + str(currentStableTokenSupply))
    if ((origStableTokenSupply - totalDestoryedStableTokenAmount) != currentStableTokenSupply):
        raise RuntimeError("error !!!!! (origStableTokenSupply - totalDestoryedStableTokenAmount) != currentStableTokenSupply")
    if(totalCdcStableTokenAmount > 0):
        raise RuntimeError("error!!! close all cdcs fail!!!")

    cdcAdmin.set_annual_stability_fee("0.15")

    ###################### transfer all users HX,BTC to mainAccount  ##################################################################
    print("transfer all users HX,BTC to mainAccount")
    mainAccountAddr = accountNames[mainAccount]
    for i in range(0, usersNum):
        user = account_name_prefix + str(i)
        #userAddr = accountNames[user]
        userBalances = get_account_balances(user,wallet_api)
        if (collateralAsset in userBalances.keys()):
            amount = userBalances[collateralAsset]
            if (amount > 0):
                wallet_api.rpc_request('transfer_to_address',
                                       [user, mainAccountAddr, convertCoinWithPrecision(amount), collateralAsset, "",
                                        0.0001, 100000,
                                        True])

        if(("HX" in userBalances.keys()) and userBalances["HX"] > HXPRECISION):
            dhxAmount = (userBalances["HX"]-HXPRECISION)/HXPRECISION
            wallet_api.rpc_request('transfer_to_address',
                                   [user, mainAccountAddr, dhxAmount, "HX", "", 0.0001, 100000, True])

    adminBalances = get_account_balances(cdc_admin, wallet_api)
    if (collateralAsset in adminBalances.keys()):
        amount = adminBalances[collateralAsset]
        if (amount > 0):
            wallet_api.rpc_request('transfer_to_address',
                                   [cdc_admin, mainAccountAddr, convertCoinWithPrecision(amount), collateralAsset, "",
                                    0.0001, 100000,
                                    True])

    if (("HX" in adminBalances.keys()) and userBalances["HX"] > HXPRECISION):
        dhxAmount = (adminBalances["HX"] - HXPRECISION) / HXPRECISION
        wallet_api.rpc_request('transfer_to_address',
                               [cdc_admin, mainAccountAddr, dhxAmount, "HX", "", 0.0001, 100000, True])
示例#10
0
class Cdc_Liquidate():
    def __init__(self, wallet_api, db_path, cdc_contract_address, account,
                 stableTokenPrecision, collateralPrecision, session, symbol,
                 logger):
        self.wallet_api = wallet_api
        self.symbol = symbol
        #Base = declarative_base()
        #Base.metadata.create_all(engine)
        self.is_running = False
        self.Session = session
        self.account = account
        self.cdc_contract_address = cdc_contract_address
        self.stableTokenPrecision = stableTokenPrecision
        self.collateralPrecision = collateralPrecision
        self.liquidator = CDCOperation(account, cdc_contract_address,
                                       self.wallet_api, self.symbol)
        self.logger = logger

        account_addr = self.wallet_api.rpc_request("get_account_addr",
                                                   [account])
        if (account_addr is None):
            raise RuntimeError("address is None, account:" + str(account))
        self.account_addr = account_addr
        rstr = self.wallet_api.rpc_request(
            'invoke_contract_offline',
            [self.account, self.cdc_contract_address, "getInfo", ""])
        cdc_contract_info = json.loads(rstr)
        self.stableTokenAddr = cdc_contract_info["stableTokenAddr"]
        self.priceFeederAddr = cdc_contract_info["priceFeederAddr"]

    def scan_liquidate(self, session):
        r = session.execute("select * from cdcs where state=1")
        cdcs = r.fetchall()
        count = len(cdcs)
        if (count <= 0):
            self.logger.info("no need to start.")
            return

        balance = int(
            self.wallet_api.rpc_request('invoke_contract_offline', [
                self.account, self.stableTokenAddr, "balanceOf",
                self.account_addr
            ]))
        if (balance <= 0):
            raise RuntimeError("balance <= 0")

        for cdc in cdcs:
            c = CdcTable()
            cdcId = cdc['cdcId']
            resultstr = self.liquidator.get_liquidable_info(cdcId)
            if (resultstr is None):
                continue
            info = json.loads(resultstr)
            if (info['isNeedLiquidation'] and (not info['isBadDebt'])):
                ##liquidate
                repayStableTokenAmount = int(info['repayStableTokenAmount'])
                auctionCollateralAmount = int(info['auctionCollateralAmount'])
                if (balance < repayStableTokenAmount):
                    self.logger.error("not enough balance ,balance:" +
                                      str(balance) +
                                      " need repayStableTokenAmount:" +
                                      str(repayStableTokenAmount))
                else:
                    self.logger.info("need to liguidate the cdcid:" + cdcId)
                    liquidateResult = self.liquidator.liquidate(
                        cdcId,
                        repayStableTokenAmount / self.stableTokenPrecision,
                        auctionCollateralAmount / self.collateralPrecision)
                    if (liquidateResult is None):
                        self.logger.error("liquidate fail ; cdcId" + cdcId +
                                          "liquidator:" + self.account +
                                          " need repayStableTokenAmount:" +
                                          str(repayStableTokenAmount))
                    else:
                        balance = balance - repayStableTokenAmount

    def run(self):
        session = self.Session()
        try:
            self.is_running = True
            while self.is_running == True:
                self.scan_liquidate(session)
                time.sleep(5)
        except BaseException as e:
            logging.error(str(e))
            traceback.print_exc()
        finally:
            session.close()

    def stop(self):
        self.is_running = False
示例#11
0
 def setup_method(self, function):
     self.api = HXWalletApi(name="TestHdaoEvents", rpc_url=HX_TESTNET_RPC)
     self.cdcOp = CDCOperation(USER1['account'], CDC_CONTRACT_ID, self.api)
     self.collector = EventsCollector(USER1['account'], CDC_CONTRACT_ID,
                                      self.api)
示例#12
0
class TestHdaoEvents():
    @classmethod
    def setup_class(cls):
        pass

    @classmethod
    def teardown_class(cls):
        pass

    def setup_method(self, function):
        self.api = HXWalletApi(name="TestHdaoEvents", rpc_url=HX_TESTNET_RPC)
        self.cdcOp = CDCOperation(USER1['account'], CDC_CONTRACT_ID, self.api)
        self.collector = EventsCollector(USER1['account'], CDC_CONTRACT_ID,
                                         self.api)

    def teardown_function(self):
        self.api = None
        self.collector = None
        self.cdc = None

    # def test_collect(self):
    #     self.collector.collect_event(969234)

    def test_cdc_query(self):
        cdcs = self.collector.query_cdc_by_address(
            'HXNUeoaUVkUg9q2uokDwzdrxp1uE4L9VhTSs')
        assert (len(cdcs) >= 1)
        assert (cdcs[0].cdc_id == '0694d145b7000d8d5b13f9f4c4acbee3533ca14a')

    def test_cdc_op_query(self):
        cdcs = self.collector.query_cdc_op_by_id(
            'ee80006bb468a434af71c38cb62e1afac6a51c52')
        assert (len(cdcs) == 2)
        assert (cdcs[0].cdc_id == 'ee80006bb468a434af71c38cb62e1afac6a51c52')

    def test_cdc_normal_operations(self):
        info = self.api.rpc_request("info", [])
        block_num = info['head_block_num']
        result = self.cdcOp.open_cdc(0.001, 0.001)
        assert ("trxid" in result and result["trxid"] != "")
        confirmed = False
        cdc = None
        while not confirmed:
            time.sleep(3)
            self.collector.collect_event(block_num)
            cdcs = self.collector.query_cdc_by_address(USER1['address'])
            for c in cdcs:
                if c.block_number > block_num:
                    confirmed = True
                    cdc = c
                    break
        assert (cdc.collateral_amount == '100000'
                and cdc.collateral_amount == '100000')
        previousCdcId = cdc.cdc_id
        self.cdcOp.close_cdc(cdc.cdc_id)
        confirmed = False
        waitTimes = 0
        with pytest.raises(AssertionError):
            while waitTimes < 10:
                time.sleep(3)
                self.collector.collect_event(block_num)
                cdcs = self.collector.query_cdc_by_address(USER1['address'])
                for c in cdcs:
                    if c.cdc_id == previousCdcId:
                        if c.state == 3:
                            raise AssertionError
                        break
示例#13
0
class Cdc_Liquidate_Robot(threading.Thread):
    def __init__(self, wallet_rpc_url, db_path, cdc_contract_address, account,
                 stableTokenPrecision, collateralPrecision):
        threading.Thread.__init__(self)
        self.wallet_api = HXWalletApi(name='events', rpc_url=wallet_rpc_url)
        #Base = declarative_base()
        engine = create_engine(db_path,
                               echo=True,
                               poolclass=SingletonThreadPool,
                               connect_args={'check_same_thread': False})
        #Base.metadata.create_all(engine)
        self.Session = sessionmaker(bind=engine)
        self.account = account
        self.cdc_contract_address = cdc_contract_address
        self.stableTokenPrecision = stableTokenPrecision
        self.collateralPrecision = collateralPrecision
        self.liquidator = CDCOperation(account, cdc_contract_address,
                                       self.wallet_api)
        account_addr = self.wallet_api.rpc_request("get_account_addr",
                                                   [account])
        if (account_addr is None):
            raise RuntimeError("address is None, account:" + str(account))
        self.account_addr = account_addr
        rstr = self.wallet_api.rpc_request(
            'invoke_contract_offline',
            [self.account, self.cdc_contract_address, "getInfo", ""])
        cdc_contract_info = json.loads(rstr)
        self.stableTokenAddr = cdc_contract_info["stableTokenAddr"]
        self.priceFeederAddr = cdc_contract_info["priceFeederAddr"]

    def scan_liquidate(self, session):
        r = session.execute('select * from cdcs where state=1')
        cdcs = r.fetchall()
        count = len(cdcs)
        if (count <= 0):
            return

        balance = int(
            self.wallet_api.rpc_request('invoke_contract_offline', [
                self.account, self.stableTokenAddr, "balanceOf",
                self.account_addr
            ]))
        if (balance <= 0):
            raise RuntimeError("balance <= 0")
            return

        for cdc in cdcs:
            c = CdcTable()
            cdcId = cdc['cdcId']
            resultstr = self.liquidator.get_liquidable_info(cdcId)
            if (resultstr is None):
                continue
            info = json.loads(resultstr)
            if (info['isNeedLiquidation'] and (not info['isBadDebt'])):
                ##liquidate
                repayStableTokenAmount = int(info['repayStableTokenAmount'])
                auctionCollateralAmount = int(info['auctionCollateralAmount'])
                if (balance < repayStableTokenAmount):
                    logging.error("not enough balance ,balance:" +
                                  str(balance) +
                                  " need repayStableTokenAmount:" +
                                  str(repayStableTokenAmount))
                else:
                    liquidateResult = self.liquidator.liquidate(
                        cdcId,
                        repayStableTokenAmount / self.stableTokenPrecision,
                        auctionCollateralAmount / self.collateralPrecision)
                    if (liquidateResult is None):
                        logging.error("liquidate fail ; cdcId" + cdcId +
                                      "liquidator:" + self.account +
                                      " need repayStableTokenAmount:" +
                                      str(repayStableTokenAmount))
                    else:
                        balance = balance - repayStableTokenAmount

    def run(self):
        try:
            session = self.Session()
            while (True):
                self.scan_liquidate(session)
                time.sleep(5)
        except BaseException as e:
            logging.error(str(e))
            traceback.print_exc()
        finally:
            session.close()
示例#14
0
 def setup_method(self, function):
     self.api = HXWalletApi(name=function.__name__, rpc_url=HX_TESTNET_RPC)
     self.cdc = CDCOperation(USER1['account'], CDC_CONTRACT_ID, self.api)