示例#1
0
def addhooktoevent(ctx_obj, contractaddress, hookid, events):
    """
    Receive smart contract events as JSON payloads.
    This delivers JSON payloads to the webhook endpoint registered against the HOOKID.

    HOOKID is received after calling `mv-cli registerhook`

    EVENTS is a list of events on which the hook will be registered.
    For example: ['*'] or ['Transfer', 'Approve'].
    If you do not pass this argument, all events will be pushed to the hook endpoint.
    """
    msg = 'dummystring'
    message_hash = encode_defunct(text=msg)
    sig_msg = Account.sign_message(message_hash,
                                   ctx_obj['settings']['PRIVATEKEY'])
    events_to_be_registered_on = list()
    if not events:
        events_to_be_registered_on.append('*')
    else:
        for each in events.split(','):
            events_to_be_registered_on.append(each)
    method_args = {
        "msg": msg,
        "sig": sig_msg.signature.hex(),
        "key": ctx_obj['settings']['MATICVIGIL_API_KEY'],
        "type": "web",
        "contract": contractaddress,
        "id": hookid,
        "events": events_to_be_registered_on
    }
    headers = {
        'accept': 'application/json',
        'Content-Type': 'application/json',
        'X-API-KEY': ctx_obj['settings']['MATICVIGIL_API_KEY']
    }
    click.echo(
        f'Registering | hook ID: {hookid} | events: {events_to_be_registered_on} | contract: {contractaddress}'
    )
    r = requests.post(
        url=
        f'{ctx_obj["settings"]["INTERNAL_API_ENDPOINT"]}/hooks/updateEvents',
        json=method_args,
        headers=headers)
    click.echo(r.text)
    if r.status_code == requests.codes.ok:
        r = r.json()
        if r['success']:
            click.echo('Succeeded in adding hook')
        else:
            click.echo('Failed to add hook')
            return
    else:
        click.echo('Failed to add hook')
        return
示例#2
0
 def sign(self, username, password, info):
     keystore_file = "{}/{}".format(client_config.account_keyfile_path,
                                         username + ".keystore")
     if os.path.exists(keystore_file) is False:
         return -1
     try:
         with open(keystore_file, "r") as dump_f:
             keytext = json.load(dump_f)
             privkey = Account.decrypt(keytext, password)
             msg = encode_defunct(text=info)
             signed_msg = Account.sign_message(msg, privkey)
             v = signed_msg['v']
             r = signed_msg['r']
             s = signed_msg['s']
             return v, r, s
     except Exception as e:
         print(e)
         return -1
示例#3
0
def enabletxmonitor(ctx_obj, contractaddress, hookid):
    """
    Receive transactions on contracts as JSON payloads.

    CONTRACTADDRESS is the address of a deployed and registered contract on your MaticVigil account.

    HOOKID is received after calling `mv-cli registerhook`
    """
    # enable tx monitoring on contract
    msg = 'dummystring'
    message_hash = encode_defunct(text=msg)
    sig_msg = Account.sign_message(message_hash,
                                   ctx_obj['settings']['PRIVATEKEY'])
    method_args = {
        "msg": msg,
        "sig": sig_msg.signature.hex(),
        "key": ctx_obj['settings']['MATICVIGIL_API_KEY'],
        "type": "web",
        "contract": contractaddress,
        "id": hookid,
        "action": "set"
    }
    headers = {
        'accept': 'application/json',
        'Content-Type': 'application/json',
        'X-API-KEY': ctx_obj["settings"]["MATICVIGIL_API_KEY"]
    }
    r = requests.post(
        url=
        f'{ctx_obj["settings"]["INTERNAL_API_ENDPOINT"]}/hooks/transactions',
        json=method_args,
        headers=headers)
    click.echo(r.text)
    if r.status_code == requests.codes.ok:
        r = r.json()
        if r['success']:
            click.echo('Succeded in adding hook to monitor all contract txs')
        else:
            click.echo('Failed to add hook to monitor on all contract txs...')
    else:
        click.echo('Failed to add hook to monitor on all contract txs...')
示例#4
0
def ev_signup(internal_api_endpoint, invite_code, private_key, verbose):
    msg = "Trying to signup"
    message_hash = encode_defunct(text=msg)
    signed_msg = Account.sign_message(message_hash, private_key)
    # --MATICVIGIL API CALL to /signup---
    try:
        r = requests.post(internal_api_endpoint + '/signup',
                          json={
                              'msg': msg,
                              'sig': signed_msg.signature.hex(),
                              'code': invite_code
                          })
    except:
        return False
    else:
        if verbose:
            print(r.url)
            print(r.text)
        if r.status_code == requests.codes.ok:
            return r.json()
        else:
            return False
