Example #1
0
    def load(self, name=None, address=None, owner_address=None):
        """

        Load a contract details using it's registered name or directly using it's known address.

        :param str name: Name of the contract that has been registered.
        If provided the address and owner_address of the registration is stored within this object

        :param str, int, Account address: Address of the contract, if the name is not known,
        then you can provide the actual address of the contract.

        :param str, int, Account owner_address: If the contract is registered the owner address of the resgistration.

        :returns int The address of the resolved contract

        """
        if name:
            address = self.resolve_address(name)
            owner_address = self.resolve_owner_address(name)
            self._name = name

        if address is None:
            raise ValueError('no contract found')

        if owner_address is None:
            owner_address = address

        self._address = to_address(address)
        self._owner_address = to_address(owner_address)
        return self._address
Example #2
0
    def get_balance(self, address_account, account_from=None):
        """

        Get a balance of an account.

        At the moment the account needs to have a balance to get the balance of it's account or any
        other account. Event though this is using a query request.

        :param address_account: Address or :class:`.Account` object to get the funds for.
        :type address_account: Account, int, str

        :param account_from: Optional :class:`.Account` object or account address to make the request.
        :type account_from: Account, int, str, optional


        :returns: Return the current balance of the address or account `address_account`

        .. code-block:: python

            >>> # Create a new account with new public/priavte keys and address
            >>> account = convex_api.create_account()
            >>> # get the balance of the contract
            >>> print(convex_api.get_balance(account))
            0
            >>> print(convex_api.request_funds(100000, account))
            100000
            >>> print(convex_api.get_balance(account))
            100000

        """
        value = 0
        if is_address(address_account):
            address = to_address(address_account)
        else:
            address = address_account.address

        address_from = address
        if account_from:
            if is_address(account_from):
                address_from = to_address(account_from)
            else:
                address_from = account_from.address
        line = f'(balance #{address})'
        """
        if self._language == API.LANGUAGE_SCRYPT:
            line = f'balance(#{address})'
        """
        try:

            result = self._transaction_query(address_from, line)
        except ConvexAPIError as error:
            if error.code != 'NOBODY':
                raise
        else:
            value = result['value']
        return value
Example #3
0
    def get_address(self, function_name, address_account):
        """

        Query the network for a contract ( function ) address. The contract must have been deployed
        by the account address provided. If not then no address will be returned

        :param str function_name: Name of the contract/function

        :param address_account: :class:`.Account` object or str address of an account to use for running this query.
        :type address_account: Account, int, str


        :returns: Returns address of the contract

        .. code-block:: python

            >>> # Create a new account with new public/priavte keys and address
            >>> account = convex_api.create_account()
            >>> # find the address of a contract
            >>> print(convex_api.get_address('my_contract', account))

        """

        line = f'(address {function_name})'
        """
        if self._language == API.LANGUAGE_SCRYPT:
            line = f'address({function_name})'
        """
        result = self.query(line, address_account)
        if result and 'value' in result:
            return to_address(result['value'])
Example #4
0
 def address(self):
     if self._address is None:
         result = self._convex.query('(address *registry*)',
                                     QUERY_ACCOUNT_ADDRESS)
         self._registry_address = to_address(result['value'])
         logger.debug(f'registry_address: {self._registry_address}')
     return self._registry_address
Example #5
0
def test_convex_api_call(convex_url):

    deploy_storage = """
(def storage-example
    (deploy
        '(do
            (def stored-data nil)
            (defn get [] stored-data)
            (defn set [x] (def stored-data x))
            (export get set)
        )
    )
)
"""
    convex = API(convex_url)
    key_pair = KeyPair()
    account = convex.create_account(key_pair)
    amount = TEST_FUNDING_AMOUNT
    request_amount = convex.request_funds(amount, account)
    result = convex.send(deploy_storage, account)
    assert(result['value'])
    contract_address = to_address(result['value'])
    test_number = secrets.randbelow(1000)
    call_set_result = convex.send(f'(call storage-example(set {test_number}))', account)
    assert(call_set_result['value'] == test_number)
    call_get_result = convex.query('(call storage-example(get))', account)
    assert(call_get_result['value'] == test_number)

    # now api calls using language scrypt
    """
Example #6
0
    def _transaction_prepare(self,
                             transaction,
                             address,
                             language=None,
                             sequence_number=None):
        """

        """
        if language is None:
            language = self._language
        prepare_url = urljoin(self._url, '/api/v1/transaction/prepare')
        data = {
            'address': to_address(address),
            'lang': language,
            'source': transaction,
        }
        if sequence_number:
            data['sequence'] = sequence_number
        logger.debug(f'_transaction_prepare {prepare_url} {data}')

        result = self._transaction_post(prepare_url, data)

        logger.debug(f'_transaction_prepare repsonse {result}')
        if 'errorCode' in result:
            raise ConvexAPIError('_transaction_prepare', result['errorCode'],
                                 result['value'])

        return result
Example #7
0
def process_convex_depoly(convex, result_value):
    deploy_storage = """
