mech-client 0.8.1__py3-none-any.whl → 0.9.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. mech_client/__init__.py +1 -1
  2. mech_client/cli.py +8 -0
  3. mech_client/marketplace_interact.py +18 -6
  4. {mech_client-0.8.1.dist-info → mech_client-0.9.0.dist-info}/METADATA +11 -1
  5. {mech_client-0.8.1.dist-info → mech_client-0.9.0.dist-info}/RECORD +30 -8
  6. scripts/__init__.py +1 -0
  7. scripts/benchmark.sh +32 -0
  8. scripts/bump.py +316 -0
  9. scripts/deposit_native.py +118 -0
  10. scripts/deposit_token.py +187 -0
  11. scripts/nvm_subscribe.py +51 -0
  12. scripts/nvm_subscription/contracts/agreement_manager.py +44 -0
  13. scripts/nvm_subscription/contracts/base_contract.py +75 -0
  14. scripts/nvm_subscription/contracts/did_registry.py +91 -0
  15. scripts/nvm_subscription/contracts/escrow_payment.py +85 -0
  16. scripts/nvm_subscription/contracts/lock_payment.py +76 -0
  17. scripts/nvm_subscription/contracts/nft.py +47 -0
  18. scripts/nvm_subscription/contracts/nft_sales.py +119 -0
  19. scripts/nvm_subscription/contracts/subscription_provider.py +107 -0
  20. scripts/nvm_subscription/contracts/token.py +87 -0
  21. scripts/nvm_subscription/contracts/transfer_nft.py +81 -0
  22. scripts/nvm_subscription/envs/base.env +10 -0
  23. scripts/nvm_subscription/envs/gnosis.env +10 -0
  24. scripts/nvm_subscription/manager.py +265 -0
  25. scripts/nvm_subscription/resources/networks.json +56 -0
  26. scripts/utils.py +127 -0
  27. scripts/whitelist.py +5 -0
  28. {mech_client-0.8.1.dist-info → mech_client-0.9.0.dist-info}/LICENSE +0 -0
  29. {mech_client-0.8.1.dist-info → mech_client-0.9.0.dist-info}/WHEEL +0 -0
  30. {mech_client-0.8.1.dist-info → mech_client-0.9.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,76 @@
1
+ # subscription/contracts/lock_payment.py
2
+ import logging
3
+ from typing import List, Union
4
+ from web3 import Web3
5
+ from eth_typing import ChecksumAddress
6
+ from web3.types import ENS
7
+
8
+ from .base_contract import BaseContract
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class LockPaymentConditionContract(BaseContract):
14
+ """
15
+ Wrapper class for the LockPaymentCondition smart contract.
16
+ Provides methods for computing hash and generating IDs.
17
+ """
18
+
19
+ def __init__(self, w3: Web3):
20
+ """
21
+ Initialize the LockPaymentConditionContract.
22
+
23
+ Args:
24
+ w3 (Web3): An instance of Web3 connected to the target Ethereum network.
25
+ """
26
+ logger.debug("Initializing LockPaymentConditionContract")
27
+ super().__init__(w3, name="LockPaymentCondition")
28
+ logger.info("LockPaymentConditionContract initialized")
29
+
30
+ def hash_values(
31
+ self,
32
+ did: str,
33
+ reward_address: Union[ChecksumAddress, ENS],
34
+ token_address: Union[ChecksumAddress, ENS],
35
+ amounts: List[int],
36
+ receivers: List[Union[ChecksumAddress, ENS]]
37
+ ) -> bytes:
38
+ """
39
+ Compute the hash of the condition parameters.
40
+
41
+ Args:
42
+ did (str): The decentralized identifier.
43
+ reward_address (ChecksumAddress | ENS): Address to receive the reward.
44
+ token_address (ChecksumAddress | ENS): ERC20 token address.
45
+ amounts (List[int]): List of amounts for each receiver.
46
+ receivers (List[ChecksumAddress | ENS]): List of receiver addresses.
47
+
48
+ Returns:
49
+ bytes: The keccak256 hash of the encoded values.
50
+ """
51
+ logger.debug("Computing hash for lock payment condition")
52
+ hash_ = self.functions().hashValues(
53
+ did,
54
+ reward_address,
55
+ token_address,
56
+ amounts,
57
+ receivers
58
+ ).call()
59
+ logger.debug(f"Computed hash: {hash_.hex()}")
60
+ return hash_
61
+
62
+ def generate_id(self, agreement_id: bytes, hash_value: bytes) -> bytes:
63
+ """
64
+ Generate a condition ID for a given agreement ID and hash.
65
+
66
+ Args:
67
+ agreement_id (str): ID of the agreement.
68
+ hash_value (bytes): Hashed condition parameters.
69
+
70
+ Returns:
71
+ bytes: The condition ID.
72
+ """
73
+ logger.debug("Generating condition ID from agreement ID and hash")
74
+ condition_id = self.functions().generateId(agreement_id, hash_value).call()
75
+ logger.info(f"Generated condition ID: {condition_id.hex()}")
76
+ return condition_id
@@ -0,0 +1,47 @@
1
+ # subscription/contracts/transfer_nft.py
2
+ import logging
3
+ from typing import Union
4
+ from web3 import Web3
5
+ from eth_typing import ChecksumAddress
6
+ from web3.types import ENS
7
+
8
+ from .base_contract import BaseContract
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class SubscriptionNFT(BaseContract):
14
+ """
15
+ Wrapper for the Token smart contract. Supports token balance
16
+ """
17
+
18
+ def __init__(self, w3: Web3):
19
+ """
20
+ Initialize the Subscription NFT instance.
21
+
22
+ Args:
23
+ w3 (Web3): A connected Web3 instance.
24
+ """
25
+ logger.debug("Initializing Subscription NFT")
26
+ super().__init__(w3, name="SubscriptionNFT")
27
+ logger.info("Subscription NFT initialized")
28
+
29
+ def get_balance(
30
+ self, sender: Union[ChecksumAddress, ENS], subscription_id: str
31
+ ) -> int:
32
+ """
33
+ Gets the user subscription credit balance.
34
+
35
+ Args:
36
+ sender (ChecksumAddress | ENS): User address.
37
+
38
+ Returns:
39
+ int: The user's credit balance.
40
+ """
41
+ sender_address: ChecksumAddress = self.w3.to_checksum_address(sender)
42
+
43
+ balance = (
44
+ self.functions().balanceOf(sender_address, int(subscription_id)).call()
45
+ )
46
+ logger.debug(f"Fetched Balance: {balance}")
47
+ return balance
@@ -0,0 +1,119 @@
1
+ # subscription/contracts/nft_sales.py
2
+ import logging
3
+ from typing import List, Any, Dict, Union
4
+ from web3 import Web3
5
+ from eth_typing import ChecksumAddress
6
+ from web3.types import ENS
7
+
8
+ from .base_contract import BaseContract
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class NFTSalesTemplateContract(BaseContract):
14
+ """
15
+ Wrapper class for the NFTSalesTemplate smart contract. Provides a method
16
+ to build a transaction for creating an agreement and paying escrow.
17
+ """
18
+
19
+ def __init__(self, w3: Web3):
20
+ """
21
+ Initialize the NFTSalesTemplateContract.
22
+
23
+ Args:
24
+ w3 (Web3): An instance of Web3 connected to an Ethereum network.
25
+ """
26
+ logger.debug("Initializing NFTSalesTemplateContract")
27
+ super().__init__(w3, name="NFTSalesTemplate")
28
+ logger.info("NFTSalesTemplateContract initialized")
29
+
30
+ def build_create_agreement_tx(
31
+ self,
32
+ agreement_id_seed: str,
33
+ did: str,
34
+ condition_seeds: List[bytes],
35
+ timelocks: List[int],
36
+ timeouts: List[int],
37
+ publisher: str,
38
+ service_index: int,
39
+ reward_address: str,
40
+ token_address: str,
41
+ amounts: List[int],
42
+ receivers: List[str],
43
+ sender: str,
44
+ value_eth: float,
45
+ gas: int = 600_000,
46
+ chain_id: int = 100
47
+ ) -> Dict[str, Any]:
48
+ """
49
+ Build a transaction dictionary to create an agreement and pay escrow.
50
+
51
+ Args:
52
+ agreement_id_seed (str): Unique identifier seed for the agreement.
53
+ did (str): Decentralized identifier.
54
+ condition_seeds (List[bytes]): List of hashed condition values.
55
+ timelocks (List[int]): Time locks for each condition.
56
+ timeouts (List[int]): Timeouts for each condition.
57
+ publisher (str): Ethereum address of the publisher.
58
+ service_index (int): Index of the service in the agreement.
59
+ reward_address (str): Address to receive the reward.
60
+ token_address (str): ERC20 token address.
61
+ amounts (List[int]): Payment amounts.
62
+ receivers (List[str]): List of payment receiver addresses.
63
+ sender (str): Ethereum address initiating the transaction.
64
+ value_eth (float): ETH value to include in the transaction.
65
+ gas (int, optional): Gas limit. Defaults to 600,000.
66
+ chain_id (int, optional): Ethereum network chain ID. Defaults to 100.
67
+
68
+ Returns:
69
+ Dict[str, Any]: Unsigned transaction dictionary.
70
+ """
71
+ logger.debug("Building transaction for createAgreementAndPayEscrow")
72
+ logger.debug(f"agreement_id_seed: {agreement_id_seed}")
73
+ logger.debug(f"did: {did}")
74
+ logger.debug(f"condition_seeds: {condition_seeds}")
75
+ logger.debug(f"timelocks: {timelocks}, timeouts: {timeouts}")
76
+ logger.debug(f"publisher: {publisher}, service_index: {service_index}")
77
+ logger.debug(f"reward_address: {reward_address}, token_address: {token_address}")
78
+ logger.debug(f"amounts: {amounts}, receivers: {receivers}")
79
+ logger.debug(f"sender: {sender}, value_eth: {value_eth}")
80
+
81
+ # Convert sender to a checksum address to ensure type safety
82
+ sender_address: ChecksumAddress = self.w3.to_checksum_address(sender)
83
+ nonce = self.w3.eth.get_transaction_count(sender_address)
84
+ logger.debug(f"Nonce for sender {sender_address}: {nonce}")
85
+
86
+ latest_block = self.w3.eth.get_block("latest")
87
+ base_fee = latest_block["baseFeePerGas"]
88
+ max_priority_fee = self.w3.eth.max_priority_fee
89
+
90
+ # Build the transaction using the contract method
91
+ tx = self.functions().createAgreementAndPayEscrow(
92
+ agreement_id_seed,
93
+ did,
94
+ condition_seeds,
95
+ timelocks,
96
+ timeouts,
97
+ self.w3.to_checksum_address(publisher),
98
+ service_index,
99
+ self.w3.to_checksum_address(reward_address),
100
+ self.w3.to_checksum_address(token_address),
101
+ amounts,
102
+ [self.w3.to_checksum_address(r) for r in receivers]
103
+ ).build_transaction({
104
+ "from": sender_address,
105
+ "value": self.w3.to_wei(value_eth, "ether"),
106
+ "chainId": chain_id,
107
+ "gas": gas,
108
+ "nonce": nonce,
109
+ })
110
+ gas = self.w3.eth.estimate_gas(tx)
111
+ tx.update({
112
+ "gas": gas,
113
+ "maxFeePerGas": base_fee + max_priority_fee,
114
+ "maxPriorityFeePerGas": max_priority_fee,
115
+ })
116
+
117
+ logger.info(f"Transaction built successfully for agreement ID: {agreement_id_seed}")
118
+ logger.debug(f"Transaction details: {tx}")
119
+ return tx
@@ -0,0 +1,107 @@
1
+ # subscription/contracts/subscription_provider.py
2
+ import logging
3
+ from typing import Union, List, Dict, Any
4
+ from web3 import Web3
5
+ from eth_typing import ChecksumAddress
6
+ from web3.types import ENS
7
+
8
+ from .base_contract import BaseContract
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class SubscriptionProvider(BaseContract):
14
+ """
15
+ Wrapper for the Token smart contract. Supports token balance
16
+ """
17
+
18
+ def __init__(self, w3: Web3):
19
+ """
20
+ Initialize the Subscription provider instance.
21
+
22
+ Args:
23
+ w3 (Web3): A connected Web3 instance.
24
+ """
25
+ logger.debug("Initializing Subscription provider")
26
+ super().__init__(w3, name="SubscriptionProvider")
27
+ logger.info("Subscription provider initialized")
28
+
29
+ def build_create_fulfill_tx(
30
+ self,
31
+ agreement_id_seed: str,
32
+ did: str,
33
+ fulfill_for_delegate_params: tuple,
34
+ fulfill_params: tuple,
35
+ sender: str,
36
+ value_eth: float,
37
+ gas: int = 450_000,
38
+ chain_id: int = 100,
39
+ ) -> Dict[str, Any]:
40
+ """
41
+ Build a transaction dictionary to create a fulfill tx.
42
+
43
+ Args:
44
+ agreement_id_seed (str): Unique identifier seed for the agreement.
45
+ did (str): Decentralized identifier.
46
+ condition_seeds (List[bytes]): List of hashed condition values.
47
+ timelocks (List[int]): Time locks for each condition.
48
+ timeouts (List[int]): Timeouts for each condition.
49
+ publisher (str): Ethereum address of the publisher.
50
+ service_index (int): Index of the service in the agreement.
51
+ reward_address (str): Address to receive the reward.
52
+ token_address (str): ERC20 token address.
53
+ amounts (List[int]): Payment amounts.
54
+ receivers (List[str]): List of payment receiver addresses.
55
+ sender (str): Ethereum address initiating the transaction.
56
+ value_eth (float): ETH value to include in the transaction.
57
+ gas (int, optional): Gas limit. Defaults to 450,000.
58
+ chain_id (int, optional): Ethereum network chain ID. Defaults to 100.
59
+
60
+ Returns:
61
+ Dict[str, Any]: Unsigned transaction dictionary.
62
+ """
63
+ logger.debug("Building transaction for fulfill")
64
+ logger.debug(f"agreement_id_seed: {agreement_id_seed}")
65
+ logger.debug(f"did: {did}")
66
+ logger.debug(f"sender: {sender}, value_eth: {value_eth}")
67
+
68
+ # Convert sender to a checksum address to ensure type safety
69
+ sender_address: ChecksumAddress = self.w3.to_checksum_address(sender)
70
+ nonce = self.w3.eth.get_transaction_count(sender_address)
71
+ logger.debug(f"Nonce for sender {sender_address}: {nonce}")
72
+
73
+ latest_block = self.w3.eth.get_block("latest")
74
+ base_fee = latest_block["baseFeePerGas"]
75
+ max_priority_fee = self.w3.eth.max_priority_fee
76
+
77
+ logger.debug(f"fulfill_for_delegate_params: {fulfill_for_delegate_params}")
78
+ logger.debug(f"fulfill_params: {fulfill_params}")
79
+
80
+ # Build the transaction using the contract method
81
+ tx = (
82
+ self.functions()
83
+ .fulfill(
84
+ agreement_id_seed, did, fulfill_for_delegate_params, fulfill_params
85
+ )
86
+ .build_transaction(
87
+ {
88
+ "from": sender_address,
89
+ "value": self.w3.to_wei(value_eth, "ether"),
90
+ "chainId": chain_id,
91
+ "gas": gas,
92
+ "nonce": nonce,
93
+ }
94
+ )
95
+ )
96
+ gas = self.w3.eth.estimate_gas(tx)
97
+ tx.update(
98
+ {
99
+ "gas": gas,
100
+ "maxFeePerGas": base_fee + max_priority_fee,
101
+ "maxPriorityFeePerGas": max_priority_fee,
102
+ }
103
+ )
104
+
105
+ logger.info(f"Transaction built successfully for fulfill: {agreement_id_seed}")
106
+ logger.debug(f"Transaction details: {tx}")
107
+ return tx
@@ -0,0 +1,87 @@
1
+ # subscription/contracts/transfer_nft.py
2
+ import logging
3
+ from typing import Union
4
+ from web3 import Web3
5
+ from eth_typing import ChecksumAddress
6
+ from web3.types import ENS
7
+
8
+ from .base_contract import BaseContract
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class SubscriptionToken(BaseContract):
14
+ """
15
+ Wrapper for the Token smart contract. Supports approve token
16
+ """
17
+
18
+ def __init__(self, w3: Web3):
19
+ """
20
+ Initialize the Token instance.
21
+
22
+ Args:
23
+ w3 (Web3): A connected Web3 instance.
24
+ """
25
+ logger.debug("Initializing Subscription Token")
26
+ super().__init__(w3, name="SubscriptionToken")
27
+ logger.info("Token initialized")
28
+
29
+ def build_approve_token_tx(
30
+ self,
31
+ sender: Union[ChecksumAddress, ENS],
32
+ to: Union[ChecksumAddress, ENS],
33
+ amount: int,
34
+ gas: int = 60_000,
35
+ chain_id: int = 100,
36
+ ) -> bytes:
37
+ """
38
+ Compute the hash of parameters for the transfer condition.
39
+
40
+ Args:
41
+ sender (ChecksumAddress | ENS): Address sending the approve tx.
42
+ to_address (ChecksumAddress | ENS): Address getting the approval.
43
+ amount (int): Number of tokens to approve.
44
+ gas (int, optional): Gas limit. Defaults to 60,000.
45
+ chain_id (int, optional): Ethereum network chain ID. Defaults to 100.
46
+
47
+ Returns:
48
+ Dict[str, Any]: Unsigned transaction dictionary.
49
+ """
50
+ logger.debug("Approving token...")
51
+ sender_address: ChecksumAddress = self.w3.to_checksum_address(sender)
52
+ to_address: ChecksumAddress = self.w3.to_checksum_address(to)
53
+ nonce = self.w3.eth.get_transaction_count(sender_address)
54
+ logger.debug(f"Nonce for sender {sender_address}: {nonce}")
55
+
56
+ latest_block = self.w3.eth.get_block("latest")
57
+ base_fee = latest_block["baseFeePerGas"]
58
+ max_priority_fee = self.w3.eth.max_priority_fee
59
+
60
+ tx = (
61
+ self.functions()
62
+ .approve(
63
+ to_address,
64
+ amount,
65
+ )
66
+ .build_transaction(
67
+ {
68
+ "from": sender,
69
+ "value": 0,
70
+ "chainId": chain_id,
71
+ "gas": gas,
72
+ "nonce": nonce,
73
+ }
74
+ )
75
+ )
76
+ gas = self.w3.eth.estimate_gas(tx)
77
+ tx.update(
78
+ {
79
+ "gas": gas,
80
+ "maxFeePerGas": base_fee + max_priority_fee,
81
+ "maxPriorityFeePerGas": max_priority_fee,
82
+ }
83
+ )
84
+
85
+ logger.info("Transaction built successfully for token approve")
86
+ logger.debug(f"Transaction details: {tx}")
87
+ return tx
@@ -0,0 +1,81 @@
1
+ # subscription/contracts/transfer_nft.py
2
+ import logging
3
+ from typing import Union
4
+ from web3 import Web3
5
+ from eth_typing import ChecksumAddress
6
+ from web3.types import ENS
7
+
8
+ from .base_contract import BaseContract
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class TransferNFTConditionContract(BaseContract):
14
+ """
15
+ Wrapper for the TransferNFTCondition smart contract. Supports hash and ID generation.
16
+ """
17
+
18
+ def __init__(self, w3: Web3):
19
+ """
20
+ Initialize the TransferNFTConditionContract instance.
21
+
22
+ Args:
23
+ w3 (Web3): A connected Web3 instance.
24
+ """
25
+ logger.debug("Initializing TransferNFTConditionContract")
26
+ super().__init__(w3, name="TransferNFTCondition")
27
+ logger.info("TransferNFTConditionContract initialized")
28
+
29
+ def hash_values(
30
+ self,
31
+ did: str,
32
+ from_address: Union[ChecksumAddress, ENS],
33
+ to_address: Union[ChecksumAddress, ENS],
34
+ amount: int,
35
+ lock_condition_id: bytes,
36
+ nft_contract_address: Union[ChecksumAddress, ENS],
37
+ _is_transfer: bool,
38
+ ) -> bytes:
39
+ """
40
+ Compute the hash of parameters for the transfer condition.
41
+
42
+ Args:
43
+ did (str): Decentralized identifier.
44
+ from_address (ChecksumAddress | ENS): Address sending the NFT.
45
+ to_address (ChecksumAddress | ENS): Address receiving the NFT.
46
+ amount (int): Number of tokens to transfer.
47
+ lock_condition_id (bytes): Lock payment condition ID.
48
+ nft_contract_address (ChecksumAddress | ENS): NFT contract address.
49
+ is_escrow (bool): Indicates if escrow is involved.
50
+
51
+ Returns:
52
+ bytes: Hashed value.
53
+ """
54
+ logger.debug("Computing transfer NFT hash value")
55
+ hash_ = self.functions().hashValues(
56
+ did,
57
+ from_address,
58
+ to_address,
59
+ amount,
60
+ lock_condition_id,
61
+ nft_contract_address,
62
+ _is_transfer
63
+ ).call()
64
+ logger.debug(f"Transfer NFT hash: {hash_.hex()}")
65
+ return hash_
66
+
67
+ def generate_id(self, agreement_id: bytes, hash_value: bytes) -> bytes:
68
+ """
69
+ Generate the condition ID for the transfer NFT condition.
70
+
71
+ Args:
72
+ agreement_id (str): ID of the agreement.
73
+ hash_value (bytes): Hashed condition parameters.
74
+
75
+ Returns:
76
+ bytes: Condition ID.
77
+ """
78
+ logger.debug("Generating transfer NFT condition ID")
79
+ condition_id = self.functions().generateId(agreement_id, hash_value).call()
80
+ logger.info(f"Transfer NFT condition ID: {condition_id.hex()}")
81
+ return condition_id
@@ -0,0 +1,10 @@
1
+ export NETWORK_NAME="BASE"
2
+ export CHAIN_ID=8453
3
+ export SUBSCRIPTION_NFT_ADDRESS="0xd5318d1a17819f65771b6c9277534c08dd765498"
4
+ export OLAS_MARKETPLACE_ADDRESS="0xaaFBeef195BDAb1Bb6f3Dc9cEbA875Cd72499230"
5
+ export RECEIVER_PLAN="0xaaFBeef195BDAb1Bb6f3Dc9cEbA875Cd72499230"
6
+ export TOKEN_ADDRESS="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" #USDC
7
+ export PLAN_DID="did:nv:6f74c18fae7e5c3589b99d7cd0ba317593f00dee53c81a2ba4ac2244232f99da"
8
+ export SUBSCRIPTION_CREDITS="1000000"
9
+ export PLAN_FEE_NVM="10000"
10
+ export PLAN_PRICE_MECHS="990000"
@@ -0,0 +1,10 @@
1
+ export NETWORK_NAME="GNOSIS"
2
+ export CHAIN_ID=100
3
+ export SUBSCRIPTION_NFT_ADDRESS="0x1b5DeaD7309b56ca7663b3301A503e077Be18cba"
4
+ export OLAS_MARKETPLACE_ADDRESS="0x7D686bD1fD3CFF6E45a40165154D61043af7D67c"
5
+ export RECEIVER_PLAN="0x7D686bD1fD3CFF6E45a40165154D61043af7D67c"
6
+ export TOKEN_ADDRESS="0x0000000000000000000000000000000000000000" # xDAI
7
+ export PLAN_DID="did:nv:b0b28402e5a7229804579d4ac55b98a1dd94660d7a7eb4add78e5ca856f2aab7"
8
+ export SUBSCRIPTION_CREDITS="1000000"
9
+ export PLAN_FEE_NVM="10000000000000000"
10
+ export PLAN_PRICE_MECHS="990000000000000000"