datadid-sdk-python 1.0.0__tar.gz → 1.0.5__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.
- {datadid_sdk_python-1.0.0 → datadid_sdk_python-1.0.5}/PKG-INFO +20 -17
- {datadid_sdk_python-1.0.0 → datadid_sdk_python-1.0.5}/README.md +19 -16
- {datadid_sdk_python-1.0.0/src → datadid_sdk_python-1.0.5/datadid}/__init__.py +0 -2
- {datadid_sdk_python-1.0.0/src → datadid_sdk_python-1.0.5/datadid}/data/client.py +8 -2
- {datadid_sdk_python-1.0.0/src → datadid_sdk_python-1.0.5/datadid}/did/client.py +41 -16
- {datadid_sdk_python-1.0.0/src → datadid_sdk_python-1.0.5/datadid}/did/types.py +2 -12
- {datadid_sdk_python-1.0.0 → datadid_sdk_python-1.0.5}/datadid_sdk_python.egg-info/PKG-INFO +20 -17
- datadid_sdk_python-1.0.5/datadid_sdk_python.egg-info/SOURCES.txt +23 -0
- datadid_sdk_python-1.0.5/datadid_sdk_python.egg-info/top_level.txt +1 -0
- {datadid_sdk_python-1.0.0 → datadid_sdk_python-1.0.5}/pyproject.toml +2 -2
- datadid_sdk_python-1.0.0/datadid_sdk_python.egg-info/SOURCES.txt +0 -23
- datadid_sdk_python-1.0.0/datadid_sdk_python.egg-info/top_level.txt +0 -1
- {datadid_sdk_python-1.0.0/src → datadid_sdk_python-1.0.5/datadid}/data/__init__.py +0 -0
- {datadid_sdk_python-1.0.0/src → datadid_sdk_python-1.0.5/datadid}/data/types.py +0 -0
- {datadid_sdk_python-1.0.0/src → datadid_sdk_python-1.0.5/datadid}/did/__init__.py +0 -0
- {datadid_sdk_python-1.0.0/src → datadid_sdk_python-1.0.5/datadid}/errors.py +0 -0
- {datadid_sdk_python-1.0.0 → datadid_sdk_python-1.0.5}/datadid_sdk_python.egg-info/dependency_links.txt +0 -0
- {datadid_sdk_python-1.0.0 → datadid_sdk_python-1.0.5}/datadid_sdk_python.egg-info/requires.txt +0 -0
- {datadid_sdk_python-1.0.0 → datadid_sdk_python-1.0.5}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datadid-sdk-python
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.5
|
|
4
4
|
Summary: Python SDK for the DataDID developer platform — Data API and DID API clients
|
|
5
5
|
License-Expression: ISC
|
|
6
6
|
Keywords: datadid,did,memo
|
|
@@ -31,7 +31,7 @@ pip install datadid-sdk-python
|
|
|
31
31
|
|
|
32
32
|
```python
|
|
33
33
|
import asyncio
|
|
34
|
-
from
|
|
34
|
+
from datadid import DataClient
|
|
35
35
|
|
|
36
36
|
async def main():
|
|
37
37
|
client = DataClient.production()
|
|
@@ -62,8 +62,8 @@ asyncio.run(main())
|
|
|
62
62
|
### Create a client
|
|
63
63
|
|
|
64
64
|
```python
|
|
65
|
-
from
|
|
66
|
-
from
|
|
65
|
+
from datadid import DataClient
|
|
66
|
+
from datadid.data.types import DataClientOptions
|
|
67
67
|
|
|
68
68
|
client = DataClient.production()
|
|
69
69
|
# or: client = DataClient.testnet()
|
|
@@ -159,9 +159,11 @@ tokens = await client.login_with_pi(
|
|
|
159
159
|
|
|
160
160
|
```python
|
|
161
161
|
# Step 1: request a challenge message from the server
|
|
162
|
+
# origin is required — use your app's own domain
|
|
162
163
|
message = await client.get_evm_challenge(
|
|
163
164
|
"0xYourWalletAddress",
|
|
164
|
-
chain_id=985,
|
|
165
|
+
chain_id=985, # optional, defaults to 985
|
|
166
|
+
origin="https://myapp.com", # required for login_with_evm to succeed
|
|
165
167
|
)
|
|
166
168
|
|
|
167
169
|
# Step 2: sign the message with the user's wallet
|
|
@@ -238,7 +240,7 @@ await client.add_action_record(61, {"some_option": "value"})
|
|
|
238
240
|
### Error handling
|
|
239
241
|
|
|
240
242
|
```python
|
|
241
|
-
from
|
|
243
|
+
from datadid import DataDIDApiError
|
|
242
244
|
|
|
243
245
|
try:
|
|
244
246
|
await client.login_with_email_password("alice@example.com", "wrongpassword")
|
|
@@ -255,8 +257,8 @@ except DataDIDApiError as err:
|
|
|
255
257
|
By default, login methods store the access token on the client automatically. You can disable this:
|
|
256
258
|
|
|
257
259
|
```python
|
|
258
|
-
from
|
|
259
|
-
from
|
|
260
|
+
from datadid import DataClient
|
|
261
|
+
from datadid.data.types import DataClientOptions
|
|
260
262
|
|
|
261
263
|
client = DataClient(DataClientOptions(
|
|
262
264
|
base_url="https://data-be.metamemo.one",
|
|
@@ -286,7 +288,7 @@ DID operations use a **sign-then-submit** pattern. You never send your private k
|
|
|
286
288
|
### Create a client
|
|
287
289
|
|
|
288
290
|
```python
|
|
289
|
-
from
|
|
291
|
+
from datadid import DIDClient
|
|
290
292
|
|
|
291
293
|
did_client = DIDClient.production()
|
|
292
294
|
# or: did_client = DIDClient.testnet()
|
|
@@ -302,10 +304,10 @@ address = "0xYourWalletAddress"
|
|
|
302
304
|
# Step 1: get the message to sign
|
|
303
305
|
message = await did_client.get_create_message(address)
|
|
304
306
|
|
|
305
|
-
# Step 2: sign it
|
|
307
|
+
# Step 2: sign it — the message is a hex-encoded byte string, sign the bytes
|
|
306
308
|
from eth_account.messages import encode_defunct
|
|
307
309
|
from eth_account import Account
|
|
308
|
-
signed = Account.sign_message(encode_defunct(
|
|
310
|
+
signed = Account.sign_message(encode_defunct(primitive=bytes.fromhex(message[2:])), private_key=private_key)
|
|
309
311
|
signature = signed.signature.hex()
|
|
310
312
|
|
|
311
313
|
# Step 3: submit — server creates the DID on-chain
|
|
@@ -329,8 +331,8 @@ print(result)
|
|
|
329
331
|
|
|
330
332
|
```python
|
|
331
333
|
info = await did_client.get_did_info("0xYourWalletAddress")
|
|
332
|
-
print(info.did)
|
|
333
|
-
print(info.
|
|
334
|
+
print(info.did) # the DID string (e.g. "did:memo:...")
|
|
335
|
+
print(info.number) # the numeric platform ID
|
|
334
336
|
```
|
|
335
337
|
|
|
336
338
|
---
|
|
@@ -343,8 +345,9 @@ my_did = "did:memo:abc123..."
|
|
|
343
345
|
# Step 1: get the message to sign
|
|
344
346
|
message = await did_client.get_delete_message(my_did)
|
|
345
347
|
|
|
346
|
-
# Step 2: sign it
|
|
347
|
-
|
|
348
|
+
# Step 2: sign it — the message is a hex-encoded byte string, sign the bytes
|
|
349
|
+
signed = Account.sign_message(encode_defunct(primitive=bytes.fromhex(message[2:])), private_key=private_key)
|
|
350
|
+
signature = signed.signature.hex()
|
|
348
351
|
|
|
349
352
|
# Step 3: submit
|
|
350
353
|
result = await did_client.delete_did(signature, my_did)
|
|
@@ -388,7 +391,7 @@ An mfile is a file that gets its own DID minted on-chain, making it permanently
|
|
|
388
391
|
message = await did_client.create_mfile_upload(file_data, "0xYourWalletAddress")
|
|
389
392
|
|
|
390
393
|
# Step 2: sign it
|
|
391
|
-
signature = ...
|
|
394
|
+
signature = ... # sign message with your wallet
|
|
392
395
|
|
|
393
396
|
# Step 3: confirm the upload
|
|
394
397
|
result = await did_client.confirm_mfile_upload(signature, "0xYourWalletAddress")
|
|
@@ -475,5 +478,5 @@ Tests hit the real production and testnet servers. The `ACCESS_TOKEN` constant i
|
|
|
475
478
|
|
|
476
479
|
## Links
|
|
477
480
|
|
|
478
|
-
- [Data API reference](https://
|
|
481
|
+
- [Data API reference](https://memolabs.gitbook.io/datadid-developer-platform-v2/en/api)
|
|
479
482
|
- [DID API reference (Swagger)](https://prodidapi.memolabs.org/swagger/index.html)
|
|
@@ -21,7 +21,7 @@ pip install datadid-sdk-python
|
|
|
21
21
|
|
|
22
22
|
```python
|
|
23
23
|
import asyncio
|
|
24
|
-
from
|
|
24
|
+
from datadid import DataClient
|
|
25
25
|
|
|
26
26
|
async def main():
|
|
27
27
|
client = DataClient.production()
|
|
@@ -52,8 +52,8 @@ asyncio.run(main())
|
|
|
52
52
|
### Create a client
|
|
53
53
|
|
|
54
54
|
```python
|
|
55
|
-
from
|
|
56
|
-
from
|
|
55
|
+
from datadid import DataClient
|
|
56
|
+
from datadid.data.types import DataClientOptions
|
|
57
57
|
|
|
58
58
|
client = DataClient.production()
|
|
59
59
|
# or: client = DataClient.testnet()
|
|
@@ -149,9 +149,11 @@ tokens = await client.login_with_pi(
|
|
|
149
149
|
|
|
150
150
|
```python
|
|
151
151
|
# Step 1: request a challenge message from the server
|
|
152
|
+
# origin is required — use your app's own domain
|
|
152
153
|
message = await client.get_evm_challenge(
|
|
153
154
|
"0xYourWalletAddress",
|
|
154
|
-
chain_id=985,
|
|
155
|
+
chain_id=985, # optional, defaults to 985
|
|
156
|
+
origin="https://myapp.com", # required for login_with_evm to succeed
|
|
155
157
|
)
|
|
156
158
|
|
|
157
159
|
# Step 2: sign the message with the user's wallet
|
|
@@ -228,7 +230,7 @@ await client.add_action_record(61, {"some_option": "value"})
|
|
|
228
230
|
### Error handling
|
|
229
231
|
|
|
230
232
|
```python
|
|
231
|
-
from
|
|
233
|
+
from datadid import DataDIDApiError
|
|
232
234
|
|
|
233
235
|
try:
|
|
234
236
|
await client.login_with_email_password("alice@example.com", "wrongpassword")
|
|
@@ -245,8 +247,8 @@ except DataDIDApiError as err:
|
|
|
245
247
|
By default, login methods store the access token on the client automatically. You can disable this:
|
|
246
248
|
|
|
247
249
|
```python
|
|
248
|
-
from
|
|
249
|
-
from
|
|
250
|
+
from datadid import DataClient
|
|
251
|
+
from datadid.data.types import DataClientOptions
|
|
250
252
|
|
|
251
253
|
client = DataClient(DataClientOptions(
|
|
252
254
|
base_url="https://data-be.metamemo.one",
|
|
@@ -276,7 +278,7 @@ DID operations use a **sign-then-submit** pattern. You never send your private k
|
|
|
276
278
|
### Create a client
|
|
277
279
|
|
|
278
280
|
```python
|
|
279
|
-
from
|
|
281
|
+
from datadid import DIDClient
|
|
280
282
|
|
|
281
283
|
did_client = DIDClient.production()
|
|
282
284
|
# or: did_client = DIDClient.testnet()
|
|
@@ -292,10 +294,10 @@ address = "0xYourWalletAddress"
|
|
|
292
294
|
# Step 1: get the message to sign
|
|
293
295
|
message = await did_client.get_create_message(address)
|
|
294
296
|
|
|
295
|
-
# Step 2: sign it
|
|
297
|
+
# Step 2: sign it — the message is a hex-encoded byte string, sign the bytes
|
|
296
298
|
from eth_account.messages import encode_defunct
|
|
297
299
|
from eth_account import Account
|
|
298
|
-
signed = Account.sign_message(encode_defunct(
|
|
300
|
+
signed = Account.sign_message(encode_defunct(primitive=bytes.fromhex(message[2:])), private_key=private_key)
|
|
299
301
|
signature = signed.signature.hex()
|
|
300
302
|
|
|
301
303
|
# Step 3: submit — server creates the DID on-chain
|
|
@@ -319,8 +321,8 @@ print(result)
|
|
|
319
321
|
|
|
320
322
|
```python
|
|
321
323
|
info = await did_client.get_did_info("0xYourWalletAddress")
|
|
322
|
-
print(info.did)
|
|
323
|
-
print(info.
|
|
324
|
+
print(info.did) # the DID string (e.g. "did:memo:...")
|
|
325
|
+
print(info.number) # the numeric platform ID
|
|
324
326
|
```
|
|
325
327
|
|
|
326
328
|
---
|
|
@@ -333,8 +335,9 @@ my_did = "did:memo:abc123..."
|
|
|
333
335
|
# Step 1: get the message to sign
|
|
334
336
|
message = await did_client.get_delete_message(my_did)
|
|
335
337
|
|
|
336
|
-
# Step 2: sign it
|
|
337
|
-
|
|
338
|
+
# Step 2: sign it — the message is a hex-encoded byte string, sign the bytes
|
|
339
|
+
signed = Account.sign_message(encode_defunct(primitive=bytes.fromhex(message[2:])), private_key=private_key)
|
|
340
|
+
signature = signed.signature.hex()
|
|
338
341
|
|
|
339
342
|
# Step 3: submit
|
|
340
343
|
result = await did_client.delete_did(signature, my_did)
|
|
@@ -378,7 +381,7 @@ An mfile is a file that gets its own DID minted on-chain, making it permanently
|
|
|
378
381
|
message = await did_client.create_mfile_upload(file_data, "0xYourWalletAddress")
|
|
379
382
|
|
|
380
383
|
# Step 2: sign it
|
|
381
|
-
signature = ...
|
|
384
|
+
signature = ... # sign message with your wallet
|
|
382
385
|
|
|
383
386
|
# Step 3: confirm the upload
|
|
384
387
|
result = await did_client.confirm_mfile_upload(signature, "0xYourWalletAddress")
|
|
@@ -465,5 +468,5 @@ Tests hit the real production and testnet servers. The `ACCESS_TOKEN` constant i
|
|
|
465
468
|
|
|
466
469
|
## Links
|
|
467
470
|
|
|
468
|
-
- [Data API reference](https://
|
|
471
|
+
- [Data API reference](https://memolabs.gitbook.io/datadid-developer-platform-v2/en/api)
|
|
469
472
|
- [DID API reference (Swagger)](https://prodidapi.memolabs.org/swagger/index.html)
|
|
@@ -24,7 +24,6 @@ from .did.types import (
|
|
|
24
24
|
CreateDIDResponse,
|
|
25
25
|
DeleteDIDResponse,
|
|
26
26
|
DIDInfoResponse,
|
|
27
|
-
DIDChainInfo,
|
|
28
27
|
)
|
|
29
28
|
|
|
30
29
|
__all__ = [
|
|
@@ -46,5 +45,4 @@ __all__ = [
|
|
|
46
45
|
"CreateDIDResponse",
|
|
47
46
|
"DeleteDIDResponse",
|
|
48
47
|
"DIDInfoResponse",
|
|
49
|
-
"DIDChainInfo",
|
|
50
48
|
]
|
|
@@ -188,6 +188,12 @@ class DataClient:
|
|
|
188
188
|
Get the sign-in challenge message for EVM wallet login.
|
|
189
189
|
|
|
190
190
|
GET /v2/login/evm/challenge
|
|
191
|
+
|
|
192
|
+
The `origin` parameter is required for login_with_evm() to succeed.
|
|
193
|
+
It must be a URL string identifying your app (e.g. "https://myapp.com").
|
|
194
|
+
The server embeds it in the SIWE challenge message, and verifies it
|
|
195
|
+
when the signature is submitted. Omitting it produces a malformed
|
|
196
|
+
challenge that login_with_evm() will reject.
|
|
191
197
|
"""
|
|
192
198
|
params: dict[str, str] = {"address": address}
|
|
193
199
|
if chain_id is not None:
|
|
@@ -251,7 +257,7 @@ class DataClient:
|
|
|
251
257
|
data = await self._request(
|
|
252
258
|
"POST",
|
|
253
259
|
"/v2/login/refresh",
|
|
254
|
-
extra_headers={"Authorization": refresh_token},
|
|
260
|
+
extra_headers={"Authorization": f"Bearer {refresh_token}"},
|
|
255
261
|
)
|
|
256
262
|
new_token = (
|
|
257
263
|
data.get("access_token")
|
|
@@ -453,7 +459,7 @@ class DataClient:
|
|
|
453
459
|
result_val = json_body.get("result")
|
|
454
460
|
if result_val is not None and result_val != 1:
|
|
455
461
|
raise DataDIDApiError(
|
|
456
|
-
json_body.get("message") or f"API returned result={result_val}",
|
|
462
|
+
json_body.get("message") or json_body.get("message_en") or f"API returned result={result_val}",
|
|
457
463
|
response.status_code,
|
|
458
464
|
json_body,
|
|
459
465
|
)
|
|
@@ -6,12 +6,9 @@ import httpx
|
|
|
6
6
|
|
|
7
7
|
from ..errors import DataDIDApiError
|
|
8
8
|
from .types import (
|
|
9
|
-
CreateDIDResponse,
|
|
10
9
|
DeleteDIDResponse,
|
|
11
|
-
DIDChainInfo,
|
|
12
10
|
DIDClientOptions,
|
|
13
11
|
DIDInfoResponse,
|
|
14
|
-
SigMsgResponse,
|
|
15
12
|
)
|
|
16
13
|
|
|
17
14
|
_PRODUCTION_URL = "https://prodidapi.memolabs.org"
|
|
@@ -49,6 +46,12 @@ class DIDClient:
|
|
|
49
46
|
Get the message you need to sign before creating a DID.
|
|
50
47
|
Sign the returned msg with your wallet, then pass the signature to create_did().
|
|
51
48
|
|
|
49
|
+
IMPORTANT: the returned message is a hex-encoded byte string. Sign the decoded
|
|
50
|
+
bytes, not the hex string itself:
|
|
51
|
+
eth_account: Account.sign_message(encode_defunct(primitive=bytes.fromhex(message[2:])), key)
|
|
52
|
+
web3.py: w3.eth.account.sign_message(encode_defunct(primitive=bytes.fromhex(message[2:])), key)
|
|
53
|
+
Signing the raw hex string will produce an invalid signature.
|
|
54
|
+
|
|
52
55
|
GET /did/createsigmsg
|
|
53
56
|
"""
|
|
54
57
|
data = await self._request("GET", f"/did/createsigmsg?address={address}")
|
|
@@ -81,36 +84,50 @@ class DIDClient:
|
|
|
81
84
|
data = await self._request("POST", "/did/createton", {"address": address})
|
|
82
85
|
return data.get("did", "") if isinstance(data, dict) else str(data)
|
|
83
86
|
|
|
84
|
-
async def get_did_exists(self, address: str) ->
|
|
87
|
+
async def get_did_exists(self, address: str) -> bool:
|
|
85
88
|
"""
|
|
86
89
|
Check whether a DID exists for the given address.
|
|
87
90
|
|
|
88
91
|
GET /did/exist
|
|
92
|
+
|
|
93
|
+
NOTE: There is a short propagation delay before a newly
|
|
94
|
+
created or deleted DID is reflected here.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
address: EVM wallet address (0x...)
|
|
89
98
|
"""
|
|
90
|
-
|
|
99
|
+
data = await self._request("GET", f"/did/exist?address={address}")
|
|
100
|
+
return data.get("exist") == 1
|
|
91
101
|
|
|
92
102
|
async def get_did_info(self, address: str) -> DIDInfoResponse:
|
|
93
103
|
"""
|
|
94
|
-
Get DID info
|
|
104
|
+
Get DID info for an EVM wallet address.
|
|
95
105
|
|
|
96
106
|
GET /did/info
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
address: EVM wallet address (0x...)
|
|
110
|
+
Returns:
|
|
111
|
+
DIDInfoResponse with did (string) and number (string).
|
|
97
112
|
"""
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
)
|
|
105
|
-
for item in (data.get("info") or [])
|
|
106
|
-
]
|
|
107
|
-
return DIDInfoResponse(did=data.get("did", ""), info=chain_list)
|
|
113
|
+
json_data = await self._request("GET", f"/did/info?address={address}")
|
|
114
|
+
inner = json_data.get("data") or json_data
|
|
115
|
+
return DIDInfoResponse(
|
|
116
|
+
did=inner.get("did", ""),
|
|
117
|
+
number=inner.get("number", ""),
|
|
118
|
+
)
|
|
108
119
|
|
|
109
120
|
async def get_delete_message(self, did: str) -> str:
|
|
110
121
|
"""
|
|
111
122
|
Get the message you need to sign before deleting a DID.
|
|
112
123
|
Sign the returned msg with your wallet, then pass the signature to delete_did().
|
|
113
124
|
|
|
125
|
+
IMPORTANT: the returned message is a hex-encoded byte string. Sign the decoded
|
|
126
|
+
bytes, not the hex string itself:
|
|
127
|
+
eth_account: Account.sign_message(encode_defunct(primitive=bytes.fromhex(message[2:])), key)
|
|
128
|
+
web3.py: w3.eth.account.sign_message(encode_defunct(primitive=bytes.fromhex(message[2:])), key)
|
|
129
|
+
Signing the raw hex string will produce an invalid signature.
|
|
130
|
+
|
|
114
131
|
GET /did/deletesigmsg
|
|
115
132
|
"""
|
|
116
133
|
data = await self._request("GET", f"/did/deletesigmsg?did={did}")
|
|
@@ -222,4 +239,12 @@ class DIDClient:
|
|
|
222
239
|
json_body,
|
|
223
240
|
)
|
|
224
241
|
|
|
242
|
+
result_val = json_body.get("result")
|
|
243
|
+
if result_val is not None and result_val != 1:
|
|
244
|
+
raise DataDIDApiError(
|
|
245
|
+
json_body.get("error") or json_body.get("message") or f"API returned result={result_val}",
|
|
246
|
+
response.status_code,
|
|
247
|
+
json_body,
|
|
248
|
+
)
|
|
249
|
+
|
|
225
250
|
return json_body
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
2
|
-
from typing import List
|
|
1
|
+
from dataclasses import dataclass
|
|
3
2
|
|
|
4
3
|
|
|
5
4
|
@dataclass
|
|
@@ -32,18 +31,9 @@ class DeleteDIDResponse:
|
|
|
32
31
|
status: str
|
|
33
32
|
|
|
34
33
|
|
|
35
|
-
@dataclass
|
|
36
|
-
class DIDChainInfo:
|
|
37
|
-
"""Chain-specific info within a DID info response."""
|
|
38
|
-
|
|
39
|
-
address: str
|
|
40
|
-
balance: str
|
|
41
|
-
chain: str
|
|
42
|
-
|
|
43
|
-
|
|
44
34
|
@dataclass
|
|
45
35
|
class DIDInfoResponse:
|
|
46
36
|
"""Response from GET /did/info."""
|
|
47
37
|
|
|
48
38
|
did: str
|
|
49
|
-
|
|
39
|
+
number: str
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datadid-sdk-python
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.5
|
|
4
4
|
Summary: Python SDK for the DataDID developer platform — Data API and DID API clients
|
|
5
5
|
License-Expression: ISC
|
|
6
6
|
Keywords: datadid,did,memo
|
|
@@ -31,7 +31,7 @@ pip install datadid-sdk-python
|
|
|
31
31
|
|
|
32
32
|
```python
|
|
33
33
|
import asyncio
|
|
34
|
-
from
|
|
34
|
+
from datadid import DataClient
|
|
35
35
|
|
|
36
36
|
async def main():
|
|
37
37
|
client = DataClient.production()
|
|
@@ -62,8 +62,8 @@ asyncio.run(main())
|
|
|
62
62
|
### Create a client
|
|
63
63
|
|
|
64
64
|
```python
|
|
65
|
-
from
|
|
66
|
-
from
|
|
65
|
+
from datadid import DataClient
|
|
66
|
+
from datadid.data.types import DataClientOptions
|
|
67
67
|
|
|
68
68
|
client = DataClient.production()
|
|
69
69
|
# or: client = DataClient.testnet()
|
|
@@ -159,9 +159,11 @@ tokens = await client.login_with_pi(
|
|
|
159
159
|
|
|
160
160
|
```python
|
|
161
161
|
# Step 1: request a challenge message from the server
|
|
162
|
+
# origin is required — use your app's own domain
|
|
162
163
|
message = await client.get_evm_challenge(
|
|
163
164
|
"0xYourWalletAddress",
|
|
164
|
-
chain_id=985,
|
|
165
|
+
chain_id=985, # optional, defaults to 985
|
|
166
|
+
origin="https://myapp.com", # required for login_with_evm to succeed
|
|
165
167
|
)
|
|
166
168
|
|
|
167
169
|
# Step 2: sign the message with the user's wallet
|
|
@@ -238,7 +240,7 @@ await client.add_action_record(61, {"some_option": "value"})
|
|
|
238
240
|
### Error handling
|
|
239
241
|
|
|
240
242
|
```python
|
|
241
|
-
from
|
|
243
|
+
from datadid import DataDIDApiError
|
|
242
244
|
|
|
243
245
|
try:
|
|
244
246
|
await client.login_with_email_password("alice@example.com", "wrongpassword")
|
|
@@ -255,8 +257,8 @@ except DataDIDApiError as err:
|
|
|
255
257
|
By default, login methods store the access token on the client automatically. You can disable this:
|
|
256
258
|
|
|
257
259
|
```python
|
|
258
|
-
from
|
|
259
|
-
from
|
|
260
|
+
from datadid import DataClient
|
|
261
|
+
from datadid.data.types import DataClientOptions
|
|
260
262
|
|
|
261
263
|
client = DataClient(DataClientOptions(
|
|
262
264
|
base_url="https://data-be.metamemo.one",
|
|
@@ -286,7 +288,7 @@ DID operations use a **sign-then-submit** pattern. You never send your private k
|
|
|
286
288
|
### Create a client
|
|
287
289
|
|
|
288
290
|
```python
|
|
289
|
-
from
|
|
291
|
+
from datadid import DIDClient
|
|
290
292
|
|
|
291
293
|
did_client = DIDClient.production()
|
|
292
294
|
# or: did_client = DIDClient.testnet()
|
|
@@ -302,10 +304,10 @@ address = "0xYourWalletAddress"
|
|
|
302
304
|
# Step 1: get the message to sign
|
|
303
305
|
message = await did_client.get_create_message(address)
|
|
304
306
|
|
|
305
|
-
# Step 2: sign it
|
|
307
|
+
# Step 2: sign it — the message is a hex-encoded byte string, sign the bytes
|
|
306
308
|
from eth_account.messages import encode_defunct
|
|
307
309
|
from eth_account import Account
|
|
308
|
-
signed = Account.sign_message(encode_defunct(
|
|
310
|
+
signed = Account.sign_message(encode_defunct(primitive=bytes.fromhex(message[2:])), private_key=private_key)
|
|
309
311
|
signature = signed.signature.hex()
|
|
310
312
|
|
|
311
313
|
# Step 3: submit — server creates the DID on-chain
|
|
@@ -329,8 +331,8 @@ print(result)
|
|
|
329
331
|
|
|
330
332
|
```python
|
|
331
333
|
info = await did_client.get_did_info("0xYourWalletAddress")
|
|
332
|
-
print(info.did)
|
|
333
|
-
print(info.
|
|
334
|
+
print(info.did) # the DID string (e.g. "did:memo:...")
|
|
335
|
+
print(info.number) # the numeric platform ID
|
|
334
336
|
```
|
|
335
337
|
|
|
336
338
|
---
|
|
@@ -343,8 +345,9 @@ my_did = "did:memo:abc123..."
|
|
|
343
345
|
# Step 1: get the message to sign
|
|
344
346
|
message = await did_client.get_delete_message(my_did)
|
|
345
347
|
|
|
346
|
-
# Step 2: sign it
|
|
347
|
-
|
|
348
|
+
# Step 2: sign it — the message is a hex-encoded byte string, sign the bytes
|
|
349
|
+
signed = Account.sign_message(encode_defunct(primitive=bytes.fromhex(message[2:])), private_key=private_key)
|
|
350
|
+
signature = signed.signature.hex()
|
|
348
351
|
|
|
349
352
|
# Step 3: submit
|
|
350
353
|
result = await did_client.delete_did(signature, my_did)
|
|
@@ -388,7 +391,7 @@ An mfile is a file that gets its own DID minted on-chain, making it permanently
|
|
|
388
391
|
message = await did_client.create_mfile_upload(file_data, "0xYourWalletAddress")
|
|
389
392
|
|
|
390
393
|
# Step 2: sign it
|
|
391
|
-
signature = ...
|
|
394
|
+
signature = ... # sign message with your wallet
|
|
392
395
|
|
|
393
396
|
# Step 3: confirm the upload
|
|
394
397
|
result = await did_client.confirm_mfile_upload(signature, "0xYourWalletAddress")
|
|
@@ -475,5 +478,5 @@ Tests hit the real production and testnet servers. The `ACCESS_TOKEN` constant i
|
|
|
475
478
|
|
|
476
479
|
## Links
|
|
477
480
|
|
|
478
|
-
- [Data API reference](https://
|
|
481
|
+
- [Data API reference](https://memolabs.gitbook.io/datadid-developer-platform-v2/en/api)
|
|
479
482
|
- [DID API reference (Swagger)](https://prodidapi.memolabs.org/swagger/index.html)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
./datadid/__init__.py
|
|
4
|
+
./datadid/errors.py
|
|
5
|
+
./datadid/data/__init__.py
|
|
6
|
+
./datadid/data/client.py
|
|
7
|
+
./datadid/data/types.py
|
|
8
|
+
./datadid/did/__init__.py
|
|
9
|
+
./datadid/did/client.py
|
|
10
|
+
./datadid/did/types.py
|
|
11
|
+
datadid/__init__.py
|
|
12
|
+
datadid/errors.py
|
|
13
|
+
datadid/data/__init__.py
|
|
14
|
+
datadid/data/client.py
|
|
15
|
+
datadid/data/types.py
|
|
16
|
+
datadid/did/__init__.py
|
|
17
|
+
datadid/did/client.py
|
|
18
|
+
datadid/did/types.py
|
|
19
|
+
datadid_sdk_python.egg-info/PKG-INFO
|
|
20
|
+
datadid_sdk_python.egg-info/SOURCES.txt
|
|
21
|
+
datadid_sdk_python.egg-info/dependency_links.txt
|
|
22
|
+
datadid_sdk_python.egg-info/requires.txt
|
|
23
|
+
datadid_sdk_python.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
datadid
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "datadid-sdk-python"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.5"
|
|
8
8
|
description = "Python SDK for the DataDID developer platform — Data API and DID API clients"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -16,7 +16,7 @@ dependencies = [
|
|
|
16
16
|
|
|
17
17
|
[tool.setuptools.packages.find]
|
|
18
18
|
where = ["."]
|
|
19
|
-
include = ["
|
|
19
|
+
include = ["datadid*"]
|
|
20
20
|
|
|
21
21
|
[tool.setuptools.package-dir]
|
|
22
22
|
"" = "."
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
README.md
|
|
2
|
-
pyproject.toml
|
|
3
|
-
./src/__init__.py
|
|
4
|
-
./src/errors.py
|
|
5
|
-
./src/data/__init__.py
|
|
6
|
-
./src/data/client.py
|
|
7
|
-
./src/data/types.py
|
|
8
|
-
./src/did/__init__.py
|
|
9
|
-
./src/did/client.py
|
|
10
|
-
./src/did/types.py
|
|
11
|
-
datadid_sdk_python.egg-info/PKG-INFO
|
|
12
|
-
datadid_sdk_python.egg-info/SOURCES.txt
|
|
13
|
-
datadid_sdk_python.egg-info/dependency_links.txt
|
|
14
|
-
datadid_sdk_python.egg-info/requires.txt
|
|
15
|
-
datadid_sdk_python.egg-info/top_level.txt
|
|
16
|
-
src/__init__.py
|
|
17
|
-
src/errors.py
|
|
18
|
-
src/data/__init__.py
|
|
19
|
-
src/data/client.py
|
|
20
|
-
src/data/types.py
|
|
21
|
-
src/did/__init__.py
|
|
22
|
-
src/did/client.py
|
|
23
|
-
src/did/types.py
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
src
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{datadid_sdk_python-1.0.0 → datadid_sdk_python-1.0.5}/datadid_sdk_python.egg-info/requires.txt
RENAMED
|
File without changes
|
|
File without changes
|