(def storage-example
    (deploy
        '(do
            (def stored-data nil)
            (defn get [] stored-data)
            (defn set [x] (def stored-data x))
            (export get set)
        )
    )
)
"""
    key_pair = KeyPair()
    account = convex.create_account(key_pair)
    for index in range(0, 10):
        convex.topup_account(account)
        try:
            result = convex.send(deploy_storage, account)
        except ConvexAPIError as e:
            balance = convex.get_balance(account)
            print('*' * 132)
            print('failed send', e, balance)
            print('*' * 132)
            result_value.value = balance
            return
        assert (result)
        assert (result['value'])
        contract_address = to_address(result['value'])
        assert (contract_address)
    result_value.value = 1
 def convert_event_list(items):
     event_list = []
     for item in items:
         event_list.append({
             'timestamp': item['timestamp'],
             'owner': to_address(item['owner']),
         })
     return event_list
def test_convex_recursion(convex, test_account):
    chain_length = 4
    address_list = []
    for index in range(0, chain_length):
        contract = f"""
(def chain-{index}
    (deploy
        '(do
            (def stored-data
                ^{{:private? true}}
                nil
            )
            (def chain-address
                ^{{:private? true}}
                nil
            )
            (defn get
                ^{{:callable? true}}
                []
                (call chain-address (get))
            )
            (defn set
                ^{{:callable? true}}
                [x]
                ( if chain-address (call chain-address(set x)) (def stored-data x))
            )
            (defn set-chain-address
                ^{{:callable? true}}
                [x]
                (def chain-address x)
            )
        )
    )
)
"""
        convex.topup_account(test_account)
        result = convex.send(contract, test_account)
        address_list.append(to_address(result['value']))
    for index in range(0, chain_length):
        next_index = index + 1
        if next_index == chain_length:
            next_index = 0
        call_address = address_list[next_index]
        result = convex.send(
            f'(call chain-{index} (set-chain-address #{call_address}))',
            test_account)
        test_number = secrets.randbelow(1000)
        if index == chain_length - 1:
            with pytest.raises(ConvexAPIError, match='DEPTH'):
                result = convex.send(
                    f'(call chain-{index} (set {test_number}))', test_account)
        else:
            result = convex.send(f'(call chain-0 (set {test_number}))',
                                 test_account)
            assert (result)
            assert (result['value'] == test_number)
    with pytest.raises(ConvexAPIError, match='DEPTH'):
        convex.query('(call chain-0 (get))', test_account)
 def register(self, asset_id: str, data: str, account: ConvexAccount):
     quote_data = ContractBase.escape_string(data)
     command = f'(register {add_0x_prefix(asset_id)} "{quote_data}")'
     result = self.send(command, account)
     if result and 'value' in result:
         return {
             'timestamp': result['value']['timestamp'],
             'owner': to_address(result['value']['owner']),
         }
     return result
Example #11
0
 def owner(self, did: str,  account_address: AccountAddress):
     did_id = did_to_id(did).lower()
     command = f'(owner {did_id})'
     if is_address(account_address):
         address = account_address
     else:
         address = account_address.address
     result = self.query(command, address)
     if result and 'value' in result:
         return to_address(result['value'])
     return result
Example #12
0
    def register_account_name(self, name, address_account, account=None):
        """

        Register or update an account address with an account name.

        This call will submit to the CNS (Convex Name Service), a name in the format
        "`account.<your_name>`". You need to have some convex balance in your account, and
        a valid account address.

        :param str name: name of the account to register.
        :param number|Account account_address: Account or address to register.
        :param Account account: :class:`.Account` object to register the account name.

        .. code-block:: python

            >>> # load the register account
            >>> register_account = convex.load_account('register_account', key_pair)
            >>> account = convex.create_account(key_pair)
            >>> print(account.address)
            1024
            >>> account = convex.register_account('my_new_account', account.address, register_account)
            >>> print(account.address)
            1024

            # or you can call with only one account, this will use the address of that account
            >>> print(register_account.address)
            404
            >>> account = convex.register_account('my_new_account', register_account)
            >>> print(account.address)
            404

        """

        # is the address_account field only an address?
        if is_address(address_account):
            address = to_address(address_account)
        else:
            # if account then use the account address, and also see if we can use it for the
            # registration
            address = address_account.address
            if account is None:
                account = address_account

        # we must have a valid account to do the registration
        if not account:
            raise ValueError('you need to provide a registration account to register an account name')

        if not address:
            raise ValueError('You need to provide a valid address to register an account name')

        self._registry.register(f'account.{name}', address, account)
        return Account(account.key_pair, address=address, name=name)
Example #13
0
def test_utils_is_address():
    address_int = secrets.randbelow(pow(2, 1024)) + 1
    assert (is_address(address_int))

    address_str = str(address_int)
    assert (is_address(address_str))

    address = to_address(f'#{address_str}')
    assert (address == address_int)

    assert (not is_address('test'))
    assert (not is_address(' #'))
    assert (is_address('#0'))
    assert (not is_address('#-1'))
Example #14
0
    def create_account(self, key_pair, sequence_retry_count=20):
        """

        Create a new account address on the convex network.

        :param `KeyPair` key_pair: :class:`.KeyPair` object that you whish to use as the signing account.
            The :class:`.KeyPair` object contains the public/private keys to access and submit commands
            on the convex network.


        :param sequence_retry_count: Number of retries to create the account. If too many clients are trying to
            create accounts on the same node, then we will get sequence errors.
        :type sequence_retry_count: int, optional

        :returns: A new :class:`.Account` object, or copy of the :class:`.Account` object with a new `address` property value set


        .. code-block:: python

            >>> from convex_api import API
            >>> convex = API('https://convex.world')
            >>> # Create a new account with new public/priavte keys and address
            >>> key_pair = KeyPair()
            >>> account = convex.create_account(key_pair)
            >>> print(account.address)
            >>> 42

            >>> #create a new account address, but use the same keys as `account`
            >>> new_account_address = convex.create_account(account=account)
            >>> print(new_account.address)
            >>> 43


        """

        if key_pair and not isinstance(key_pair, KeyPair):
            raise TypeError(
                f'key_pair value {key_pair} must be a type convex_api.KeyPair')

        create_account_url = urljoin(self._url, '/api/v1/createAccount')
        account_data = {
            'accountKey': key_pair.public_key_api,
        }

        logger.debug(f'create_account {create_account_url} {account_data}')
        result = self._transaction_post(create_account_url, account_data)
        logger.debug(f'create_account result {result}')
        account = Account(key_pair, to_address(result['address']))
        return account
Example #15
0
    def transfer(self, to_address_account, amount, account):
        """

        Transfer funds from on account to another.

        :param to_address_account: Address or :class:`.Account` object to send the funds too
        :type to_address_account: Account, int, str

        :param number amount: Amount to transfer

        :param Account account: :class:`.Account` object to send the funds from

        :returns: The transfer record sent back after the transfer has been made

        .. code-block:: python

            >>> # Create a new account with new public/priavte keys and address
            >>> account = convex_api.create_account()
            >>> print(convex_api.request_funds(10000000, account))
            10000000
            >>> print(convex_api.get_balance(account))
            10000000

            >>> my_account = convex_api.create_account()
            >>> # transfer some funds to my_account
            >>> print(convex_api.transfer(my_account, 100, account))
            100
            >>> print(convex_api.get_balance(my_account))
            100
            >>> print(convex_api.get_balance(account))
            9998520

        """
        if is_address(to_address_account):
            transfer_to_address = to_address(to_address_account)
        else:
            transfer_to_address = to_address_account.address
        if not to_address:
            raise ValueError(f'You must provide a valid to account/address ({transfer_to_address}) to transfer funds too')

        line = f'(transfer #{transfer_to_address} {amount})'
        """
        if self._language == API.LANGUAGE_SCRYPT:
            line = f'transfer(#{transfer_to_address}, {amount})'
        """
        result = self.send(line, account)
        if result and 'value' in result:
            return result['value']
        return 0
def test_provenance_contract_event_owner_list(convex, provenance_contract,
                                              accounts, register_test_list):
    account_other = accounts[1]
    topup_accounts(convex, account_other)
    record = register_test_list[secrets.randbelow(len(register_test_list))]
    owner_count = 0
    for item in register_test_list:
        if item['owner'] == record['owner']:
            owner_count += 1
    owner_address = to_address(record['owner'])
    result = provenance_contract.query(f'(owner-list {owner_address})',
                                       account_other)
    asset_list = result['value']
    assert (asset_list)
    assert (len(asset_list) >= owner_count)
def test_schedule_transfer(convex, test_account, other_account):
    # you can send coins to an actor , if it exports the receive-coin function

    contract = """
