oli-python 0.1.0__tar.gz
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.
- oli_python-0.1.0/PKG-INFO +117 -0
- oli_python-0.1.0/README.md +90 -0
- oli_python-0.1.0/oli/__init__.py +4 -0
- oli_python-0.1.0/oli/attestation/__init__.py +11 -0
- oli_python-0.1.0/oli/attestation/offchain.py +273 -0
- oli_python-0.1.0/oli/attestation/onchain.py +272 -0
- oli_python-0.1.0/oli/attestation/utils_other.py +111 -0
- oli_python-0.1.0/oli/attestation/utils_validator.py +200 -0
- oli_python-0.1.0/oli/core.py +128 -0
- oli_python-0.1.0/oli/data/__init__.py +4 -0
- oli_python-0.1.0/oli/data/fetcher.py +111 -0
- oli_python-0.1.0/oli/data/graphql.py +87 -0
- oli_python-0.1.0/oli_python.egg-info/PKG-INFO +117 -0
- oli_python-0.1.0/oli_python.egg-info/SOURCES.txt +17 -0
- oli_python-0.1.0/oli_python.egg-info/dependency_links.txt +1 -0
- oli_python-0.1.0/oli_python.egg-info/requires.txt +2 -0
- oli_python-0.1.0/oli_python.egg-info/top_level.txt +1 -0
- oli_python-0.1.0/setup.cfg +4 -0
- oli_python-0.1.0/setup.py +29 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: oli-python
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python SDK for interacting with the Open Labels Initiative; A framework for address labels in the blockchain space. Read & write labels into the OLI Label Pool, check your labels for OLI compliance.
|
|
5
|
+
Home-page: https://github.com/openlabelsinitiative/oli-python
|
|
6
|
+
Author: Lorenz Lehmann
|
|
7
|
+
Author-email: lorenz@growthepie.xyz
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
Requires-Dist: web3>=6.0.0
|
|
17
|
+
Requires-Dist: PyYAML>=6.0.0
|
|
18
|
+
Dynamic: author
|
|
19
|
+
Dynamic: author-email
|
|
20
|
+
Dynamic: classifier
|
|
21
|
+
Dynamic: description
|
|
22
|
+
Dynamic: description-content-type
|
|
23
|
+
Dynamic: home-page
|
|
24
|
+
Dynamic: requires-dist
|
|
25
|
+
Dynamic: requires-python
|
|
26
|
+
Dynamic: summary
|
|
27
|
+
|
|
28
|
+
# OLI Python Package
|
|
29
|
+
|
|
30
|
+
Python SDK for interacting with the Open Labels Initiative; A framework for address labels in the blockchain space. Read & write labels into the OLI Label Pool, check your labels for OLI compliance.
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install oli-python
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Basic Usage
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from oli import OLI
|
|
42
|
+
import os
|
|
43
|
+
|
|
44
|
+
# Initialize the client
|
|
45
|
+
# Make sure to pull in your private key from an .env file
|
|
46
|
+
oli = OLI(private_key=os.environ['private_key'], is_production=True)
|
|
47
|
+
|
|
48
|
+
# Create an offchain label
|
|
49
|
+
address = ""
|
|
50
|
+
chain_id = "eip155:1" # Ethereum
|
|
51
|
+
tags = {
|
|
52
|
+
"contract_name": "growthepie donation address",
|
|
53
|
+
"is_eoa": True,
|
|
54
|
+
"owner_project": "growthepie"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# Check if your label is OLI compliant
|
|
58
|
+
possible_to_attest = oli.check_label_correctness(address, chain_id, tags)
|
|
59
|
+
print(f"You can attest your label: {possible_to_attest}")
|
|
60
|
+
|
|
61
|
+
# Submit a label as an offchain attestation
|
|
62
|
+
response = oli.create_offchain_label(address, chain_id, tags)
|
|
63
|
+
print(f"Attestation created: {response.text}")
|
|
64
|
+
|
|
65
|
+
# Submit a label as an onchain attestation
|
|
66
|
+
tx_hash, uid = oli.create_onchain_label(address, chain_id, tags)
|
|
67
|
+
print(f"Transaction hash: {tx_hash}")
|
|
68
|
+
print(f"Attestation UID: {uid}")
|
|
69
|
+
|
|
70
|
+
# Batch submit multiple labels as one onchain attestation
|
|
71
|
+
labels = [
|
|
72
|
+
{'address': address, 'chain_id': chain_id, 'tags': tags},
|
|
73
|
+
{'address': address, 'chain_id': chain_id, 'tags': tags}
|
|
74
|
+
]
|
|
75
|
+
tx_hash, uids = oli.create_multi_onchain_labels(labels)
|
|
76
|
+
print(f"Batch transaction hash: {tx_hash}")
|
|
77
|
+
print(f"Attestation UIDs: {uids}")
|
|
78
|
+
|
|
79
|
+
# Revoke an attestation (revoking onchain attestations here)
|
|
80
|
+
trx_hash = oli.revoke_attestation(uid, onchain=True)
|
|
81
|
+
|
|
82
|
+
# Revoke multiple attestations (revoking onchain attestations here)
|
|
83
|
+
trx_hash, count = oli.multi_revoke_attestations(uids, onchain=True)
|
|
84
|
+
|
|
85
|
+
# Query attestations for a specific address
|
|
86
|
+
result = oli.graphql_query_attestations(address=address)
|
|
87
|
+
print(result)
|
|
88
|
+
|
|
89
|
+
# Download parquet export of raw attestations
|
|
90
|
+
oli.get_full_raw_export_parquet()
|
|
91
|
+
|
|
92
|
+
# Download parquet export of decoded attestations
|
|
93
|
+
oli.get_full_decoded_export_parquet()
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Wallet Requirements
|
|
98
|
+
|
|
99
|
+
Make sure your wallet contains ETH to pay for onchain attestations (including revocations). Offchain attestations are free.
|
|
100
|
+
|
|
101
|
+
The OLI Label Pool is deployed on **Base mainnet**. For testing purposes, you can use Base Sepolia Testnet (set `is_production=False`).
|
|
102
|
+
|
|
103
|
+
## Features
|
|
104
|
+
|
|
105
|
+
- Create onchain (single or batch) and offchain (single) OLI label attestations
|
|
106
|
+
- Revoke attestations (single or batch)
|
|
107
|
+
- Check your label if it is OLI compliant
|
|
108
|
+
- Query attestations using GraphQL
|
|
109
|
+
- Download full dataset exports in Parquet format
|
|
110
|
+
|
|
111
|
+
## Documentation
|
|
112
|
+
|
|
113
|
+
For more details, see the [OLI Documentation](https://github.com/openlabelsinitiative/OLI).
|
|
114
|
+
|
|
115
|
+
## License
|
|
116
|
+
|
|
117
|
+
MIT
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# OLI Python Package
|
|
2
|
+
|
|
3
|
+
Python SDK for interacting with the Open Labels Initiative; A framework for address labels in the blockchain space. Read & write labels into the OLI Label Pool, check your labels for OLI compliance.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install oli-python
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Basic Usage
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from oli import OLI
|
|
15
|
+
import os
|
|
16
|
+
|
|
17
|
+
# Initialize the client
|
|
18
|
+
# Make sure to pull in your private key from an .env file
|
|
19
|
+
oli = OLI(private_key=os.environ['private_key'], is_production=True)
|
|
20
|
+
|
|
21
|
+
# Create an offchain label
|
|
22
|
+
address = ""
|
|
23
|
+
chain_id = "eip155:1" # Ethereum
|
|
24
|
+
tags = {
|
|
25
|
+
"contract_name": "growthepie donation address",
|
|
26
|
+
"is_eoa": True,
|
|
27
|
+
"owner_project": "growthepie"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# Check if your label is OLI compliant
|
|
31
|
+
possible_to_attest = oli.check_label_correctness(address, chain_id, tags)
|
|
32
|
+
print(f"You can attest your label: {possible_to_attest}")
|
|
33
|
+
|
|
34
|
+
# Submit a label as an offchain attestation
|
|
35
|
+
response = oli.create_offchain_label(address, chain_id, tags)
|
|
36
|
+
print(f"Attestation created: {response.text}")
|
|
37
|
+
|
|
38
|
+
# Submit a label as an onchain attestation
|
|
39
|
+
tx_hash, uid = oli.create_onchain_label(address, chain_id, tags)
|
|
40
|
+
print(f"Transaction hash: {tx_hash}")
|
|
41
|
+
print(f"Attestation UID: {uid}")
|
|
42
|
+
|
|
43
|
+
# Batch submit multiple labels as one onchain attestation
|
|
44
|
+
labels = [
|
|
45
|
+
{'address': address, 'chain_id': chain_id, 'tags': tags},
|
|
46
|
+
{'address': address, 'chain_id': chain_id, 'tags': tags}
|
|
47
|
+
]
|
|
48
|
+
tx_hash, uids = oli.create_multi_onchain_labels(labels)
|
|
49
|
+
print(f"Batch transaction hash: {tx_hash}")
|
|
50
|
+
print(f"Attestation UIDs: {uids}")
|
|
51
|
+
|
|
52
|
+
# Revoke an attestation (revoking onchain attestations here)
|
|
53
|
+
trx_hash = oli.revoke_attestation(uid, onchain=True)
|
|
54
|
+
|
|
55
|
+
# Revoke multiple attestations (revoking onchain attestations here)
|
|
56
|
+
trx_hash, count = oli.multi_revoke_attestations(uids, onchain=True)
|
|
57
|
+
|
|
58
|
+
# Query attestations for a specific address
|
|
59
|
+
result = oli.graphql_query_attestations(address=address)
|
|
60
|
+
print(result)
|
|
61
|
+
|
|
62
|
+
# Download parquet export of raw attestations
|
|
63
|
+
oli.get_full_raw_export_parquet()
|
|
64
|
+
|
|
65
|
+
# Download parquet export of decoded attestations
|
|
66
|
+
oli.get_full_decoded_export_parquet()
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Wallet Requirements
|
|
71
|
+
|
|
72
|
+
Make sure your wallet contains ETH to pay for onchain attestations (including revocations). Offchain attestations are free.
|
|
73
|
+
|
|
74
|
+
The OLI Label Pool is deployed on **Base mainnet**. For testing purposes, you can use Base Sepolia Testnet (set `is_production=False`).
|
|
75
|
+
|
|
76
|
+
## Features
|
|
77
|
+
|
|
78
|
+
- Create onchain (single or batch) and offchain (single) OLI label attestations
|
|
79
|
+
- Revoke attestations (single or batch)
|
|
80
|
+
- Check your label if it is OLI compliant
|
|
81
|
+
- Query attestations using GraphQL
|
|
82
|
+
- Download full dataset exports in Parquet format
|
|
83
|
+
|
|
84
|
+
## Documentation
|
|
85
|
+
|
|
86
|
+
For more details, see the [OLI Documentation](https://github.com/openlabelsinitiative/OLI).
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
MIT
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from oli.attestation.onchain import OnchainAttestations
|
|
2
|
+
from oli.attestation.offchain import OffchainAttestations
|
|
3
|
+
from oli.attestation.utils_validator import UtilsValidator
|
|
4
|
+
from oli.attestation.utils_other import UtilsOther
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"OnchainAttestations",
|
|
8
|
+
"OffchainAttestations",
|
|
9
|
+
"UtilsValidator",
|
|
10
|
+
"UtilsOther"
|
|
11
|
+
]
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import requests
|
|
3
|
+
import secrets
|
|
4
|
+
import json
|
|
5
|
+
from requests import Response
|
|
6
|
+
|
|
7
|
+
class OffchainAttestations:
|
|
8
|
+
def __init__(self, oli_client):
|
|
9
|
+
"""
|
|
10
|
+
Initialize OffchainAttestations with an OLI client.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
oli_client: The OLI client instance
|
|
14
|
+
"""
|
|
15
|
+
self.oli = oli_client
|
|
16
|
+
|
|
17
|
+
def create_offchain_label(self, address: str, chain_id: str, tags: dict, ref_uid: str="0x0000000000000000000000000000000000000000000000000000000000000000", retry: int=4):
|
|
18
|
+
"""
|
|
19
|
+
Create an offchain OLI label attestation for a contract.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
address (str): The contract address to label
|
|
23
|
+
chain_id (str): Chain ID in CAIP-2 format where the address/contract resides
|
|
24
|
+
tags (dict): OLI compliant tags as a dict information (name, version, etc.)
|
|
25
|
+
ref_uid (str): Reference UID
|
|
26
|
+
retry (int): Number of retries for the API post request to EAS ipfs
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
dict: API request response
|
|
30
|
+
"""
|
|
31
|
+
# fix simple formatting errors in tags
|
|
32
|
+
tags = self.oli.validator.fix_simple_tags_formatting(tags)
|
|
33
|
+
|
|
34
|
+
# Check all necessary input parameters
|
|
35
|
+
self.oli.validator.check_label_correctness(address, chain_id, tags, ref_uid, auto_fix=False)
|
|
36
|
+
|
|
37
|
+
# Encode the label data
|
|
38
|
+
data = self.oli.utils_other.encode_label_data(chain_id, tags)
|
|
39
|
+
|
|
40
|
+
# Build the attestation
|
|
41
|
+
attestation = self.build_offchain_attestation(
|
|
42
|
+
recipient=address,
|
|
43
|
+
schema=self.oli.oli_label_pool_schema,
|
|
44
|
+
data=data,
|
|
45
|
+
ref_uid=ref_uid
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# Post to the API & retry if status code is not 200
|
|
49
|
+
response = self.post_offchain_attestation(attestation)
|
|
50
|
+
n0 = retry
|
|
51
|
+
while response.status_code != 200 and retry > 0:
|
|
52
|
+
retry -= 1
|
|
53
|
+
time.sleep(2 ** (n0 - retry)) # exponential backoff
|
|
54
|
+
response = self.post_offchain_attestation(attestation)
|
|
55
|
+
|
|
56
|
+
# if it fails after all retries, raise an error
|
|
57
|
+
if response.status_code != 200:
|
|
58
|
+
raise Exception(f"Failed to submit offchain attestation to EAS API ipfs post endpoint after {n0} retries: {response.status_code} - {response.text}")
|
|
59
|
+
|
|
60
|
+
return response
|
|
61
|
+
|
|
62
|
+
def post_offchain_attestation(self, attestation: dict, filename: str="OLI.txt") -> Response:
|
|
63
|
+
"""
|
|
64
|
+
Post API an attestation to the EAS API.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
attestation (dict): The attestation package
|
|
68
|
+
filename (str): Custom filename
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
dict: API response
|
|
72
|
+
"""
|
|
73
|
+
# Convert numerical values to strings for JSON serialization
|
|
74
|
+
attestation["sig"]["message"]["time"] = str(attestation["sig"]["message"]["time"])
|
|
75
|
+
attestation["sig"]["message"]["expirationTime"] = str(attestation["sig"]["message"]["expirationTime"])
|
|
76
|
+
attestation["sig"]["domain"]["chainId"] = str(attestation["sig"]["domain"]["chainId"])
|
|
77
|
+
|
|
78
|
+
# Prepare payload for the API endpoint
|
|
79
|
+
payload = {
|
|
80
|
+
"filename": filename,
|
|
81
|
+
"textJson": json.dumps(attestation, separators=(',', ':'))
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
headers = {
|
|
85
|
+
"Content-Type": "application/json"
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# Post the data to the API
|
|
89
|
+
response = requests.post(self.oli.eas_api_url, json=payload, headers=headers)
|
|
90
|
+
return response
|
|
91
|
+
|
|
92
|
+
def build_offchain_attestation(self, recipient: str, schema: str, data: str, ref_uid: str, revocable: bool=True, expiration_time: int=0) -> dict:
|
|
93
|
+
"""
|
|
94
|
+
Build an offchain attestation with the given parameters.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
recipient (str): Ethereum address of the contract to be labeled
|
|
98
|
+
schema (str): Schema hash
|
|
99
|
+
data (str): Hex-encoded data
|
|
100
|
+
ref_uid (str): Reference UID
|
|
101
|
+
revocable (bool): Whether the attestation is revocable
|
|
102
|
+
expiration_time (int): Expiration time in seconds since epoch
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
dict: The signed attestation and UID
|
|
106
|
+
"""
|
|
107
|
+
# Create a random salt
|
|
108
|
+
salt = f"0x{secrets.token_hex(32)}"
|
|
109
|
+
|
|
110
|
+
# Current time in seconds
|
|
111
|
+
current_time = int(time.time())
|
|
112
|
+
|
|
113
|
+
# Typed data for the attestation
|
|
114
|
+
typed_data = {
|
|
115
|
+
"version": 2,
|
|
116
|
+
"recipient": recipient,
|
|
117
|
+
"time": current_time,
|
|
118
|
+
"revocable": revocable,
|
|
119
|
+
"schema": schema,
|
|
120
|
+
"refUID": ref_uid,
|
|
121
|
+
"data": data,
|
|
122
|
+
"expirationTime": expiration_time,
|
|
123
|
+
"salt": salt,
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
# EIP-712 typed data format
|
|
127
|
+
types = {
|
|
128
|
+
"domain": {
|
|
129
|
+
"name": "EAS Attestation",
|
|
130
|
+
"version": "1.2.0",
|
|
131
|
+
"chainId": self.oli.rpc_chain_number,
|
|
132
|
+
"verifyingContract": self.oli.eas_address
|
|
133
|
+
},
|
|
134
|
+
"primaryType": "Attest",
|
|
135
|
+
"message": typed_data,
|
|
136
|
+
"types": {
|
|
137
|
+
"Attest": [
|
|
138
|
+
{"name": "version", "type": "uint16"},
|
|
139
|
+
{"name": "schema", "type": "bytes32"},
|
|
140
|
+
{"name": "recipient", "type": "address"},
|
|
141
|
+
{"name": "time", "type": "uint64"},
|
|
142
|
+
{"name": "expirationTime", "type": "uint64"},
|
|
143
|
+
{"name": "revocable", "type": "bool"},
|
|
144
|
+
{"name": "refUID", "type": "bytes32"},
|
|
145
|
+
{"name": "data", "type": "bytes"},
|
|
146
|
+
{"name": "salt", "type": "bytes32"}
|
|
147
|
+
]
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
# Sign the message using the account
|
|
152
|
+
signed_message = self.oli.account.sign_typed_data(
|
|
153
|
+
domain_data=types["domain"],
|
|
154
|
+
message_types=types["types"],
|
|
155
|
+
message_data=typed_data
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
# Calculate the UID
|
|
159
|
+
attester = '0x0000000000000000000000000000000000000000' # for offchain UID calculation
|
|
160
|
+
uid = self.oli.utils_other.calculate_attestation_uid_v2(
|
|
161
|
+
schema, recipient, attester, current_time, data,
|
|
162
|
+
expiration_time, revocable, ref_uid, salt=salt
|
|
163
|
+
)
|
|
164
|
+
uid_hex = '0x' + uid.hex()
|
|
165
|
+
|
|
166
|
+
# Package the result
|
|
167
|
+
result = {
|
|
168
|
+
"sig": {
|
|
169
|
+
"domain": types["domain"],
|
|
170
|
+
"primaryType": types["primaryType"],
|
|
171
|
+
"types": types["types"],
|
|
172
|
+
"message": typed_data,
|
|
173
|
+
"uid": uid_hex,
|
|
174
|
+
"version": 2,
|
|
175
|
+
"signature": {
|
|
176
|
+
"r": hex(signed_message.r),
|
|
177
|
+
"s": hex(signed_message.s),
|
|
178
|
+
"v": signed_message.v
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
"signer": self.oli.address
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return result
|
|
185
|
+
|
|
186
|
+
def revoke_attestation(self, uid_hex: str, gas_limit: int=200000):
|
|
187
|
+
"""
|
|
188
|
+
Revoke an offchain attestation using its UID.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
uid_hex (str): UID of the attestation to revoke (in hex format)
|
|
192
|
+
gas_limit (int): Gas limit for the transaction. If not set, defaults to 200000. Gas estimation is not possible for revoke transactions.
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
str: Transaction hash
|
|
196
|
+
"""
|
|
197
|
+
function = self.oli.eas.functions.revokeOffchain(self.oli.w3.to_bytes(hexstr=uid_hex))
|
|
198
|
+
|
|
199
|
+
# Define the transaction parameters
|
|
200
|
+
tx_params = {
|
|
201
|
+
'chainId': self.oli.rpc_chain_number,
|
|
202
|
+
'gasPrice': self.oli.w3.eth.gas_price,
|
|
203
|
+
'nonce': self.oli.w3.eth.get_transaction_count(self.oli.address),
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
# Estimate gas if no limit provided
|
|
207
|
+
tx_params = self.oli.utils_other.estimate_gas_limit(function, tx_params, gas_limit)
|
|
208
|
+
|
|
209
|
+
# Build the transaction to revoke an attestation
|
|
210
|
+
transaction = function.build_transaction(tx_params)
|
|
211
|
+
|
|
212
|
+
# Sign the transaction
|
|
213
|
+
signed_txn = self.oli.w3.eth.account.sign_transaction(transaction, private_key=self.oli.private_key)
|
|
214
|
+
|
|
215
|
+
# Send the transaction
|
|
216
|
+
try:
|
|
217
|
+
txn_hash = self.oli.w3.eth.send_raw_transaction(signed_txn.raw_transaction)
|
|
218
|
+
except Exception as e:
|
|
219
|
+
raise Exception(f"Failed to send revoke transaction to mempool: {e}")
|
|
220
|
+
|
|
221
|
+
# Get the transaction receipt
|
|
222
|
+
txn_receipt = self.oli.w3.eth.wait_for_transaction_receipt(txn_hash)
|
|
223
|
+
|
|
224
|
+
# Check if the transaction was successful
|
|
225
|
+
if txn_receipt.status == 1:
|
|
226
|
+
return f"0x{txn_hash.hex()}"
|
|
227
|
+
else:
|
|
228
|
+
raise Exception(f"Transaction failed: {txn_receipt}")
|
|
229
|
+
|
|
230
|
+
def multi_revoke_attestations(self, uids: str, gas_limit: int=10000000):
|
|
231
|
+
"""
|
|
232
|
+
Revoke multiple offchain attestations in a single transaction.
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
uids (list): List of UIDs to revoke (in hex format)
|
|
236
|
+
gas_limit (int): Gas limit for the transaction. If not set, defaults to 10000000. Gas estimation is not possible for revoke transactions.
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
str: Transaction hash
|
|
240
|
+
int: Number of attestations revoked
|
|
241
|
+
"""
|
|
242
|
+
revocation_data = []
|
|
243
|
+
for uid in uids:
|
|
244
|
+
revocation_data.append(self.oli.w3.to_bytes(hexstr=uid))
|
|
245
|
+
function = self.oli.eas.functions.multiRevokeOffchain(revocation_data)
|
|
246
|
+
|
|
247
|
+
# Define the transaction parameters
|
|
248
|
+
tx_params = {
|
|
249
|
+
'chainId': self.oli.rpc_chain_number,
|
|
250
|
+
'gasPrice': self.oli.w3.eth.gas_price,
|
|
251
|
+
'nonce': self.oli.w3.eth.get_transaction_count(self.oli.address),
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
# Estimate gas if no limit provided
|
|
255
|
+
tx_params = self.oli.utils_other.estimate_gas_limit(function, tx_params, gas_limit)
|
|
256
|
+
|
|
257
|
+
# Build the transaction
|
|
258
|
+
transaction = function.build_transaction(tx_params)
|
|
259
|
+
|
|
260
|
+
# Sign the transaction
|
|
261
|
+
signed_txn = self.oli.w3.eth.account.sign_transaction(transaction, private_key=self.oli.private_key)
|
|
262
|
+
|
|
263
|
+
# Send the transaction
|
|
264
|
+
txn_hash = self.oli.w3.eth.send_raw_transaction(signed_txn.raw_transaction)
|
|
265
|
+
|
|
266
|
+
# Get the transaction receipt
|
|
267
|
+
txn_receipt = self.oli.w3.eth.wait_for_transaction_receipt(txn_hash)
|
|
268
|
+
|
|
269
|
+
# Check if the transaction was successful
|
|
270
|
+
if txn_receipt.status == 1:
|
|
271
|
+
return f"0x{txn_hash.hex()}", len(uids)
|
|
272
|
+
else:
|
|
273
|
+
raise Exception(f"Transaction failed: {txn_receipt}")
|