def on_get(self, req, res): LOG.info("v2.market_information.GetAgreement") if config.IBET_SB_EXCHANGE_CONTRACT_ADDRESS is None and \ config.IBET_MEMBERSHIP_EXCHANGE_CONTRACT_ADDRESS is None and \ config.IBET_CP_EXCHANGE_CONTRACT_ADDRESS is None and \ config.IBET_SHARE_EXCHANGE_CONTRACT_ADDRESS is None: raise NotSupportedError(method="GET", url=req.path) # 入力値チェック request_json = self.validate(req) # リクエストから情報を抽出 order_id = request_json["order_id"] agreement_id = request_json["agreement_id"] exchange_address = to_checksum_address( request_json["exchange_address"]) # 取引コントラクトに接続 ExchangeContract, exchange = self.exchange_contracts(exchange_address) # 注文情報の取得 if exchange != "IbetOTCExchange": maker_address, token_address, _, _, is_buy, _, _ = \ ExchangeContract.functions.getOrder(order_id).call() else: maker_address, _, token_address, _, _, _, _ = \ ExchangeContract.functions.getOrder(order_id).call() is_buy = False if maker_address == config.ZERO_ADDRESS: raise InvalidParameterError("Data not found") # 約定情報の取得 taker_address, amount, price, canceled, paid, expiry = \ ExchangeContract.functions.getAgreement(order_id, agreement_id).call() if taker_address == config.ZERO_ADDRESS: raise InvalidParameterError("Data not found") if is_buy: buyer_address = maker_address seller_address = taker_address else: buyer_address = taker_address seller_address = maker_address res_data = { "token_address": token_address, # トークンアドレス "counterpart": taker_address, # Takerのアドレス "buyer_address": buyer_address, # 買い手EOA "seller_address": seller_address, # 売り手EOA "amount": amount, # 約定数量 "price": price, # 約定単価 "canceled": canceled, # 約定取消フラグ "paid": paid, # 支払済フラグ "expiry": expiry # 有効期限(unixtime) } self.on_success(res, res_data)
def on_post(self, req, res): LOG.info("v2.position.CouponConsumptions") session = req.context["session"] if config.COUPON_TOKEN_ENABLED is False: raise NotSupportedError(method="POST", url=req.path) # Validation request_json = CouponConsumptions.validate(req) # Create a list of coupon consumption history _coupon_address = to_checksum_address(request_json["token_address"]) coupon_consumptions = [] for _account_address in request_json["account_address_list"]: consumptions = session.query(IDXConsumeCoupon). \ filter(IDXConsumeCoupon.token_address == _coupon_address). \ filter(IDXConsumeCoupon.account_address == _account_address). \ all() for consumption in consumptions: coupon_consumptions.append({ "account_address": _account_address, "block_timestamp": consumption.block_timestamp.strftime("%Y/%m/%d %H:%M:%S"), "value": consumption.amount }) # Sort by block_timestamp in ascending order coupon_consumptions = sorted(coupon_consumptions, key=lambda x: x["block_timestamp"]) self.on_success(res, coupon_consumptions)
def on_post(self, req, res): LOG.info("v2.market_information.CouponLastPrice") if config.COUPON_TOKEN_ENABLED is False or config.IBET_CP_EXCHANGE_CONTRACT_ADDRESS is None: raise NotSupportedError(method="POST", url=req.path) request_json = CouponLastPrice.validate(req) ExchangeContract = Contract.get_contract( "IbetCouponExchange", config.IBET_CP_EXCHANGE_CONTRACT_ADDRESS) price_list = [] for token_address in request_json["address_list"]: try: last_price = ExchangeContract.functions. \ lastPrice(to_checksum_address(token_address)).call() except Exception as e: LOG.error(e) last_price = 0 price_list.append({ "token_address": token_address, "last_price": last_price }) self.on_success(res, price_list)
def on_post(self, req, res): LOG.info("v2.order_list.ShareOrderList") session = req.context["session"] if config.SHARE_TOKEN_ENABLED is False or config.IBET_SHARE_EXCHANGE_CONTRACT_ADDRESS is None: raise NotSupportedError(method="POST", url=req.path) # validate request_json = self.validate(req) order_list = [] settlement_list = [] complete_list = [] for account_address in request_json["account_address_list"]: try: # order_list order_list.extend( self.get_otc_order_list( session=session, token_model=ShareToken, exchange_contract_name="IbetOTCExchange", exchange_contract_address=config. IBET_SHARE_EXCHANGE_CONTRACT_ADDRESS, account_address=account_address)) order_list = sorted(order_list, key=lambda x: x["sort_id"]) # settlement_list settlement_list.extend( self.get_otc_settlement_list( session=session, token_model=ShareToken, exchange_contract_name="IbetOTCExchange", exchange_contract_address=config. IBET_SHARE_EXCHANGE_CONTRACT_ADDRESS, account_address=account_address)) settlement_list = sorted(settlement_list, key=lambda x: x["sort_id"]) # complete_list complete_list.extend( self.get_otc_complete_list( session=session, token_model=ShareToken, exchange_contract_name="IbetOTCExchange", exchange_contract_address=config. IBET_SHARE_EXCHANGE_CONTRACT_ADDRESS, account_address=account_address)) complete_list = sorted(complete_list, key=lambda x: x["sort_id"]) except Exception as err: LOG.exception(err) response_json = { "order_list": order_list, "settlement_list": settlement_list, "complete_list": complete_list } self.on_success(res, response_json)
def on_get(self, req, res): LOG.info('v2.token.MembershipTokens') session = req.context["session"] if config.MEMBERSHIP_TOKEN_ENABLED is False: raise NotSupportedError(method='GET', url=req.path) # Validation request_json = MembershipTokens.validate(req) # TokenList-Contractへの接続 ListContract = Contract.get_contract( 'TokenList', config.TOKEN_LIST_CONTRACT_ADDRESS) # 取扱トークンリストを取得 available_tokens = session.query(Listing).\ filter(Listing.is_public == True).\ order_by(Listing.id).\ all() list_length = len(available_tokens) if request_json['cursor'] is not None and request_json['cursor'] > list_length: raise InvalidParameterError("cursor parameter must be less than token list num") # パラメータを設定 cursor = request_json['cursor'] if cursor is None: cursor = list_length limit = request_json['limit'] if limit is None: limit = 10 token_list = [] count = 0 # TokenListを降順に調べる(登録が新しい順) for i in reversed(range(0, cursor)): if count >= limit: break # TokenList-Contractからトークンの情報を取得する token_address = to_checksum_address(available_tokens[i].token_address) token = ListContract.functions. \ getTokenByAddress(token_address).call() token_detail = MembershipTokenDetails.get_token_detail( session=session, token_id=i, token_address=token[0], token_template=token[1] ) if token_detail is not None: token_list.append(token_detail) count += 1 self.on_success(res, token_list)
def on_get(self, req, res): LOG.info('v2.token_abi.CouponABI') if config.COUPON_TOKEN_ENABLED is False: raise NotSupportedError(method='GET', url=req.path) ibet_coupon_json = json.load( open("app/contracts/json/IbetCoupon.json", "r")) abi = ibet_coupon_json['abi'] self.on_success(res, abi)
def on_get(self, req, res): LOG.info('v2.token_abi.MembershipABI') if config.MEMBERSHIP_TOKEN_ENABLED is False: raise NotSupportedError(method='GET', url=req.path) ibet_membership_json = json.load( open("app/contracts/json/IbetMembership.json", "r")) abi = ibet_membership_json['abi'] self.on_success(res, abi)
def on_get(self, req, res): LOG.info('v2.token_abi.StraightBondABI') if config.BOND_TOKEN_ENABLED is False: raise NotSupportedError(method='GET', url=req.path) ibet_straightbond_json = json.load( open("app/contracts/json/IbetStraightBond.json", "r")) abi = ibet_straightbond_json['abi'] self.on_success(res, abi)
def on_post(self, req, res): LOG.info("v2.market_information.MembershipTick") if config.MEMBERSHIP_TOKEN_ENABLED is False or config.IBET_MEMBERSHIP_EXCHANGE_CONTRACT_ADDRESS is None: raise NotSupportedError(method="POST", url=req.path) request_json = MembershipTick.validate(req) session = req.context["session"] tick_list = [] # TokenごとにTickを取得 for token_address in request_json["address_list"]: token = to_checksum_address(token_address) tick = [] try: entries = session.query(Agreement, Order). \ join(Order, Agreement.unique_order_id == Order.unique_order_id). \ filter(Order.token_address == token). \ filter(Agreement.status == AgreementStatus.DONE.value). \ order_by(desc(Agreement.settlement_timestamp)). \ all() for entry in entries: block_timestamp_utc = entry.IDXAgreement.settlement_timestamp tick.append({ "block_timestamp": block_timestamp_utc.strftime("%Y/%m/%d %H:%M:%S"), "buy_address": entry.IDXAgreement.buyer_address, "sell_address": entry.IDXAgreement.seller_address, "order_id": entry.IDXAgreement.order_id, "agreement_id": entry.IDXAgreement.agreement_id, "price": entry.IDXOrder.price, "amount": entry.IDXAgreement.amount }) tick_list.append({ "token_address": token_address, "tick": tick }) except Exception as e: LOG.error(e) tick_list = [] self.on_success(res, tick_list)
def on_get(self, req, res): LOG.info('v2.token.CouponTokenAddresses') session = req.context["session"] if config.COUPON_TOKEN_ENABLED is False: raise NotSupportedError(method='GET', url=req.path) # Validation request_json = CouponTokens.validate(req) # TokenList-Contractへの接続 ListContract = Contract.get_contract( 'TokenList', config.TOKEN_LIST_CONTRACT_ADDRESS) # 取扱トークンリストを取得 available_tokens = session.query(Listing).\ filter(Listing.is_public == True).\ order_by(Listing.id).\ all() list_length = len(available_tokens) if request_json['cursor'] is not None and request_json['cursor'] > list_length: raise InvalidParameterError( "cursor parameter must be less than token list num") # パラメータを設定 cursor = request_json['cursor'] if cursor is None: cursor = list_length limit = request_json['limit'] if limit is None: limit = 10 token_list = [] count = 0 for i in reversed(range(0, cursor)): if count >= limit: break token_address = to_checksum_address(available_tokens[i].token_address) token = ListContract.functions.getTokenByAddress(token_address).call() if token[1] == 'IbetCoupon': # ibetCoupon以外は処理をスキップ # Token-Contractへの接続 TokenContract = Contract.get_contract("IbetCoupon", token_address) if TokenContract.functions.status().call(): # 取扱停止の場合は処理をスキップ token_list.append({"id": i, "token_address": token_address}) count += 1 self.on_success(res, token_list)
def on_get(self, req, res, contract_address=None): LOG.info('v2.token.ShareTokenDetails') if config.SHARE_TOKEN_ENABLED is False: raise NotSupportedError(method='GET', url=req.path) # 入力アドレスフォーマットチェック try: contract_address = to_checksum_address(contract_address) if not Web3.isAddress(contract_address): description = 'invalid contract_address' raise InvalidParameterError(description=description) except: description = 'invalid contract_address' raise InvalidParameterError(description=description) session = req.context["session"] # 取扱トークン情報を取得 # NOTE:非公開トークンも取扱対象とする listed_token = session.query(Listing).\ filter(Listing.token_address == contract_address). \ first() if listed_token is None: raise DataNotExistsError('contract_address: %s' % contract_address) # TokenList-Contractへの接続 ListContract = Contract.get_contract('TokenList', config.TOKEN_LIST_CONTRACT_ADDRESS) # TokenList-Contractからトークンの情報を取得する token_address = to_checksum_address(contract_address) token = ListContract.functions.getTokenByAddress(token_address).call() token_detail = self.get_token_detail( session=session, token_address=token_address, token_template=token[1] ) if token_detail is None: raise DataNotExistsError('contract_address: %s' % contract_address) self.on_success(res, token_detail)
def on_get(self, req, res): if req.path == '/': res.status = falcon.HTTP_200 res.body = self.to_json(self.HELLO_WORLD) else: raise NotSupportedError(method='GET', url=req.path)
def on_post(self, req, res): LOG.info("v2.position.ShareMyTokens") session = req.context["session"] if config.SHARE_TOKEN_ENABLED is False: raise NotSupportedError(method="POST", url=req.path) # Validation request_json = ShareMyTokens.validate(req) # TokenList Contract ListContract = Contract.get_contract( contract_name="TokenList", address=config.TOKEN_LIST_CONTRACT_ADDRESS) # Exchange Contract ExchangeContract = None if config.IBET_SHARE_EXCHANGE_CONTRACT_ADDRESS is not None: ExchangeContract = Contract.get_contract( contract_name="IbetOTCExchange", address=config.IBET_SHARE_EXCHANGE_CONTRACT_ADDRESS) listed_tokens = session.query(Listing).all() position_list = [] for _account_address in request_json["account_address_list"]: # Get token details for token in listed_tokens: token_info = ListContract.functions.getTokenByAddress( token.token_address).call() token_address = token_info[0] token_template = token_info[1] if token_template == "IbetShare": _account_address = to_checksum_address(_account_address) TokenContract = Contract.get_contract( contract_name="IbetShare", address=token_address) try: balance = TokenContract.functions.balanceOf( _account_address).call() pending_transfer = TokenContract.functions.pendingTransfer( _account_address).call() if ExchangeContract is not None: commitment = ExchangeContract.functions.commitmentOf( _account_address, token_address).call() else: # If EXCHANGE_CONTRACT_ADDRESS is not set, set commitment to zero. commitment = 0 # If balance, pending_transfer, and commitment are non-zero, # get the token information from TokenContract. if balance == 0 and pending_transfer == 0 and commitment == 0: continue else: sharetoken = ShareToken.get( session=session, token_address=token_address) position_list.append({ "token": sharetoken.__dict__, "balance": balance, "pending_transfer": pending_transfer, "commitment": commitment }) except Exception as e: LOG.exception(e) continue self.on_success(res, position_list)
def on_post(self, req, res): LOG.info("v2.position.CouponMyTokens") session = req.context["session"] if config.COUPON_TOKEN_ENABLED is False: raise NotSupportedError(method="POST", url=req.path) # Validation request_json = CouponMyTokens.validate(req) # TokenList Contract ListContract = Contract.get_contract( contract_name="TokenList", address=config.TOKEN_LIST_CONTRACT_ADDRESS) # Coupon Exchange Contract CouponExchangeContract = None if config.IBET_CP_EXCHANGE_CONTRACT_ADDRESS is not None: CouponExchangeContract = Contract.get_contract( contract_name="IbetCouponExchange", address=config.IBET_CP_EXCHANGE_CONTRACT_ADDRESS) listed_tokens = session.query(Listing).all() position_list = [] for _account_address in request_json["account_address_list"]: # Get token details for token in listed_tokens: token_info = ListContract.functions.getTokenByAddress( token.token_address).call() token_address = token_info[0] token_template = token_info[1] owner = to_checksum_address(_account_address) if token_template == "IbetCoupon": CouponTokenContract = Contract.get_contract( contract_name="IbetCoupon", address=token_address) try: balance = CouponTokenContract.functions.balanceOf( owner).call() if CouponExchangeContract is not None: commitment = CouponExchangeContract.functions.commitmentOf( owner, token_address).call() else: # If EXCHANGE_CONTRACT_ADDRESS is not set, set commitment to zero. commitment = 0 used = CouponTokenContract.functions.usedOf( owner).call() # Retrieving token receipt history from IDXTransfer # NOTE: Index data has a lag from the most recent transfer state. received_history = session.query(IDXTransfer). \ filter(IDXTransfer.token_address == token.token_address). \ filter(IDXTransfer.to_address == owner). \ first() # If balance, pending_transfer, and commitment are non-zero, # get the token information from TokenContract. if balance == 0 and commitment == 0 and used == 0 and received_history is None: continue else: coupontoken = CouponToken.get( session=session, token_address=token_address) position_list.append({ "token": coupontoken.__dict__, "balance": balance, "commitment": commitment, "used": used }) except Exception as e: LOG.error(e) continue self.on_success(res, position_list)
def on_post(self, req, res): raise NotSupportedError(method="POST", url=req.path)
def on_put(self, req, res): raise NotSupportedError(method='PUT', url=req.path)
def on_delete(self, req, res): raise NotSupportedError(method='DELETE', url=req.path)
def on_post(self, req, res): LOG.info("v2.market_information.CouponOrderBook") session = req.context["session"] if config.COUPON_TOKEN_ENABLED is False or config.IBET_CP_EXCHANGE_CONTRACT_ADDRESS is None: raise NotSupportedError(method="POST", url=req.path) # 入力値チェック request_json = CouponOrderBook.validate(req) # 入力値を抽出 token_address = to_checksum_address(request_json["token_address"]) # 注文を抽出 is_buy = request_json["order_type"] == "buy" # 相対注文が買い注文かどうか exchange_address = to_checksum_address( config.IBET_CP_EXCHANGE_CONTRACT_ADDRESS) # account_address(注文者のアドレス)指定時は注文者以外の注文板を取得する # account_address(注文者のアドレス)未指定時は全ての注文板を取得する if "account_address" in request_json: account_address = to_checksum_address( request_json["account_address"]) if is_buy: # 買注文 # <抽出条件> # 1) Token Addressが指定したものと同じ # 2) クライアントが買い注文をしたい場合 => 売り注文を抽出 # 売り注文をしたい場合 => 買い注文を抽出 # 3) 未キャンセル # 4) 指値以下 # 5) 指定したアカウントアドレス以外 # # NOTE:DEXでは約定取消時に売注文中状態に戻すため、約定数量には取消分を含めていない orders = session.query(Order.order_id, Order.amount, Order.price, Order.exchange_address, Order.account_address, func.sum(Agreement.amount)). \ outerjoin(Agreement, and_(Order.unique_order_id == Agreement.unique_order_id, Agreement.status != AgreementStatus.CANCELED.value)). \ group_by(Order.order_id, Order.amount, Order.price, Order.exchange_address, Order.account_address). \ filter(Order.exchange_address == exchange_address). \ filter(Order.token_address == token_address). \ filter(Order.is_buy == False). \ filter(Order.is_cancelled == False). \ filter(Order.account_address != account_address). \ filter(Order.agent_address == config.AGENT_ADDRESS). \ all() else: # 売注文 # <抽出条件> # 1) Token Addressが指定したものと同じ # 2) クライアントが買い注文をしたい場合 => 売り注文を抽出 # 売り注文をしたい場合 => 買い注文を抽出 # 3) 未キャンセル # 4) 指値以上 # 5) 指定したアカウントアドレス以外 orders = session.query(Order.order_id, Order.amount, Order.price, Order.exchange_address, Order.account_address, func.sum(Agreement.amount)). \ outerjoin(Agreement, Order.unique_order_id == Agreement.unique_order_id). \ group_by(Order.order_id, Order.amount, Order.price, Order.exchange_address, Order.account_address). \ filter(Order.exchange_address == exchange_address). \ filter(Order.token_address == token_address). \ filter(Order.is_buy == True). \ filter(Order.is_cancelled == False). \ filter(Order.account_address != account_address). \ filter(Order.agent_address == config.AGENT_ADDRESS). \ all() else: if is_buy: # 買注文 # <抽出条件> # 1) Token Addressが指定したものと同じ # 2) クライアントが買い注文をしたい場合 => 売り注文を抽出 # 売り注文をしたい場合 => 買い注文を抽出 # 3) 未キャンセル # 4) 指値以下 # # NOTE:DEXでは約定取消時に売注文中状態に戻すため、約定数量には取消分を含めていない orders = session.query(Order.order_id, Order.amount, Order.price, Order.exchange_address, Order.account_address, func.sum(Agreement.amount)). \ outerjoin(Agreement, and_(Order.unique_order_id == Agreement.unique_order_id, Agreement.status != AgreementStatus.CANCELED.value)). \ group_by(Order.order_id, Order.amount, Order.price, Order.exchange_address, Order.account_address). \ filter(Order.exchange_address == exchange_address). \ filter(Order.token_address == token_address). \ filter(Order.is_buy == False). \ filter(Order.is_cancelled == False). \ filter(Order.agent_address == config.AGENT_ADDRESS). \ all() else: # 売注文 # <抽出条件> # 1) Token Addressが指定したものと同じ # 2) クライアントが買い注文をしたい場合 => 売り注文を抽出 # 売り注文をしたい場合 => 買い注文を抽出 # 3) 未キャンセル # 4) 指値以上 orders = session.query(Order.order_id, Order.amount, Order.price, Order.exchange_address, Order.account_address, func.sum(Agreement.amount)). \ outerjoin(Agreement, Order.unique_order_id == Agreement.unique_order_id). \ group_by(Order.order_id, Order.amount, Order.price, Order.exchange_address, Order.account_address). \ filter(Order.exchange_address == exchange_address). \ filter(Order.token_address == token_address). \ filter(Order.is_buy == True). \ filter(Order.is_cancelled == False). \ filter(Order.agent_address == config.AGENT_ADDRESS). \ all() # レスポンス用の注文一覧を構築 order_list_tmp = [] for (order_id, amount, price, exchange_address, account_address, agreement_amount) in orders: # 残存注文数量 = 発注数量 - 約定済み数量 if not (agreement_amount is None): amount -= int(agreement_amount) # 残注文ありの注文のみを抽出する if amount <= 0: continue order_list_tmp.append({ "order_id": order_id, "price": price, "amount": amount, "account_address": account_address, }) # 買い注文の場合は価格で昇順に、売り注文の場合は価格で降順にソートする if request_json["order_type"] == "buy": order_list = sorted(order_list_tmp, key=lambda x: x["price"]) else: order_list = sorted(order_list_tmp, key=lambda x: -x["price"]) self.on_success(res, order_list)