示例#5
0
def ev_login(internal_api_endpoint, private_key, verbose=False):
    msg = "Trying to login"
    message_hash = encode_defunct(text=msg)
    signed_msg = Account.sign_message(message_hash, private_key)
    # --MATICVIGIL API CALL---
    headers = {
        'accept': 'application/json',
        'Content-Type': 'application/json'
    }
    r = requests.post(internal_api_endpoint + '/login',
                      json={
                          'msg': msg,
                          'sig': signed_msg.signature.hex()
                      },
                      headers=headers)
    if verbose:
        click.echo(r.text)
    if r.status_code == requests.codes.ok:
        r = r.json()
        return r['data']
    else:
        return None
示例#6
0
def registerhook(ctx_obj, contract, url):
    """
    Registers a webhook endpoint and returns an ID for hook
    """
    headers = {
        'accept': 'application/json',
        'Content-Type': 'application/json',
        'X-API-KEY': ctx_obj['settings']['MATICVIGIL_API_KEY']
    }
    msg = 'dummystring'
    message_hash = encode_defunct(text=msg)
    sig_msg = Account.sign_message(message_hash,
                                   ctx_obj['settings']['PRIVATEKEY'])
    method_args = {
        "msg": msg,
        "sig": sig_msg.signature.hex(),
        "key": ctx_obj['settings']['MATICVIGIL_API_KEY'],
        "type": "web",
        "contract": contract,
        "web": url
    }
    r = requests.post(
        url=f'{ctx_obj["settings"]["INTERNAL_API_ENDPOINT"]}/hooks/add',
        json=method_args,
        headers=headers)
    click.echo(r.text)
    if r.status_code == requests.codes.ok:
        r = r.json()
        if not r['success']:
            click.echo('Failed to register webhook with MaticVigil API...')
        else:
            hook_id = r["data"]["id"]
            click.echo(
                'Succeeded in registering webhook with MaticVigil API...')
            click.echo(f'MaticVigil Hook ID: {hook_id}')
    else:
        click.echo('Failed to register webhook with MaticVigil API...')
示例#7
0
def test_verify_eip191(testerchain, signature_verifier):
    message = os.urandom(100)

    # Generate Umbral key
    umbral_privkey = SecretKey.random()
    umbral_pubkey = umbral_privkey.public_key()
    umbral_pubkey_bytes = pubkey_as_uncompressed_bytes(umbral_pubkey)

    #
    # Check EIP191 signatures: Version E
    #

    # Produce EIP191 signature (version E)
    signable_message = encode_defunct(primitive=message)
    signature = Account.sign_message(
        signable_message=signable_message,
        private_key=umbral_privkey.to_secret_bytes())
    signature = bytes(signature.signature)

    # Off-chain verify, just in case
    checksum_address = to_checksum_address(
        canonical_address_from_umbral_key(umbral_pubkey))
    assert verify_eip_191(address=checksum_address,
                          message=message,
                          signature=signature)

    # Verify signature on-chain
    version_E = b'E'
    assert signature_verifier.functions.verifyEIP191(message, signature,
                                                     umbral_pubkey_bytes,
                                                     version_E).call()

    # Of course, it'll fail if we try using version 0
    version_0 = b'\x00'
    assert not signature_verifier.functions.verifyEIP191(
        message, signature, umbral_pubkey_bytes, version_0).call()

    # Check that the hash-based method also works independently
    hash = signature_verifier.functions.hashEIP191(message, version_E).call()
    eip191_header = "\x19Ethereum Signed Message:\n" + str(len(message))
    assert hash == keccak_digest(eip191_header.encode() + message)

    address = signature_verifier.functions.recover(hash, signature).call()
    assert address == checksum_address

    #
    # Check EIP191 signatures: Version 0
    #

    # Produce EIP191 signature (version 0)
    validator = to_canonical_address(signature_verifier.address)
    signable_message = SignableMessage(version=HexBytes(version_0),
                                       header=HexBytes(validator),
                                       body=HexBytes(message))
    signature = Account.sign_message(
        signable_message=signable_message,
        private_key=umbral_privkey.to_secret_bytes())
    signature = bytes(signature.signature)

    # Off-chain verify, just in case
    checksum_address = to_checksum_address(
        canonical_address_from_umbral_key(umbral_pubkey))
    assert checksum_address == Account.recover_message(
        signable_message=signable_message, signature=signature)

    # On chain verify signature
    assert signature_verifier.functions.verifyEIP191(message, signature,
                                                     umbral_pubkey_bytes,
                                                     version_0).call()

    # Of course, now it fails if we try with version E
    assert not signature_verifier.functions.verifyEIP191(
        message, signature, umbral_pubkey_bytes, version_E).call()

    # Check that the hash-based method also works independently
    hash = signature_verifier.functions.hashEIP191(message, version_0).call()
    eip191_header = b"\x19\x00" + validator
    assert hash == keccak_digest(eip191_header + message)

    address = signature_verifier.functions.recover(hash, signature).call()
    assert address == checksum_address
