def set_fee_address(fee_address): if len(fee_address) != 20: return False storage = MCTManager() storage.put("feeAddress", fee_address)
def get_offers(trading_pair) -> list: ''' Get List of Offers for trading pair :param trading_pair: scripthash of each contract trading pair :return: list of Offers() ''' storage = MCTManager() result_serialized = storage.get(trading_pair) if not result_serialized: print("result_serialized is null") return None result_info = storage.deserialize(result_serialized) offers = [] for result in result_info: offer = Offer() offer.MakerAddress = result.MakerAddress offer.OfferAssetID = result.OfferAssetID offer.OfferAssetCategory = result.OfferAssetCategory offer.OfferAmount = result.OfferAmount offer.WantAssetID = result.WantAssetID offer.WantAssetCategory = result.WantAssetCategory offer.WantAmount = result.WantAmount offer.AvailableAmount = result.AvailableAmount offer.TradingPair = result.OfferAssetCategory + result.WantAssetCategory offers.append(offer) return offers
def remove_offer(trading_pair, offer_hash): ''' Remove Single Offer :param trading_pair: :param offer_hash: :return: Out put of Storage Call ''' storage = MCTManager() storage.delete(trading_pair + offer_hash)
def set_taker_fee(fee, asset_id): if fee > max_fee: return False if fee < 0: return False storage = MCTManager() key = concat("takerFee", asset_id) storage.put(key, fee)
def get_maker_fee(asset_id): storage = MCTManager() key = concat("makerFee", asset_id) fee = storage.get(key) if len(fee) != 0 or len(asset_id) == 0: return fee return storage.get("makerFee")
def get_volume(bucket_number, asset_id): storage = MCTManager() volume_key = concat("tradeVolume", bucket_number) volume_key = concat(volume_key, asset_id) volume_data = storage.get(volume_key) if len(volume_data) == 0: return Volume() else: return storage.deserialize(volume_data)
def transfer_asset_to(address, asset_id, amount): storage = MCTManager() if amount < 1: Notify("Amount to transfer less than 1!") return key = concat(address, asset_id) current_balance = storage.get(key) storage.put(key, current_balance + amount)
def get_offer(trading_pair, hash) -> Offer: ''' Get Single Offer :param trading_pair: :param hash: :return: Offer Object ''' storage = MCTManager() offer_data = storage.get(trading_pair + hash) if len(offer_data) == 0: return Offer() else: return storage.deserialize(offer_data)
def store_offer(trading_pair, offer_hash, offer): ''' Store Single Offer :param trading_pair: :param offer_hash: :param offer: :return: Out put of Storage Call ''' storage = MCTManager() if offer.AvailableAmount == 0: remove_offer(trading_pair, offer_hash) else: offer_data = storage.serialize_array(offer) storage.put(trading_pair + offer_hash, offer_data)
def make_offer(offer) -> bool: ''' Make New Offer on books :param offer: :return: Result of if offer was valid ''' if not CheckWitness(offer.MakerAddress): return False # Checking that the person that invoked this was the smart contract it self if not CheckWitness(OWNER): return False allowed = get_state() if allowed == 'Inactive' or allowed == 'Pending': return False if (allowed == 'Terminated' and not offer.OfferAssetID == NeoAssetID and offer.WantAssetID == GasAssetID and not offer.WantAssetID == NeoAssetID and offer.OfferAssetID == GasAssetID): return False trading_pair = offer.OfferAssetID + offer.WantAssetID offer_hash = hash(offer) storage = MCTManager() if storage.get(trading_pair + offer_hash): return False if not offer.OfferAmount > 0 and offer.WantAmount > 0: return False if offer.OfferAssetID == offer.WantAssetID: return False if (len(offer.OfferAssetID) != 20 and len(offer.OfferAssetID) != 32 or len(offer.WantAssetID) != 20 and len(offer.WantAssetID) != 32): return False if not reduce_balance(offer.MakerAddress, offer.OfferAssetID, offer.OfferAmount): return False store_offer(trading_pair, offer_hash, offer) created(offer.MakerAddress, offer_hash, offer.OfferAssetID, offer.OfferAmount, offer.WantAssetID, offer.WantAmount) return True
def reduce_balance(address, asset_id, amount): storage = MCTManager() if amount < 1: Notify("Amount to reduce less than 1") return False key = concat(address, asset_id) current_balance = storage.get(key) new_balance = current_balance - amount if new_balance < 0: Notify("Not enough balance") return False if new_balance > 0: storage.put(key, new_balance) else: storage.delete(key) return True
def add_volume(asset_id, native_amount, foreign_amount): time = GetTime() storage = MCTManager() bucket_number = time / bucket_duration volume_key = concat("tradeVolume", bucket_number) volume_key = concat(volume_key, asset_id) volume_data = storage.get(volume_key) if len(volume_data) == 0: volume = Volume() volume.Native = native_amount volume.Foreign = foreign_amount else: volume = storage.deserialize(volume_data) volume.Native = volume.Native + native_amount volume.Foreign = volume.Foreign + foreign_amount storage.put(volume_key, storage.serialize_array(volume))
def get_state(): storage = MCTManager() return storage.get('state')
def get_balance(originator, asset_id): storage = MCTManager() key = concat(originator, asset_id) return storage.get(key)
def terminate_trading(): storage = MCTManager() storage.put("state", "terminated")
def unfreeze_trading(): storage = MCTManager() storage.put("state", "Active")
def fill_offer(filler_address, trading_pair, offer_hash, amount_to_fill, use_native_token): if not CheckWitness(filler_address): return False # Checking that the person that invoked this was the smart contract if not CheckWitness(OWNER): return False offer = get_offer(trading_pair, offer_hash) storage = MCTManager() if offer.MakerAddress == '': failed(filler_address, offer_hash) return False allowed = get_state() if allowed == 'Inactive' or allowed == 'Pending': return False if (allowed == 'Terminated' and not offer.OfferAssetID == NeoAssetID and offer.WantAssetID == GasAssetID and not offer.WantAssetID == NeoAssetID and offer.OfferAssetID == GasAssetID): return False if filler_address == offer.MakerAddress: return False amount_to_take = (offer.OfferAmount * offer.WantAmount) / offer.OfferAmount if amount_to_take > offer.AvailableAmount: amount_to_take = offer.AvailableAmount amount_to_fill = (amount_to_take * offer.WantAmount) / offer.OfferAmount if amount_to_take <= 0: failed(filler_address, offer_hash) return True fee_address = storage.get('feeAddress') maker_fee_rate = get_maker_fee(offer.WantAssetID) taker_fee_rate = get_taker_fee(offer.OfferAssetID) maker_fee = (amount_to_fill * maker_fee_rate) / fee_factor taker_fee = (amount_to_take * taker_fee_rate) / fee_factor native_fee = 0 if use_native_token and offer.OfferAssetID != native_token: time = GetTime() bucket_number = time / bucket_duration volume = get_volume(bucket_number, offer.OfferAssetID) native_volume = volume.Native foreign_volume = volume.Foreign if foreign_volume > 0: native_fee = (taker_fee * native_volume) / (foreign_volume * native_token_discount) if not reduce_balance(filler_address, native_token, native_fee): native_fee = 0 if offer.OfferAssetID == native_token: taker_fee = taker_fee / native_token_discount if native_fee > 0: taker_amount = amount_to_take - taker_fee else: taker_amount = 0 # Transfer to taker transfer_asset_to(filler_address, offer.WantAssetID, taker_amount) transferred(filler_address, offer.OfferAssetID, taker_amount) # Transfer to maker maker_amount = amount_to_fill - maker_fee transfer_asset_to(offer.MakerAddress, offer.WantAssetID, maker_amount) transferred(offer.MakerAddress, offer.WantAssetID, maker_amount) # Move fees if maker_fee > 0: transfer_asset_to(fee_address, offer.WantAssetID, maker_fee) if native_fee == 0 and offer.OfferAssetID != native_token: transfer_asset_to(fee_address, offer.OfferAssetID, taker_fee) # Update native token exchange rate if offer.OfferAssetID == native_token: add_volume(offer.WantAssetID, amount_to_take, amount_to_fill) if offer.WantAssetID == native_token: add_volume(offer.OfferAssetID, amount_to_fill, amount_to_take) # Update available amount offer.AvailableAmount = offer.AvailableAmount - amount_to_take store_offer(trading_pair, offer_hash, offer) filled(filler_address, offer_hash, amount_to_fill, offer.OfferAssetID, offer.OfferAmount, offer.WantAssetID, offer.WantAmount) return True
def main(operation, args): trigger = GetTrigger() if trigger == Verification(): ''' Check if state of contract == {Active,Pending,Frozen} Validate inputs Check that valid self send Validate utxo has been reserved Validate withdraw destination Validate amount withdrawn ''' if CheckWitness(OWNER): return True return False elif trigger == Application(): if operation == 'initialize': if not CheckWitness(OWNER): print("initialize error") return False if len(args) != 3: print("To few args") return False return initialize() # Get functions if operation == 'getstate': return get_state() # ARGS: asset_id if operation == 'getMakerFee': return get_maker_fee(args[0]) # ARGS: asset_id if operation == 'getTakerFee': return get_taker_fee(args[0]) # ARGS: asset_id if operation == 'getExchangeRate': return get_exchange_rate(args[0]) # ARGS: trading_pair if operation == 'getOffers': return get_offers(args[0]) # ARGS: originator, asset_id if operation == 'getBalance': return get_balance(args[0], args[1]) # Execute functions # ARGS: address, asset_id, amount if operation == 'deposit': if get_state() != 'Active': return False if len(args) != 3: return False if not verify_sent_amount(args[0], args[1], args[2]): return False if not transfer_asset_to(args[0], args[1], args[2]): return False return True # ARGS: maker_address, offer_asset_id, offer_amount, want_asset_id, want_amount, avail_amount, nonce if operation == 'makeOffer': if get_state() != 'Active': return False if len(args) != 7: return False offer = new_offer(args[0], args[1], args[2], args[3], args[4], args[5], args[6]) return make_offer(offer) # ARGS: filler_address, trading_pair, offer_hash, amount_to_fill, use_native_token) if operation == 'fillOffer': if get_state() != 'Active': return False if len(args) != 5: return False return fill_offer(args[0], args[1], args[2], args[3], args[4]) # ARGS: trading_pair, offer_hash if operation == 'cancelOffer': if get_state() != 'Active': return False if len(args) != 2: return False return cancel_offer(args[0], args[1]) if operation == 'withdraw': return process_withdrawal() # Owner Operations if not CheckWitness(OWNER): return False if operation == 'freezeTrading': return freeze_trading() if operation == 'unfreezeTrading': return unfreeze_trading() if operation == 'terminateTrading': return terminate_trading() if operation == 'addToWhitelist': return add_to_whitelist() if operation == 'removeFromWhitelist': return remove_from_whitelist() # ARGS: amount if operation == 'ownerWithdraw': if not CheckWitness(OWNER): print( 'Only the contract owner can withdraw MCT from the contract' ) return False if len(args) != 1: print('withdraw amount not specified') return False t_amount = args[0] my_hash = GetExecutingScriptHash() storage = MCTManager() return storage.transfer(my_hash, t_amount) return False
def initialize(): storage = MCTManager() storage.put('state', 'Active')