datadid-sdk-python 1.0.3__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.
Files changed (19) hide show
  1. {datadid_sdk_python-1.0.3 → datadid_sdk_python-1.0.5}/PKG-INFO +31 -36
  2. {datadid_sdk_python-1.0.3 → datadid_sdk_python-1.0.5}/README.md +30 -35
  3. {datadid_sdk_python-1.0.3/src → datadid_sdk_python-1.0.5/datadid}/__init__.py +0 -2
  4. {datadid_sdk_python-1.0.3/src → datadid_sdk_python-1.0.5/datadid}/data/client.py +8 -2
  5. {datadid_sdk_python-1.0.3/src → datadid_sdk_python-1.0.5/datadid}/did/client.py +41 -16
  6. {datadid_sdk_python-1.0.3/src → datadid_sdk_python-1.0.5/datadid}/did/types.py +2 -12
  7. {datadid_sdk_python-1.0.3 → datadid_sdk_python-1.0.5}/datadid_sdk_python.egg-info/PKG-INFO +31 -36
  8. datadid_sdk_python-1.0.5/datadid_sdk_python.egg-info/SOURCES.txt +23 -0
  9. datadid_sdk_python-1.0.5/datadid_sdk_python.egg-info/top_level.txt +1 -0
  10. {datadid_sdk_python-1.0.3 → datadid_sdk_python-1.0.5}/pyproject.toml +2 -2
  11. datadid_sdk_python-1.0.3/datadid_sdk_python.egg-info/SOURCES.txt +0 -23
  12. datadid_sdk_python-1.0.3/datadid_sdk_python.egg-info/top_level.txt +0 -1
  13. {datadid_sdk_python-1.0.3/src → datadid_sdk_python-1.0.5/datadid}/data/__init__.py +0 -0
  14. {datadid_sdk_python-1.0.3/src → datadid_sdk_python-1.0.5/datadid}/data/types.py +0 -0
  15. {datadid_sdk_python-1.0.3/src → datadid_sdk_python-1.0.5/datadid}/did/__init__.py +0 -0
  16. {datadid_sdk_python-1.0.3/src → datadid_sdk_python-1.0.5/datadid}/errors.py +0 -0
  17. {datadid_sdk_python-1.0.3 → datadid_sdk_python-1.0.5}/datadid_sdk_python.egg-info/dependency_links.txt +0 -0
  18. {datadid_sdk_python-1.0.3 → datadid_sdk_python-1.0.5}/datadid_sdk_python.egg-info/requires.txt +0 -0
  19. {datadid_sdk_python-1.0.3 → 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
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 src import DataClient
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 src import DataClient
66
- from src.data.types import DataClientOptions
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, # optional
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
@@ -229,12 +231,16 @@ await client.add_action_record(61)
229
231
  await client.add_action_record(61, {"some_option": "value"})
230
232
  ```
231
233
 
234
+ **AliveCheck action IDs** (AliveCheck is the platform's liveness/subscription service):
235
+ - `5` — first-time AliveCheck subscription
236
+ - `6` — AliveCheck renewal
237
+
232
238
  ---
233
239
 
234
240
  ### Error handling
235
241
 
236
242
  ```python
237
- from src import DataDIDApiError
243
+ from datadid import DataDIDApiError
238
244
 
239
245
  try:
240
246
  await client.login_with_email_password("alice@example.com", "wrongpassword")
@@ -251,8 +257,8 @@ except DataDIDApiError as err:
251
257
  By default, login methods store the access token on the client automatically. You can disable this:
252
258
 
253
259
  ```python
254
- from src import DataClient
255
- from src.data.types import DataClientOptions
260
+ from datadid import DataClient
261
+ from datadid.data.types import DataClientOptions
256
262
 
257
263
  client = DataClient(DataClientOptions(
258
264
  base_url="https://data-be.metamemo.one",
@@ -282,7 +288,7 @@ DID operations use a **sign-then-submit** pattern. You never send your private k
282
288
  ### Create a client
283
289
 
284
290
  ```python
285
- from src import DIDClient
291
+ from datadid import DIDClient
286
292
 
287
293
  did_client = DIDClient.production()
288
294
  # or: did_client = DIDClient.testnet()
@@ -298,10 +304,10 @@ address = "0xYourWalletAddress"
298
304
  # Step 1: get the message to sign
299
305
  message = await did_client.get_create_message(address)
300
306
 
301
- # Step 2: sign it with your wallet (eth_account example)
307
+ # Step 2: sign it the message is a hex-encoded byte string, sign the bytes
302
308
  from eth_account.messages import encode_defunct
303
309
  from eth_account import Account
304
- signed = Account.sign_message(encode_defunct(text=message), private_key=private_key)
310
+ signed = Account.sign_message(encode_defunct(primitive=bytes.fromhex(message[2:])), private_key=private_key)
305
311
  signature = signed.signature.hex()
306
312
 
307
313
  # Step 3: submit — server creates the DID on-chain
@@ -325,8 +331,8 @@ print(result)
325
331
 
326
332
  ```python
327
333
  info = await did_client.get_did_info("0xYourWalletAddress")
328
- print(info.did) # the DID string
329
- print(info.info) # list of DIDChainInfo(address, balance, chain)
334
+ print(info.did) # the DID string (e.g. "did:memo:...")
335
+ print(info.number) # the numeric platform ID
330
336
  ```
331
337
 
332
338
  ---
@@ -339,8 +345,9 @@ my_did = "did:memo:abc123..."
339
345
  # Step 1: get the message to sign
340
346
  message = await did_client.get_delete_message(my_did)
341
347
 
342
- # Step 2: sign it
343
- signature = ...
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()
344
351
 
345
352
  # Step 3: submit
346
353
  result = await did_client.delete_did(signature, my_did)
@@ -384,7 +391,7 @@ An mfile is a file that gets its own DID minted on-chain, making it permanently
384
391
  message = await did_client.create_mfile_upload(file_data, "0xYourWalletAddress")
385
392
 
386
393
  # Step 2: sign it
387
- signature = ...
394
+ signature = ... # sign message with your wallet
388
395
 
389
396
  # Step 3: confirm the upload
390
397
  result = await did_client.confirm_mfile_upload(signature, "0xYourWalletAddress")
@@ -409,19 +416,7 @@ file = await did_client.download_mfile(
409
416
  python tests/run.py
410
417
  ```
411
418
 
412
- Tests hit the real production and testnet servers. A valid access token is required.
413
-
414
- 1. Copy `.env.example` to `.env`
415
- 2. Paste your token as `DATADID_TOKEN=eyJ...`
416
-
417
- To get a token: log into the DataDID app, open browser devtools (F12 → Network tab), find the login request, and copy the `access_token` from the response JSON. Tokens expire after 24 hours.
418
-
419
- You can also pass the token inline without creating a `.env` file:
420
-
421
- ```bash
422
- DATADID_TOKEN=eyJ... python tests/run.py # macOS / Linux
423
- set DATADID_TOKEN=eyJ... && python tests/run.py # Windows cmd
424
- ```
419
+ Tests hit the real production and testnet servers. The `ACCESS_TOKEN` constant in `tests/data_client_test.py` needs to be a valid token; replace it if tests fail with a 401 error.
425
420
 
426
421
  ---
427
422
 
@@ -436,14 +431,14 @@ set DATADID_TOKEN=eyJ... && python tests/run.py # Windows cmd
436
431
  | `set_access_token(token)` | Manually set the auth token |
437
432
  | `get_access_token()` | Read the current token |
438
433
  | `send_email_code(email)` | Send verification code to email |
439
- | `login_with_email(email, code, source, useragent?)` | Login with email + code |
440
- | `register_with_email(email, code, password, source, useragent?)` | Register new account |
434
+ | `login_with_email(email, code, source)` | Login with email + code |
435
+ | `register_with_email(email, code, password, source)` | Register new account |
441
436
  | `login_with_email_password(email, password)` | Login with email + password |
442
437
  | `reset_password(email, code, new_password)` | Reset password |
443
- | `login_with_telegram(initdata, source, useragent?)` | Login with Telegram |
444
- | `login_with_pi(pi_access_token, source, useragent?)` | Login with Pi Browser |
445
- | `get_evm_challenge(address, chain_id?, origin?)` | Get EVM sign-in challenge |
446
- | `login_with_evm(message, signature, source, useragent?)` | Login with EVM wallet signature |
438
+ | `login_with_telegram(initdata, source)` | Login with Telegram |
439
+ | `login_with_pi(pi_access_token, source)` | Login with Pi Browser |
440
+ | `get_evm_challenge(address, chain_id?)` | Get EVM sign-in challenge |
441
+ | `login_with_evm(message, signature, source)` | Login with EVM wallet signature |
447
442
  | `refresh_token(refresh_token)` | Get a new access token |
448
443
  | `get_me()` | Basic user info (uid, email, role) |
449
444
  | `get_user_info()` | Full user profile |
@@ -483,5 +478,5 @@ set DATADID_TOKEN=eyJ... && python tests/run.py # Windows cmd
483
478
 
484
479
  ## Links
485
480
 
486
- - [Data API reference](https://data-be.metamemo.one)
481
+ - [Data API reference](https://memolabs.gitbook.io/datadid-developer-platform-v2/en/api)
487
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 src import DataClient
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 src import DataClient
56
- from src.data.types import DataClientOptions
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, # optional
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
@@ -219,12 +221,16 @@ await client.add_action_record(61)
219
221
  await client.add_action_record(61, {"some_option": "value"})
220
222
  ```
221
223
 
224
+ **AliveCheck action IDs** (AliveCheck is the platform's liveness/subscription service):
225
+ - `5` — first-time AliveCheck subscription
226
+ - `6` — AliveCheck renewal
227
+
222
228
  ---
223
229
 
224
230
  ### Error handling
225
231
 
226
232
  ```python
227
- from src import DataDIDApiError
233
+ from datadid import DataDIDApiError
228
234
 
229
235
  try:
230
236
  await client.login_with_email_password("alice@example.com", "wrongpassword")
@@ -241,8 +247,8 @@ except DataDIDApiError as err:
241
247
  By default, login methods store the access token on the client automatically. You can disable this:
242
248
 
243
249
  ```python
244
- from src import DataClient
245
- from src.data.types import DataClientOptions
250
+ from datadid import DataClient
251
+ from datadid.data.types import DataClientOptions
246
252
 
247
253
  client = DataClient(DataClientOptions(
248
254
  base_url="https://data-be.metamemo.one",
@@ -272,7 +278,7 @@ DID operations use a **sign-then-submit** pattern. You never send your private k
272
278
  ### Create a client
273
279
 
274
280
  ```python
275
- from src import DIDClient
281
+ from datadid import DIDClient
276
282
 
277
283
  did_client = DIDClient.production()
278
284
  # or: did_client = DIDClient.testnet()
@@ -288,10 +294,10 @@ address = "0xYourWalletAddress"
288
294
  # Step 1: get the message to sign
289
295
  message = await did_client.get_create_message(address)
290
296
 
291
- # Step 2: sign it with your wallet (eth_account example)
297
+ # Step 2: sign it the message is a hex-encoded byte string, sign the bytes
292
298
  from eth_account.messages import encode_defunct
293
299
  from eth_account import Account
294
- signed = Account.sign_message(encode_defunct(text=message), private_key=private_key)
300
+ signed = Account.sign_message(encode_defunct(primitive=bytes.fromhex(message[2:])), private_key=private_key)
295
301
  signature = signed.signature.hex()
296
302
 
297
303
  # Step 3: submit — server creates the DID on-chain
@@ -315,8 +321,8 @@ print(result)
315
321
 
316
322
  ```python
317
323
  info = await did_client.get_did_info("0xYourWalletAddress")
318
- print(info.did) # the DID string
319
- print(info.info) # list of DIDChainInfo(address, balance, chain)
324
+ print(info.did) # the DID string (e.g. "did:memo:...")
325
+ print(info.number) # the numeric platform ID
320
326
  ```
321
327
 
322
328
  ---
@@ -329,8 +335,9 @@ my_did = "did:memo:abc123..."
329
335
  # Step 1: get the message to sign
330
336
  message = await did_client.get_delete_message(my_did)
331
337
 
332
- # Step 2: sign it
333
- signature = ...
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()
334
341
 
335
342
  # Step 3: submit
336
343
  result = await did_client.delete_did(signature, my_did)
@@ -374,7 +381,7 @@ An mfile is a file that gets its own DID minted on-chain, making it permanently
374
381
  message = await did_client.create_mfile_upload(file_data, "0xYourWalletAddress")
375
382
 
376
383
  # Step 2: sign it
377
- signature = ...
384
+ signature = ... # sign message with your wallet
378
385
 
379
386
  # Step 3: confirm the upload
380
387
  result = await did_client.confirm_mfile_upload(signature, "0xYourWalletAddress")
@@ -399,19 +406,7 @@ file = await did_client.download_mfile(
399
406
  python tests/run.py
400
407
  ```
401
408
 
402
- Tests hit the real production and testnet servers. A valid access token is required.
403
-
404
- 1. Copy `.env.example` to `.env`
405
- 2. Paste your token as `DATADID_TOKEN=eyJ...`
406
-
407
- To get a token: log into the DataDID app, open browser devtools (F12 → Network tab), find the login request, and copy the `access_token` from the response JSON. Tokens expire after 24 hours.
408
-
409
- You can also pass the token inline without creating a `.env` file:
410
-
411
- ```bash
412
- DATADID_TOKEN=eyJ... python tests/run.py # macOS / Linux
413
- set DATADID_TOKEN=eyJ... && python tests/run.py # Windows cmd
414
- ```
409
+ Tests hit the real production and testnet servers. The `ACCESS_TOKEN` constant in `tests/data_client_test.py` needs to be a valid token; replace it if tests fail with a 401 error.
415
410
 
416
411
  ---
417
412
 
@@ -426,14 +421,14 @@ set DATADID_TOKEN=eyJ... && python tests/run.py # Windows cmd
426
421
  | `set_access_token(token)` | Manually set the auth token |
427
422
  | `get_access_token()` | Read the current token |
428
423
  | `send_email_code(email)` | Send verification code to email |
429
- | `login_with_email(email, code, source, useragent?)` | Login with email + code |
430
- | `register_with_email(email, code, password, source, useragent?)` | Register new account |
424
+ | `login_with_email(email, code, source)` | Login with email + code |
425
+ | `register_with_email(email, code, password, source)` | Register new account |
431
426
  | `login_with_email_password(email, password)` | Login with email + password |
432
427
  | `reset_password(email, code, new_password)` | Reset password |
433
- | `login_with_telegram(initdata, source, useragent?)` | Login with Telegram |
434
- | `login_with_pi(pi_access_token, source, useragent?)` | Login with Pi Browser |
435
- | `get_evm_challenge(address, chain_id?, origin?)` | Get EVM sign-in challenge |
436
- | `login_with_evm(message, signature, source, useragent?)` | Login with EVM wallet signature |
428
+ | `login_with_telegram(initdata, source)` | Login with Telegram |
429
+ | `login_with_pi(pi_access_token, source)` | Login with Pi Browser |
430
+ | `get_evm_challenge(address, chain_id?)` | Get EVM sign-in challenge |
431
+ | `login_with_evm(message, signature, source)` | Login with EVM wallet signature |
437
432
  | `refresh_token(refresh_token)` | Get a new access token |
438
433
  | `get_me()` | Basic user info (uid, email, role) |
439
434
  | `get_user_info()` | Full user profile |
@@ -473,5 +468,5 @@ set DATADID_TOKEN=eyJ... && python tests/run.py # Windows cmd
473
468
 
474
469
  ## Links
475
470
 
476
- - [Data API reference](https://data-be.metamemo.one)
471
+ - [Data API reference](https://memolabs.gitbook.io/datadid-developer-platform-v2/en/api)
477
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) -> Any:
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
- return await self._request("GET", f"/did/exist?address={address}")
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 (DID string + per-chain balance/address details).
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
- data = await self._request("GET", f"/did/info?address={address}")
99
- chain_list = [
100
- DIDChainInfo(
101
- address=item.get("address", ""),
102
- balance=item.get("balance", ""),
103
- chain=item.get("chain", ""),
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, field
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
- info: List[DIDChainInfo] = field(default_factory=list)
39
+ number: str
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datadid-sdk-python
3
- Version: 1.0.3
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 src import DataClient
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 src import DataClient
66
- from src.data.types import DataClientOptions
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, # optional
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
@@ -229,12 +231,16 @@ await client.add_action_record(61)
229
231
  await client.add_action_record(61, {"some_option": "value"})
230
232
  ```
231
233
 
234
+ **AliveCheck action IDs** (AliveCheck is the platform's liveness/subscription service):
235
+ - `5` — first-time AliveCheck subscription
236
+ - `6` — AliveCheck renewal
237
+
232
238
  ---
233
239
 
234
240
  ### Error handling
235
241
 
236
242
  ```python
237
- from src import DataDIDApiError
243
+ from datadid import DataDIDApiError
238
244
 
239
245
  try:
240
246
  await client.login_with_email_password("alice@example.com", "wrongpassword")
@@ -251,8 +257,8 @@ except DataDIDApiError as err:
251
257
  By default, login methods store the access token on the client automatically. You can disable this:
252
258
 
253
259
  ```python
254
- from src import DataClient
255
- from src.data.types import DataClientOptions
260
+ from datadid import DataClient
261
+ from datadid.data.types import DataClientOptions
256
262
 
257
263
  client = DataClient(DataClientOptions(
258
264
  base_url="https://data-be.metamemo.one",
@@ -282,7 +288,7 @@ DID operations use a **sign-then-submit** pattern. You never send your private k
282
288
  ### Create a client
283
289
 
284
290
  ```python
285
- from src import DIDClient
291
+ from datadid import DIDClient
286
292
 
287
293
  did_client = DIDClient.production()
288
294
  # or: did_client = DIDClient.testnet()
@@ -298,10 +304,10 @@ address = "0xYourWalletAddress"
298
304
  # Step 1: get the message to sign
299
305
  message = await did_client.get_create_message(address)
300
306
 
301
- # Step 2: sign it with your wallet (eth_account example)
307
+ # Step 2: sign it the message is a hex-encoded byte string, sign the bytes
302
308
  from eth_account.messages import encode_defunct
303
309
  from eth_account import Account
304
- signed = Account.sign_message(encode_defunct(text=message), private_key=private_key)
310
+ signed = Account.sign_message(encode_defunct(primitive=bytes.fromhex(message[2:])), private_key=private_key)
305
311
  signature = signed.signature.hex()
306
312
 
307
313
  # Step 3: submit — server creates the DID on-chain
@@ -325,8 +331,8 @@ print(result)
325
331
 
326
332
  ```python
327
333
  info = await did_client.get_did_info("0xYourWalletAddress")
328
- print(info.did) # the DID string
329
- print(info.info) # list of DIDChainInfo(address, balance, chain)
334
+ print(info.did) # the DID string (e.g. "did:memo:...")
335
+ print(info.number) # the numeric platform ID
330
336
  ```
331
337
 
332
338
  ---
@@ -339,8 +345,9 @@ my_did = "did:memo:abc123..."
339
345
  # Step 1: get the message to sign
340
346
  message = await did_client.get_delete_message(my_did)
341
347
 
342
- # Step 2: sign it
343
- signature = ...
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()
344
351
 
345
352
  # Step 3: submit
346
353
  result = await did_client.delete_did(signature, my_did)
@@ -384,7 +391,7 @@ An mfile is a file that gets its own DID minted on-chain, making it permanently
384
391
  message = await did_client.create_mfile_upload(file_data, "0xYourWalletAddress")
385
392
 
386
393
  # Step 2: sign it
387
- signature = ...
394
+ signature = ... # sign message with your wallet
388
395
 
389
396
  # Step 3: confirm the upload
390
397
  result = await did_client.confirm_mfile_upload(signature, "0xYourWalletAddress")
@@ -409,19 +416,7 @@ file = await did_client.download_mfile(
409
416
  python tests/run.py
410
417
  ```
411
418
 
412
- Tests hit the real production and testnet servers. A valid access token is required.
413
-
414
- 1. Copy `.env.example` to `.env`
415
- 2. Paste your token as `DATADID_TOKEN=eyJ...`
416
-
417
- To get a token: log into the DataDID app, open browser devtools (F12 → Network tab), find the login request, and copy the `access_token` from the response JSON. Tokens expire after 24 hours.
418
-
419
- You can also pass the token inline without creating a `.env` file:
420
-
421
- ```bash
422
- DATADID_TOKEN=eyJ... python tests/run.py # macOS / Linux
423
- set DATADID_TOKEN=eyJ... && python tests/run.py # Windows cmd
424
- ```
419
+ Tests hit the real production and testnet servers. The `ACCESS_TOKEN` constant in `tests/data_client_test.py` needs to be a valid token; replace it if tests fail with a 401 error.
425
420
 
426
421
  ---
427
422
 
@@ -436,14 +431,14 @@ set DATADID_TOKEN=eyJ... && python tests/run.py # Windows cmd
436
431
  | `set_access_token(token)` | Manually set the auth token |
437
432
  | `get_access_token()` | Read the current token |
438
433
  | `send_email_code(email)` | Send verification code to email |
439
- | `login_with_email(email, code, source, useragent?)` | Login with email + code |
440
- | `register_with_email(email, code, password, source, useragent?)` | Register new account |
434
+ | `login_with_email(email, code, source)` | Login with email + code |
435
+ | `register_with_email(email, code, password, source)` | Register new account |
441
436
  | `login_with_email_password(email, password)` | Login with email + password |
442
437
  | `reset_password(email, code, new_password)` | Reset password |
443
- | `login_with_telegram(initdata, source, useragent?)` | Login with Telegram |
444
- | `login_with_pi(pi_access_token, source, useragent?)` | Login with Pi Browser |
445
- | `get_evm_challenge(address, chain_id?, origin?)` | Get EVM sign-in challenge |
446
- | `login_with_evm(message, signature, source, useragent?)` | Login with EVM wallet signature |
438
+ | `login_with_telegram(initdata, source)` | Login with Telegram |
439
+ | `login_with_pi(pi_access_token, source)` | Login with Pi Browser |
440
+ | `get_evm_challenge(address, chain_id?)` | Get EVM sign-in challenge |
441
+ | `login_with_evm(message, signature, source)` | Login with EVM wallet signature |
447
442
  | `refresh_token(refresh_token)` | Get a new access token |
448
443
  | `get_me()` | Basic user info (uid, email, role) |
449
444
  | `get_user_info()` | Full user profile |
@@ -483,5 +478,5 @@ set DATADID_TOKEN=eyJ... && python tests/run.py # Windows cmd
483
478
 
484
479
  ## Links
485
480
 
486
- - [Data API reference](https://data-be.metamemo.one)
481
+ - [Data API reference](https://memolabs.gitbook.io/datadid-developer-platform-v2/en/api)
487
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "datadid-sdk-python"
7
- version = "1.0.3"
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 = ["src*"]
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