示例#8
0
def verifycontract(ctx_obj, verbose, interactive, contract_address,
                   contract_name, solidity_compiler, optimization,
                   contract_file):
    """
    Verify and add a contract to your MaticVigil account that was previously deployed through a different interface, for eg. https://remix.ethereum.org
    """
    headers = {
        'accept': 'application/json',
        'Content-Type': 'application/json',
        'X-API-KEY': ctx_obj['settings']['MATICVIGIL_API_KEY']
    }
    main_contract_src = ''
    if not contract_file or interactive:
        contract_address = click.prompt('Contract address to be verified')
        contract_address = to_normalized_address(contract_address)
        contract_name = click.prompt('Contract name')
        contract_file = click.prompt('Location of Solidity file',
                                     type=click.Path(exists=True,
                                                     dir_okay=False))
        with open(contract_file, 'r') as f:
            while True:
                chunk = f.read(1024)
                if not chunk:
                    break
                main_contract_src += chunk
        click.secho('Getting a list of compiler versions...', fg='green')
        # get list of compilers
        compilers = dict()
        try:
            c_r = make_http_call(
                request_type='get',
                url=ctx_obj['settings']['INTERNAL_API_ENDPOINT'] +
                '/compilers',
                headers={'accept': 'application/json'})
        except Exception as e:
            click.echo('Exception retrieving list of compilers', err=True)
            if isinstance(e, EVHTTPError):
                click.echo(
                    'Possible HTTP error. Try with --verbose flag for more information',
                    err=True)
                if verbose:
                    click.echo(e.__str__(), err=True)
            elif isinstance(e, EVAPIError):
                click.echo(
                    'Possible API error.Try with --verbose flag for more information',
                    err=True)
                if verbose:
                    click.echo(e.__str__(), err=True)
            elif isinstance(e, EVBaseException) and verbose:
                click.echo(e.__str__(), err=True)
            sys.exit(1)
        if type(c_r['data']) == list:
            if len(c_r['data']) < 1:
                click.echo('Got empty list of compilers. Exiting...', err=True)
                sys.exit(1)
            for idx, each in enumerate(c_r['data']):
                compilers[idx] = each
            click.echo_via_pager(_gen_compilers_list(compilers))
        i = click.prompt('Select option from compiler versions above. Eg. 2',
                         type=int)
        solidity_compiler = compilers[i - 1]['full']
        optimization = click.confirm('Optimization enabled?')
    else:
        with open(contract_file, 'r') as f:
            while True:
                chunk = f.read(1024)
                if not chunk:
                    break
                main_contract_src += chunk
    msg = 'dummystring'
    message_hash = encode_defunct(text=msg)
    sig_msg = Account.sign_message(message_hash,
                                   ctx_obj['settings']['PRIVATEKEY'])
    method_args = {
        'msg': msg,
        'sig': sig_msg.signature.hex(),
        'contractAddress': contract_address,
        'skipCompiling': False,
        'name': contract_name,
        'version': solidity_compiler,
        'optimization': optimization,
        'code': main_contract_src
    }
    click.secho(
        f'Verifying contract {contract_name} at {contract_address} from source {contract_file}...',
        fg='bright_white')
    try:
        c_r = make_http_call(request_type='post',
                             url=ctx_obj['settings']['INTERNAL_API_ENDPOINT'] +
                             '/verify',
                             headers={'accept': 'application/json'},
                             params=method_args)
    except Exception as e:
        click.echo('Exception verifying contract', err=True)
        if isinstance(e, EVHTTPError):
            click.echo(
                'Possible HTTP error. Try with --verbose flag for more information',
                err=True)
            if verbose:
                click.echo(e.__str__(), err=True)
        elif isinstance(e, EVAPIError):
            click.echo(
                'Possible API error.Try with --verbose flag for more information',
                err=True)
            if verbose:
                click.echo(e.__str__(), err=True)
        elif isinstance(e, EVBaseException) and verbose:
            click.echo(e.__str__(), err=True)
        sys.exit(1)
    else:
        click.secho('Contract verified!', fg='green')