(def transfer-for-ever
    (deploy
        '(do
            (defn tx-delay
                ^{:callable? true}
                [to-address amount]
                (transfer to-address amount)
                (def call-address *address*)
                (schedule (+ *timestamp* 1000) (call call-address (tx-delay to-address amount)))
            )
            (defn tx-now
                ^{:callable? true}
                [to-address amount]
                (transfer to-address amount)
            )
            (defn show-schedule
                ^{:callable? true}
                []
                [(get *state* :schedule) *address*]
            )
            (defn receive-coin
                ^{:callable? true}
                [sender amount data]
                (accept amount)
            )
        )
    )
)
"""
    # (call contract-address (tx-to to-address amount))

    convex.topup_account(test_account)
    convex.topup_account(other_account, 8000000)
    result = convex.send(contract, test_account)
    contract_address = to_address(result['value'])
    convex.transfer(contract_address, 800000, other_account)
    convex.topup_account(test_account)
    result = convex.send(
        f'(call #{contract_address} (tx-delay #{other_account.address} 1000))',
        test_account)
    print(result)
    result = convex.send(f'(call #{contract_address} (show-schedule))',
                         test_account)
    print(result)
Example #18
0
    def deploy(self,
               account,
               text=None,
               filename=None,
               name=None,
               owner_account=None):
        """

        Deploy a new/updated contract on the convex network.

        :param Account account: Account to use to deploy the contract

        :param str text: Contract text to deploy

        :param str filename: Filename of the contract to deploy

        :param str name: Name of the contract to register

        :param Account onwer_account: Optional owner account of the registration.
        If not provided then the Account will be used.

        :returns Address of the new contract

        """
        if filename:
            with open(filename, 'r') as fp:
                text = fp.read()
        if text is None:
            raise ValueError(
                'You need to provide a contract filename or text to deploy')
        deploy_line = f"""
