def post_bounties_guid_assertions(guid): account = g.chain.w3.toChecksumAddress(g.eth_address) base_nonce = int( request.args.get('base_nonce', g.chain.w3.eth.getTransactionCount(account))) body = request.get_json() try: _post_bounties_guid_assertions_schema(body) except fastjsonschema.JsonSchemaException as e: return failure('Invalid JSON: ' + e.message, 400) bid = [int(b) for b in body['bid']] mask = bool_list_to_int(body['mask']) verdict_count = len([m for m in body['mask'] if m]) commitment = body.get('commitment') verdicts = body.get('verdicts') if commitment is None and verdicts is None: return failure('Require verdicts and bid_portions or a commitment', 400) if not bid or len(bid) != verdict_count: return failure( 'bid_portions must be equal in length to the number of true mask values', 400) max_bid = eth.assertion_bid_max(g.chain.bounty_registry.contract) min_bid = eth.assertion_bid_min(g.chain.bounty_registry.contract) if any((b for b in bid if max_bid < b < min_bid)): return failure('Invalid assertion bid', 400) approve_amount = sum(bid) + eth.assertion_fee( g.chain.bounty_registry.contract) nonce = None if commitment is None: nonce, commitment = calculate_commitment(account, bool_list_to_int(verdicts)) else: commitment = int(commitment) ret = { 'transactions': [ build_transaction( g.chain.nectar_token.contract.functions.approve( g.chain.bounty_registry.contract.address, approve_amount), base_nonce), build_transaction( g.chain.bounty_registry.contract.functions.postAssertion( guid.int, bid, mask, commitment), base_nonce + 1), ] } if nonce is not None: # Pass generated nonce onto user in response, used for reveal ret['nonce'] = nonce return success(ret)
def post_assertion_metadata(): config = app.config['POLYSWARMD'] session = app.config['REQUESTS_SESSION'] body = request.get_json() loaded_body = json.loads(body) if isinstance(body, str) else body try: if not AssertionMetadata.validate(loaded_body, silent=True) and \ not BountyMetadata.validate(loaded_body, silent=True): return failure('Invalid metadata', 400) except json.JSONDecodeError: # Expected when people provide incorrect metadata. Not stack worthy return failure('Invalid Assertion metadata', 400) try: uri = config.artifact.client.add_artifact(json.dumps(loaded_body), session, redis=config.redis.client) response = success(uri) except HTTPError as e: response = failure(e.response.content, e.response.status_code) except ArtifactException as e: response = failure(e.message, 500) except Exception: logger.exception('Received error posting to IPFS got response') response = failure('Could not add metadata to ipfs', 500) return response
def post_arbiter_staking_deposit(): account = g.chain.w3.toChecksumAddress(g.eth_address) base_nonce = int( request.args.get('base_nonce', g.chain.w3.eth.getTransactionCount(account))) body = request.get_json() try: _post_arbiter_staking_deposit_schema(body) except fastjsonschema.JsonSchemaException as e: return failure('Invalid JSON: ' + e.message, 400) amount = int(body['amount']) total = g.chain.arbiter_staking.contract.functions.balanceOf( account).call() if amount + total >= eth.staking_total_max( g.chain.arbiter_staking.contract): return failure('Total stake above allowable maximum.', 400) transactions = [ build_transaction( g.chain.nectar_token.contract.functions.approve( g.chain.arbiter_staking.contract.address, amount), base_nonce), build_transaction( g.chain.arbiter_staking.contract.functions.deposit(amount), base_nonce + 1), ] return success({'transactions': transactions})
def post_arbiter_staking_withdrawal(): account = g.chain.w3.toChecksumAddress(g.eth_address) base_nonce = int( request.args.get('base_nonce', g.chain.w3.eth.getTransactionCount(account))) body = request.get_json() try: _post_arbiter_staking_withdrawal_schema(body) except fastjsonschema.JsonSchemaException as e: return failure('Invalid JSON: ' + e.message, 400) amount = int(body['amount']) available = g.chain.arbiter_staking.contract.functions.withdrawableBalanceOf( account).call() if amount > available: return failure('Exceeds withdrawal eligible %s' % available, 400) transactions = [ build_transaction( g.chain.arbiter_staking.contract.functions.withdraw(amount), base_nonce), ] return success({'transactions': transactions})
def post_bounties(): config = app.config['POLYSWARMD'] session = app.config['REQUESTS_SESSION'] account = g.chain.w3.toChecksumAddress(g.eth_address) base_nonce = int( request.args.get('base_nonce', g.chain.w3.eth.getTransactionCount(account))) body = request.get_json() try: _post_bounties_schema(body) except fastjsonschema.JsonSchemaException as e: return failure('Invalid JSON: ' + e.message, 400) guid = uuid.uuid4() artifact_type = ArtifactType.from_string(body['artifact_type']) amount = int(body['amount']) artifact_uri = body['uri'] duration_blocks = body['duration'] metadata = body.get('metadata', '') try: arts = config.artifact.client.ls(artifact_uri, session) except HTTPError as e: return failure(e.response.content, e.response.status_code) except ArtifactException: logger.exception('Failed to ls given artifact uri') return failure(f'Failed to check artifact uri', 500) if amount < eth.bounty_amount_min( g.chain.bounty_registry.contract) * len(arts): return failure('Invalid bounty amount', 400) if metadata and not config.artifact.client.check_uri(metadata): return failure('Invalid bounty metadata URI (should be IPFS hash)', 400) num_artifacts = len(arts) bloom = calculate_bloom(arts) approve_amount = amount + eth.bounty_fee(g.chain.bounty_registry.contract) transactions = [ build_transaction( g.chain.nectar_token.contract.functions.approve( g.chain.bounty_registry.contract.address, approve_amount), base_nonce), build_transaction( g.chain.bounty_registry.contract.functions.postBounty( guid.int, artifact_type.value, amount, artifact_uri, num_artifacts, duration_blocks, bloom, metadata), base_nonce + 1), ] return success({'transactions': transactions})
def get_artifacts_status(): config = app.config['POLYSWARMD'] session = app.config['REQUESTS_SESSION'] try: return success(config.artifact.client.status(session)) except HTTPError as e: return failure(e.response.content, e.response.status_code) except ArtifactException as e: return failure(e.message, 500)
def get_balance_address_eth(address): if not g.chain.w3.isAddress(address): return failure('Invalid address', 400) address = g.chain.w3.toChecksumAddress(address) try: balance = g.chain.w3.eth.getBalance(address) return success(str(balance)) except Exception: logger.exception('Unexpected exception retrieving ETH balance') return failure("Could not retrieve balance")
def get_balance_address_nct(address): if not g.chain.w3.isAddress(address): return failure('Invalid address', 400) address = g.chain.w3.toChecksumAddress(address) try: balance = g.chain.nectar_token.contract.functions.balanceOf( address).call() return success(str(balance)) except Exception: logger.exception('Unexpected exception retrieving NCT balance') return failure("Could not retrieve balance")
def get_balance_total_stake(address): if not g.chain.w3.isAddress(address): return failure('Invalid address', 400) address = g.chain.w3.toChecksumAddress(address) try: balance = g.chain.arbiter_staking.contract.functions.balanceOf( address).call() return success(str(balance)) except Exception: logger.exception( 'Unexpected exception retrieving total staking balance') return failure("Could not retrieve balance")
def get_bounties_guid_assertions_id(guid, id_): bounty = bounty_to_dict( g.chain.bounty_registry.contract.functions.bountiesByGuid( guid.int).call()) if bounty['author'] == ZERO_ADDRESS: return failure('Bounty not found', 404) try: assertion = get_assertion(guid, id_, bounty['num_artifacts']) return success(assertion) except: # noqa: E772 return failure('Assertion not found', 404)
def get_bounties_guid_votes_id(guid, id_): bounty = bounty_to_dict( g.chain.bounty_registry.contract.functions.bountiesByGuid( guid.int).call()) if bounty['author'] == ZERO_ADDRESS: return failure('Bounty not found', 404) try: vote = vote_to_dict( g.chain.bounty_registry.contract.functions.votesByGuid( guid.int, id_).call(), bounty['num_artifacts']) return success(vote) except: # noqa: E772 return failure('Vote not found', 404)
def post_uri(guid): offer_channel = channel_to_dict( g.chain.offer_registry.contract.functions.guidToChannel( guid.int).call()) msig_address = offer_channel['msig_address'] offer_msig = g.chain.offer_multi_sig.bind(msig_address) account = g.chain.w3.toChecksumAddress(g.eth_address) base_nonce = int( request.args.get('base_nonce', g.chain.w3.eth.getTransactionCount(account))) body = request.get_json() try: _post_uri_schema(body) except fastjsonschema.JsonSchemaException as e: return failure('Invalid JSON: ' + e.message) websocket_uri = body['websocketUri'] transactions = [ build_transaction( offer_msig.functions.setCommunicationUri( g.chain.w3.toHex(text=websocket_uri)), base_nonce), ] return success({'transactions': transactions})
def post_challange(guid): offer_channel = channel_to_dict( g.chain.offer_registry.contract.functions.guidToChannel( guid.int).call()) msig_address = offer_channel['msig_address'] offer_msig = g.chain.offer_multi_sig.bind(msig_address) account = g.chain.w3.toChecksumAddress(g.eth_address) base_nonce = int( request.args.get('base_nonce', g.chain.w3.eth.getTransactionCount(account))) body = request.get_json() try: _post_challange_schema(body) except fastjsonschema.JsonSchemaException as e: return failure('Invalid JSON: ' + e.message) state = g.chain.w3.toBytes(hexstr=body['state']) v = body['v'] r = list(map(lambda s: g.chain.w3.toBytes(hexstr=s), body['r'])) s = list(map(lambda s: g.chain.w3.toBytes(hexstr=s), body['s'])) transactions = [ build_transaction(offer_msig.functions.challengeSettle(state, v, r, s), base_nonce), ] return success({'transactions': transactions})
def post_create_offer_channel(): account = g.chain.w3.toChecksumAddress(g.eth_address) base_nonce = int( request.args.get('base_nonce', g.chain.w3.eth.getTransactionCount(account))) body = request.get_json() try: _post_create_offer_channel_schema(body) except fastjsonschema.JsonSchemaException as e: return failure('Invalid JSON: ' + e.message) guid = uuid.uuid4() ambassador = g.chain.w3.toChecksumAddress(body['ambassador']) expert = g.chain.w3.toChecksumAddress(body['expert']) settlement_period_length = body['settlementPeriodLength'] transactions = [ build_transaction( g.chain.offer_registry.contract.functions.initializeOfferChannel( guid.int, ambassador, expert, settlement_period_length), base_nonce), ] return success({'transactions': transactions})
def post_join(guid): offer_channel = channel_to_dict( g.chain.offer_registry.contract.functions.guidToChannel( guid.int).call()) msig_address = offer_channel['msig_address'] offer_msig = g.chain.offer_multi_sig.bind(msig_address) account = g.chain.w3.toChecksumAddress(g.eth_address) base_nonce = int( request.args.get('base_nonce', g.chain.w3.eth.getTransactionCount(account))) body = request.get_json() try: _post_join_schema(body) except fastjsonschema.JsonSchemaException as e: return failure('Invalid JSON: ' + e.message) state = body['state'] v = body['v'] r = body['r'] s = body['s'] transactions = [ build_transaction( offer_msig.functions.joinAgreement(state, v, to_padded_hex(r), to_padded_hex(s)), base_nonce), ] return success({'transactions': transactions})
def wrapper(*args, **kwargs): g.eth_address = request.args.get('account') if not g.eth_address and account_required: return failure('Account must be provided', 400) c = chain_name if c is None: c = request.args.get('chain', 'side') chain = app.config['POLYSWARMD'].chains.get(c) if not chain: chain_options = ", ".join(app.config['POLYSWARMD'].chains) return failure(f'Chain must one of {chain_options}', 400) g.chain = chain return func(*args, **kwargs)
def get_artifacts_identifier_id_stat(identifier, id_): config = app.config['POLYSWARMD'] session = app.config['REQUESTS_SESSION'] try: response = success( config.artifact.client.details(identifier, id_, session)) except HTTPError as e: response = failure(e.response.content, e.response.status_code) except InvalidUriException: response = failure('Invalid artifact URI', 400) except ArtifactNotFoundException: response = failure(f'Artifact with URI {identifier} not found', 404) except ArtifactException as e: response = failure(e.message, 500) return response
def get_transactions(): body = request.get_json() try: _get_transactions_schema_validator(body) except fastjsonschema.JsonSchemaException as e: return failure('Invalid JSON: ' + e.message, 400) ret: Dict[str, List[Any]] = defaultdict(list) for transaction in body['transactions']: event = events_from_transaction(HexBytes(transaction), g.chain.name) for k, v in event.items(): ret[k].extend(v) if ret['errors']: logging.error('Got transaction errors: %s', ret['errors']) return failure(ret, 400) return success(ret)
def post_artifacts(): config = app.config['POLYSWARMD'] session = app.config['REQUESTS_SESSION'] try: files = [(f'{i:06d}', f) for (i, f) in enumerate(request.files.getlist(key='file')) if check_size(f, g.user.max_artifact_size)] except (AttributeError, IOError): logger.error('Error checking file size') return failure('Unable to read file sizes', 400) except ArtifactTooLargeException: return failure('Artifact too large', 413) except ArtifactEmptyException: return failure('Artifact empty', 400) if not files: return failure('No artifacts', 400) if len(files) > config.artifact.limit: return failure('Too many artifacts', 400) try: response = success(config.artifact.client.add_artifacts( files, session)) except HTTPError as e: response = failure(e.response.content, e.response.status_code) except ArtifactException as e: response = failure(e.message, 500) return response
def get_bounties_guid_bloom(guid): bounty = bounty_to_dict( g.chain.bounty_registry.contract.functions.bountiesByGuid( guid.int).call()) if bounty['author'] == ZERO_ADDRESS: return failure('Bounty not found', 404) try: bloom_parts = [] for i in range(0, 8): bloom_parts.append( g.chain.bounty_registry.contract.functions.bloomByGuid( guid.int, i).call()) bloom = bloom_to_dict(bloom_parts) return success(bloom) except: # noqa: E772 logger.exception('Bloom not found') return failure('Bloom not found', 404)
def get_artifacts_identifier_id(identifier, id_): config = app.config['POLYSWARMD'] session = app.config['REQUESTS_SESSION'] try: response = config.artifact.client.get_artifact( identifier, session, index=id_, max_size=g.user.max_artifact_size) except HTTPError as e: response = failure(e.response.content, e.response.status_code) except InvalidUriException: response = failure('Invalid artifact URI', 400) except ArtifactNotFoundException: response = failure(f'Artifact with URI {identifier}/{id_} not found', 404) except ArtifactTooLargeException: response = failure(f'Artifact with URI {identifier}/{id_} too large', 400) except ArtifactException as e: response = failure(e.message, 500) return response
def get_bounties_guid(guid): config = app.config['POLYSWARMD'] session = app.config['REQUESTS_SESSION'] bounty = bounty_to_dict( g.chain.bounty_registry.contract.functions.bountiesByGuid( guid.int).call()) metadata = bounty.get('metadata', None) if metadata: metadata = substitute_metadata(metadata, config.artifact.client, session, validate=BountyMetadata.validate, redis=config.redis.client) else: metadata = None bounty['metadata'] = metadata if not config.artifact.client.check_uri(bounty['uri']): return failure(f'Invalid {config.artifact.client.name} URI', 400) if bounty['author'] == ZERO_ADDRESS: return failure('Bounty not found', 404) return success(bounty)
def get_artifacts_identifier(identifier): config = app.config['POLYSWARMD'] session = app.config['REQUESTS_SESSION'] try: arts = config.artifact.client.ls(identifier, session) if len(arts) > 256: return failure( f'Invalid {config.artifact.client.name} resource, too many links', 400) response = success([{'name': a[0], 'hash': a[1]} for a in arts]) except HTTPError as e: response = failure(e.response.content, e.response.status_code) except InvalidUriException: response = failure('Invalid artifact URI', 400) except ArtifactNotFoundException: response = failure(f'Artifact with URI {identifier} not found', 404) except ArtifactException as e: response = failure(e.message, 500) return response
def create_state(): body = request.get_json() try: _create_state_schema(body) except fastjsonschema.JsonSchemaException as e: return failure('Invalid JSON: ' + e.message) body['token_address'] = str(g.chain.nectar_token.address) if 'verdicts' in body and 'mask' in body: body['verdicts'] = bool_list_to_int(body['verdicts']) body['mask'] = bool_list_to_int(body['mask']) return success({'state': dict_to_state(body)})
def get_websocket(guid): offer_channel = g.chain.offer_registry.contract.functions.guidToChannel( guid.int).call() channel_data = channel_to_dict(offer_channel) msig_address = channel_data['msig_address'] offer_msig = g.chain.offer_multi_sig.bind(msig_address) socket_uri = offer_msig.functions.websocketUri().call() # TODO find a better way than replace socket_uri = g.chain.w3.toText(socket_uri).replace('\u0000', '') if not validate_ws_url(socket_uri): return failure('Contract does not have a valid WebSocket uri', 400) return success({'websocket': socket_uri})
def send_funds_from(): # Grab correct versions by chain type account = g.chain.w3.toChecksumAddress(g.eth_address) base_nonce = int(request.args.get('base_nonce', g.chain.w3.eth.getTransactionCount(account))) erc20_relay_address = g.chain.w3.toChecksumAddress(g.chain.erc20_relay.address) body = request.get_json() try: _send_funds_from_schema(body) except fastjsonschema.JsonSchemaException as e: return failure('Invalid JSON: ' + e.message, 400) amount = int(body['amount']) transactions = [ build_transaction( g.chain.nectar_token.contract.functions.transfer(erc20_relay_address, amount), base_nonce ), ] return success({'transactions': transactions})
def post_bounties_guid_vote(guid): account = g.chain.w3.toChecksumAddress(g.eth_address) base_nonce = int( request.args.get('base_nonce', g.chain.w3.eth.getTransactionCount(account))) body = request.get_json() try: _post_bounties_guid_vote_schema(body) except fastjsonschema.JsonSchemaException as e: return failure('Invalid JSON: ' + e.message, 400) votes = bool_list_to_int(body['votes']) valid_bloom = bool(body['valid_bloom']) transactions = [ build_transaction( g.chain.bounty_registry.contract.functions.voteOnBounty( guid.int, votes, valid_bloom), base_nonce), ] return success({'transactions': transactions})
def get_bounties_guid_votes(guid): bounty = bounty_to_dict( g.chain.bounty_registry.contract.functions.bountiesByGuid( guid.int).call()) if bounty['author'] == ZERO_ADDRESS: return failure('Bounty not found', 404) num_votes = g.chain.bounty_registry.contract.functions.getNumberOfVotes( guid.int).call() votes = [] for i in range(num_votes): try: vote = vote_to_dict( g.chain.bounty_registry.contract.functions.votesByGuid( guid.int, i).call(), bounty['num_artifacts']) votes.append(vote) except Exception: logger.exception('Could not retrieve vote') continue return success(votes)
def get_bounties_guid_assertions(guid): bounty = bounty_to_dict( g.chain.bounty_registry.contract.functions.bountiesByGuid( guid.int).call()) if bounty['author'] == ZERO_ADDRESS: return failure('Bounty not found', 404) num_assertions = g.chain.bounty_registry.contract.functions.getNumberOfAssertions( guid.int).call() assertions = [] for i in range(num_assertions): try: assertion = get_assertion(guid, i, bounty['num_artifacts']) # Nonce is 0 when a reveal did not occur if assertion['nonce'] == "0": assertion['verdicts'] = [None] * bounty['num_artifacts'] assertions.append(assertion) except Exception: logger.exception('Could not retrieve assertion') continue return success(assertions)
def post_bounties_guid_assertions_id_reveal(guid, id_): account = g.chain.w3.toChecksumAddress(g.eth_address) base_nonce = int( request.args.get('base_nonce', g.chain.w3.eth.getTransactionCount(account))) body = request.get_json() try: _post_bounties_guid_assertions_id_reveal_schema(body) except fastjsonschema.JsonSchemaException as e: return failure('Invalid JSON: ' + e.message, 400) nonce = int(body['nonce']) verdicts = bool_list_to_int(body['verdicts']) metadata = body['metadata'] transactions = [ build_transaction( g.chain.bounty_registry.contract.functions.revealAssertion( guid.int, id_, nonce, verdicts, metadata), base_nonce), ] return success({'transactions': transactions})