示例#9
0
def deploy(ctx_obj, contract_name, inputs, verbose, contract):
    """
    Deploys a smart contract from the solidity source code specified

    CONTRACT: path to the solidity file

    Usage example: mv-cli deploy contracts/Microblog.sol --contractName=Microblog --constructorInputs='JSON representation of the constructor arguments in an array'
    """
    constructor_input_prompt = False
    if contract_name:
        if verbose:
            click.echo('Got contract name: ')
            click.echo(contract_name)
    else:
        contract_name = click.prompt('Enter the contract name')
    if verbose:
        click.echo('Got constructor inputs: ')
        click.echo(inputs)
    if inputs:
        if verbose:
            click.echo('Got constructor inputs: ')
            click.echo(inputs)
        c_inputs = json.loads(inputs)
    else:
        constructor_input_prompt = True
        c_inputs = list()  # an empty list
    sources = dict()
    if contract[0] == '~':
        contract_full_path = os.path.expanduser(contract)
    else:
        contract_full_path = contract
    resident_directory = ''.join(
        map(lambda x: x + '/',
            contract_full_path.split('/')[:-1]))
    contract_file_name = contract_full_path.split('/')[-1]
    contract_file_obj = open(file=contract_full_path)

    main_contract_src = ''
    while True:
        chunk = contract_file_obj.read(1024)
        if not chunk:
            break
        main_contract_src += chunk
    sources[f'mv-cli/{contract_file_name}'] = {'content': main_contract_src}
    # loop through imports and add them to sources
    source_unit = parser.parse(main_contract_src)
    source_unit_obj = parser.objectify(source_unit)

    for each in source_unit_obj.imports:
        import_location = each['path'].replace("'", "")
        # TODO: follow specified relative paths and import such files too
        if import_location[:2] != './':
            click.echo(
                f'You can only import files from within the same directory as of now',
                err=True)
            return
        # otherwise read the file into the contents mapping
        full_path = resident_directory + import_location[2:]
        imported_contract_obj = open(full_path, 'r')
        contract_src = ''
        while True:
            chunk = imported_contract_obj.read(1024)
            if not chunk:
                break
            contract_src += chunk
        sources[f'mv-cli/{import_location[2:]}'] = {'content': contract_src}

    if len(c_inputs) == 0 and constructor_input_prompt:
        abi_json = extract_abi(ctx_obj['settings'], {
            'sources': sources,
            'sourceFile': f'mv-cli/{contract_file_name}'
        })
        abp = ABIParser(abi_json=abi_json)
        abp.load_abi()
        if len(abp.constructor_params()) > 0:
            click.echo('Enter constructor inputs...')
            for idx, each_param in enumerate(abp.constructor_params()):
                param_type = abp._constructor_mapping["constructor"][
                    "input_types"][idx]
                param_type_cat = abp.type_category(param_type)
                arg = click.prompt(f'{each_param}({param_type})')
                if param_type_cat == 'integer':
                    arg = int(arg)
                elif param_type_cat == 'array':
                    # check if it can be deserialized into a python dict
                    try:
                        arg_dict = json.loads(arg)
                    except json.JSONDecodeError:
                        click.echo(
                            f'Parameter {each_param} of type {param_type} '
                            f'should be correctly passed as a JSON array',
                            err=True)
                        sys.exit(1)
                c_inputs.append(arg)
    msg = "Trying to deploy"
    message_hash = encode_defunct(text=msg)
    # deploy from alpha account
    signed_msg = Account.sign_message(message_hash,
                                      ctx_obj['settings']['PRIVATEKEY'])
    deploy_json = {
        'msg': msg,
        'sig': signed_msg.signature.hex(),
        'name': contract_name,
        'inputs': c_inputs,
        'sources': sources,
        'sourceFile': f'mv-cli/{contract_file_name}'
    }
    # click.echo(deploy_json)
    # --MATICVIGIL API CALL---
    r = requests.post(ctx_obj['settings']['INTERNAL_API_ENDPOINT'] + '/deploy',
                      json=deploy_json)
    if verbose:
        click.echo('MaticVigil deploy response: ')
        click.echo(r.text)
    if r.status_code == requests.codes.ok:
        click.echo(f'Contract {contract_name} deployed successfully')
        r = r.json()
        click.echo(f'Contract Address: {r["data"]["contract"]}')
        click.echo(f'Deploying tx: {r["data"]["hash"]}')
    else:
        click.echo('Contract deployment failed')