(deploy
    (quote
        (do
            {text}
        )
    )
)
    """
        result = self._convex.send(deploy_line, account)
        if result and 'value' in result:
            address = to_address(result["value"])
            if name:
                if owner_account is None:
                    owner_account = account
                self._convex.registry.register(name, address, owner_account)
            return address
Example #19
0
    def _transaction_submit(self, address, public_key, hash_data, signed_data):
        """

        """
        submit_url = urljoin(self._url, '/api/v1/transaction/submit')
        data = {
            'address': to_address(address),
            'accountKey': public_key,
            'hash': hash_data,
            'sig': remove_0x_prefix(signed_data)
        }
        logger.debug(f'_transaction_submit {submit_url} {data}')
        result = self._transaction_post(submit_url, data)
        logger.debug(f'_transaction_submit response {result}')
        if 'errorCode' in result:
            raise ConvexAPIError('_transaction_submit', result['errorCode'],
                                 result['value'])
        return result
    def deploy(self, account: Account):
        if not self._source:
            raise ValueError(f'Cannot deploy the contract {self.name} with no source text')

        deploy_line = f"""
    (deploy
        (quote
            (do
                {self._source}
            )
        )
    )
"""
        # print(deploy_line)
        result = self._convex.send(deploy_line, account)
        if result and 'value' in result:
            self._address = to_address(result["value"])
            return self._address
Example #21
0
    def address(self, value):
        """

        Sets the network address of this account

        :param value: Address to use for this account
        :type value: str, int

        .. code-block:: python

            >>> # import the account keys
            >>> key_pair = KeyPair.import_from_mnemonic('my private key words ..')

            >>> account = convex.create_account(key_pair)
            >>> # set the address that was given to us when we created the account on the network
            >>> account.address = 42

        """
        self._address = to_address(value)
Example #22
0
    def __init__(self, key_pair, address, name=None):
        """

        Create a new account with a private key KeyPair.

        :param KeyPair key_pair: The public/private key of the account

        :param int address: address of the account

        :param str name: Optional name of the account

        .. code-block:: python

            >>> # import convex-api
            >>> from convex_api import API, KeyPair, Account

            >>> # setup the network connection
            >>> convex = API('https://convex.world')

            >>> # create a random keypair
            >>> key_pair = KeyPair()

            >>> # create a new account and address
            >>> account = convex.create_account(key_pair)

            >>> # export the private key to a file
            >>> key_pair.export_to_file('/tmp/my_account.pem', 'my secret password')

            >>> # save the address for later
            >>> my_address = account.address

            >>> # ----

            >>> # now import the account and address for later use
            >>> key_pair = KeyPair.import_from_file('/tmp/my_account.pem', 'my secret password')
            >>> account = Account(key_pair, my_address)


        """
        self._key_pair = key_pair
        self._address = to_address(address)
        self._name = name
Example #23
0
    def get_account_info(self, address_account):
        """

        Get account information. This will only work with an account that has a balance or has had some transactions
        processed on the convex network. New accounts with no transfer or transactions will raise:

            ConvexRequestError(404, 'The Account for this Address does not exist.') error

        The returned information is dictionary of account information.

        :param address_account: :class:`.Account` object or address of an account to get current information on.
        :type address_account: Account, int, str

        :returns: dict of information, such as

        .. code-block:: python

            >>> # Create a new account with new public/priavte keys and address
            >>> account = convex_api.create_account()
            >>> # get the balance of the contract
            >>> print(convex_api.get_account_info(account))

            {'environment': {}, 'address': 1178, 'memorySize': 0, 'balance': 0,
            'isLibrary': False, 'isActor': False, 'allowance': 0,
            'sequence': 0, 'type': 'user'}

        """
        if is_address(address_account):
            address = to_address(address_account)
        else:
            address = address_account.address

        account_url = urljoin(self._url, f'/api/v1/accounts/{address}')
        logger.debug(f'get_account_info {account_url}')

        response = requests.get(account_url)
        if response.status_code != 200:
            raise ConvexRequestError('get_account_info', response.status_code, response.text)

        result = response.json()
        logger.debug(f'get_account_info repsonse {result}')
        return result
Example #24
0
    def query(self, transaction, account_address=None):
        """

        Sends a query to the contract.

        :param str transaction: The transaction query to send to the contract

        :param str, int, Account account_address: The address to provide as the sender for this query.

        :returns The query result

        """
        if not self._address:
            raise ValueError(f'No contract address found for {self._name}')
        if account_address is None:
            account_address = to_address(account_address)
        if account_address is None:
            account_address = self._address
        return self._convex.query(f'(call #{self._address} {transaction})',
                                  account_address)
Example #25
0
    def query(self, transaction, address_account, language=None):
        """

        Run a query transaction on the block chain. Since this does not change the network state, and
        the account does not need to sign the transaction. No funds will be used when executing
        this query. For this reason you can just pass the account address, or if you want to the :class:`.Account` object.

        :param str transaction: Transaction to execute. This can only be a read only transaction.

        :param address_account: :class:`.Account` object or int address of an account to use for running this query.
        :type address_account: Account, int, str

        :param language: The type of language to use, if not provided the default language set will be used.
        :type language: str, optional

        :returns: Return the resultant query transaction


        .. code-block:: python

            >>> # Create a new account with new public/priavte keys and address
            >>> account = convex_api.create_account()

            >>> # submit a query transaction using the account address

            >>> print(convex_api.query(f'(balance {account.address})', account.address))
            {'value': 0}

            >>> # request some funds to do stuff
            >>> print(convex_api.request_funds(100000, account))
            100000
            >>> print(convex_api.query(f'(balance {account.address})', account.address))
            {'value': 100000}

        """
        if is_address(address_account):
            address = to_address(address_account)
        else:
            address = address_account.address

        return self._transaction_query(address, transaction, language)
def test_convex_registry_register_update(registry, convex_network,
                                         convex_accounts):
    convex = convex_network.convex

    contract_name = f'starfish-test.{secrets.token_hex(8)}'
    owner_address = registry.resolve_owner(contract_name)
    assert (owner_address is None)

    # deploy function get set
    account = convex_accounts[0]
    convex.topup_account(account)
    result = convex.send(TEST_DEPLOY, account)
    assert (result)
    assert ('value' in result)
    contract_address = to_address(result["value"])
    assert (contract_address)

    # register with standard text name
    owner_address = registry.resolve_owner(TEST_CONTRACT_NAME)
    if owner_address:
        account.address = owner_address

    result = registry.register(TEST_CONTRACT_NAME, contract_address, account)
    assert (result)
Example #27
0
def DISABLED_test_convex_api_query_scrypt(convex_url, test_account):
    convex = API(convex_url, API.LANGUAGE_SCRYPT)
    result = convex.query(f'address({test_account.address})', test_account)
    assert(result)
    # return value is the address as a checksum
    assert(to_address(result['value']) == test_account.address)
Example #28
0
def test_convex_api_query_lisp(convex_url, test_account):
    convex = API(convex_url)
    result = convex.query(f'(address {test_account.address})', test_account)
    assert(result)
    # return value is the address as a checksum
    assert(to_address(result['value']) == test_account.address)