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 __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 _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']
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)
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)
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())
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 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)
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])
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
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)
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
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()
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)