|
5 | 5 | - Using Arkiv with existing web3.py code |
6 | 6 | - Accessing raw Web3 functionality |
7 | 7 | - Mixing Arkiv operations with standard Web3 calls |
| 8 | +- Full CRUD lifecycle (create, read, update, delete) |
8 | 9 |
|
9 | | -Run this example: python examples/04_web3_integration.py |
| 10 | +Run this example: uv run python -m arkiv_starter.04_web3_integration |
10 | 11 | """ |
11 | 12 |
|
12 | 13 | from arkiv.provider import ProviderBuilder |
13 | | -from eth_account import Account |
14 | | -from web3 import Web3 |
15 | | - |
16 | | -from arkiv import Arkiv |
| 14 | +from arkiv import Arkiv, NamedAccount |
17 | 15 | from arkiv.node import ArkivNode |
| 16 | +from web3 import Web3 |
| 17 | +from typing import cast |
| 18 | +from web3.providers.base import BaseProvider |
18 | 19 |
|
19 | 20 | # Setup: Start node and create client |
20 | 21 | print("π Starting local Arkiv node...") |
21 | 22 | node = ArkivNode() |
22 | 23 | node.start() |
23 | 24 |
|
| 25 | +# Create and fund account |
24 | 26 | provider = ProviderBuilder().node(node).build() |
25 | | -client = Arkiv(provider) |
| 27 | +provider = cast(BaseProvider, provider) # cast for static type checkers |
26 | 28 |
|
27 | 29 | # Create and fund account |
28 | | -account = Account.create() |
| 30 | +account = NamedAccount.create("web3-integration") |
29 | 31 | node.fund_account(account) |
30 | | -client.eth.default_account = account |
| 32 | + |
| 33 | +# Initialize client with account |
| 34 | +client = Arkiv(provider, account=account) |
31 | 35 | print(f"β
Account ready: {account.address}\n") |
32 | 36 |
|
33 | 37 | # ============================================================================ |
|
61 | 65 |
|
62 | 66 | # Create entity |
63 | 67 | print("π Creating entity with Arkiv...") |
64 | | -tx_hash = client.arkiv.create_entity( |
65 | | - payload=b"Web3 integration example", expires_in=3600, content_type="text/plain" |
| 68 | +entity_key, receipt = client.arkiv.create_entity( |
| 69 | + payload=b"Web3 integration example", |
| 70 | + expires_in=3600, |
| 71 | + content_type="text/plain" |
66 | 72 | ) |
67 | | -print(f" Transaction Hash: {tx_hash.hex()}") |
68 | | - |
69 | | -# Wait and get receipt (standard Web3 call) |
70 | | -receipt = client.eth.wait_for_transaction_receipt(tx_hash) |
71 | | -print(f" Block Number: {receipt['blockNumber']}") |
72 | | -print(f" Gas Used: {receipt['gasUsed']}\n") |
| 73 | +print(f" Transaction Hash: {receipt.tx_hash}") |
| 74 | +print(f" Block Number: {receipt.block_number}\n") |
73 | 75 |
|
74 | | -# Extract entity ID from logs |
75 | | -entity_id = int(receipt["logs"][0]["topics"][1].hex(), 16) |
76 | | -print(f"β
Entity Created: ID {entity_id}\n") |
| 76 | +print(f"β
Entity Created: Key {entity_key}\n") |
77 | 77 |
|
78 | 78 | # ============================================================================ |
79 | 79 | # Part 3: Direct Contract Interaction (Advanced) |
|
85 | 85 | arkiv_contract = client.arkiv.contract |
86 | 86 | print(f"π Contract Address: {arkiv_contract.address}") |
87 | 87 |
|
88 | | -# Call contract methods directly |
89 | | -entity_count = arkiv_contract.functions.getEntityCount().call() |
90 | | -print(f"π Total Entity Count: {entity_count}") |
91 | | - |
92 | | -# Get entity using direct contract call |
93 | | -entity_data = arkiv_contract.functions.getEntity(entity_id).call() |
94 | | -print(f"\nπ Entity {entity_id} (via direct contract call):") |
95 | | -print(f" Owner: {entity_data[0]}") |
96 | | -print(f" Content Type: {entity_data[1]}") |
97 | | -print(f" Expires At: {entity_data[2]}") |
98 | | -print(f" Content Length: {len(entity_data[3])} bytes") |
99 | | -print(f" Content: {entity_data[3].decode('utf-8')}\n") |
| 88 | +# Get entity using Arkiv's high-level API |
| 89 | +entity = client.arkiv.get_entity(entity_key) |
| 90 | +print(f"\nπ Entity {entity_key} (via Arkiv SDK):") |
| 91 | +print(f" Owner: {entity.owner}") |
| 92 | +print(f" Content Type: {entity.content_type}") |
| 93 | +print(f" Expires At Block: {entity.expires_at_block}") |
| 94 | +if entity.payload: |
| 95 | + print(f" Content Length: {len(entity.payload)} bytes") |
| 96 | + print(f" Content: {entity.payload.decode('utf-8')}\n") |
| 97 | +else: |
| 98 | + print(f" No payload content\n") |
100 | 99 |
|
101 | 100 | # ============================================================================ |
102 | | -# Part 4: Transaction Signing (Manual) |
| 101 | +# Part 4: Updating and Deleting Entities |
103 | 102 | # ============================================================================ |
104 | | -print("βοΈ Part 4: Manual Transaction Signing") |
| 103 | +print("βοΈ Part 4: Updating and Deleting Entities") |
105 | 104 | print("=" * 60) |
106 | 105 |
|
107 | | -# Build transaction manually |
108 | | -print("π¨ Building transaction manually...") |
109 | | -nonce = client.eth.get_transaction_count(account.address) |
110 | | - |
111 | | -# Prepare update transaction |
112 | | -update_txn = arkiv_contract.functions.updateEntity( |
113 | | - entity_id, |
114 | | - b"Manually signed update", |
115 | | - int(client.eth.get_block("latest")["number"]) + 1800, # expires_at in blocks |
116 | | - "text/plain", |
117 | | -).build_transaction( |
118 | | - { |
119 | | - "from": account.address, |
120 | | - "nonce": nonce, |
121 | | - "gas": 200000, |
122 | | - "gasPrice": client.eth.gas_price, |
123 | | - } |
| 106 | +# Update entity |
| 107 | +print("π Updating entity...") |
| 108 | +update_receipt = client.arkiv.update_entity( |
| 109 | + entity_key, |
| 110 | + payload=b"Updated via Web3 example", |
| 111 | + expires_in=7200, |
| 112 | + content_type="text/plain" |
124 | 113 | ) |
125 | | - |
126 | | -# Sign transaction |
127 | | -print("βοΈ Signing transaction...") |
128 | | -signed_txn = client.eth.account.sign_transaction(update_txn, account.key) |
129 | | - |
130 | | -# Send signed transaction |
131 | | -print("π€ Sending signed transaction...") |
132 | | -tx_hash = client.eth.send_raw_transaction(signed_txn.raw_transaction) |
133 | | -print(f" Transaction Hash: {tx_hash.hex()}") |
134 | | - |
135 | | -# Wait for confirmation |
136 | | -receipt = client.eth.wait_for_transaction_receipt(tx_hash) |
137 | | -print(f"β
Transaction mined in block {receipt['blockNumber']}\n") |
| 114 | +print(f" Transaction Hash: {update_receipt.tx_hash}") |
| 115 | +print(f" Block Number: {update_receipt.block_number}\n") |
138 | 116 |
|
139 | 117 | # Verify update |
140 | | -updated_entity = client.arkiv.get_entity(entity_id) |
141 | | -print(f"π Updated content: {updated_entity.content.decode('utf-8')}") |
| 118 | +updated_entity = client.arkiv.get_entity(entity_key) |
| 119 | +if updated_entity.payload: |
| 120 | + print(f"π Updated content: {updated_entity.payload.decode('utf-8')}\n") |
| 121 | +else: |
| 122 | + print(f"π No payload content\n") |
| 123 | + |
| 124 | +# Delete entity |
| 125 | +print("ποΈ Deleting entity...") |
| 126 | +delete_receipt = client.arkiv.delete_entity(entity_key) |
| 127 | +print(f" Transaction Hash: {delete_receipt.tx_hash}") |
| 128 | +print(f" Block Number: {delete_receipt.block_number}\n") |
| 129 | + |
| 130 | +# Verify deletion (should return None or raise exception) |
| 131 | +try: |
| 132 | + deleted_entity = client.arkiv.get_entity(entity_key) |
| 133 | + if deleted_entity: |
| 134 | + print(f"β οΈ Entity still exists") |
| 135 | + else: |
| 136 | + print(f"β
Entity successfully deleted\n") |
| 137 | +except Exception as e: |
| 138 | + print(f"β
Entity successfully deleted (not found)\n") |
142 | 139 |
|
143 | 140 | # ============================================================================ |
144 | 141 | # Summary |
145 | 142 | # ============================================================================ |
146 | | -print("\n" + "=" * 60) |
| 143 | +print("=" * 60) |
147 | 144 | print("π Summary:") |
148 | 145 | print(" β
Standard Web3 operations work seamlessly") |
149 | 146 | print(" β
Arkiv adds convenient entity management methods") |
150 | | -print(" β
Direct contract access available when needed") |
151 | | -print(" β
Full control over transaction signing") |
| 147 | +print(" β
Full CRUD operations on blockchain entities") |
| 148 | +print(" β
Access to contract details and chain information") |
152 | 149 | print("=" * 60) |
153 | 150 |
|
154 | 151 | # Cleanup |
|
0 commit comments