paperproof-sdk-py 0.2.2__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.
- paperproof/__init__.py +270 -0
- paperproof/abort_explainer.py +352 -0
- paperproof/analytics.py +406 -0
- paperproof/builders/__init__.py +8 -0
- paperproof/builders/base.py +39 -0
- paperproof/builders/comments.py +91 -0
- paperproof/builders/governance.py +124 -0
- paperproof/builders/ops.py +291 -0
- paperproof/builders/publishing.py +334 -0
- paperproof/cli.py +312 -0
- paperproof/client.py +323 -0
- paperproof/coin_utils.py +120 -0
- paperproof/constants.py +108 -0
- paperproof/deployment_update.py +225 -0
- paperproof/deployment_verifier.py +218 -0
- paperproof/deployments.py +31 -0
- paperproof/errors.py +93 -0
- paperproof/events.py +358 -0
- paperproof/events_trust.py +76 -0
- paperproof/mainnet_harness.py +394 -0
- paperproof/py.typed +1 -0
- paperproof/pysui_executor.py +432 -0
- paperproof/query.py +301 -0
- paperproof/query_providers.py +275 -0
- paperproof/robust.py +143 -0
- paperproof/service.py +269 -0
- paperproof/sui.py +423 -0
- paperproof/sync.py +292 -0
- paperproof/transactions.py +62 -0
- paperproof/types.py +533 -0
- paperproof/utils.py +125 -0
- paperproof/validation.py +329 -0
- paperproof/views.py +298 -0
- paperproof/walrus.py +131 -0
- paperproof/walrus_robust.py +299 -0
- paperproof/watch.py +324 -0
- paperproof_sdk_py-0.2.2.dist-info/METADATA +620 -0
- paperproof_sdk_py-0.2.2.dist-info/RECORD +43 -0
- paperproof_sdk_py-0.2.2.dist-info/WHEEL +5 -0
- paperproof_sdk_py-0.2.2.dist-info/entry_points.txt +2 -0
- paperproof_sdk_py-0.2.2.dist-info/licenses/LICENSE +201 -0
- paperproof_sdk_py-0.2.2.dist-info/licenses/NOTICE +5 -0
- paperproof_sdk_py-0.2.2.dist-info/top_level.txt +1 -0
paperproof/__init__.py
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# Copyright (c) 2026 PaperProof Labs
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
from paperproof.abort_explainer import (
|
|
5
|
+
MoveAbortInfo,
|
|
6
|
+
PaperProofErrorExplanation,
|
|
7
|
+
explain_paperproof_error,
|
|
8
|
+
format_paperproof_error_explanation,
|
|
9
|
+
parse_move_abort,
|
|
10
|
+
)
|
|
11
|
+
from paperproof.analytics import (
|
|
12
|
+
artifact_records_to_csv,
|
|
13
|
+
artifact_records_to_dataframe,
|
|
14
|
+
artifact_records_to_dicts,
|
|
15
|
+
artifact_records_to_jsonl,
|
|
16
|
+
batch_get_objects,
|
|
17
|
+
collect_events,
|
|
18
|
+
event_page_to_dicts,
|
|
19
|
+
event_to_dict,
|
|
20
|
+
events_to_csv,
|
|
21
|
+
events_to_dataframe,
|
|
22
|
+
events_to_dicts,
|
|
23
|
+
events_to_jsonl,
|
|
24
|
+
query_governance_history,
|
|
25
|
+
query_recent_activity,
|
|
26
|
+
record_to_dict,
|
|
27
|
+
records_to_csv,
|
|
28
|
+
records_to_dataframe,
|
|
29
|
+
records_to_dicts,
|
|
30
|
+
records_to_jsonl,
|
|
31
|
+
vote_records_to_csv,
|
|
32
|
+
vote_records_to_dataframe,
|
|
33
|
+
vote_records_to_dicts,
|
|
34
|
+
vote_records_to_jsonl,
|
|
35
|
+
write_events_csv,
|
|
36
|
+
write_events_jsonl,
|
|
37
|
+
write_records_csv,
|
|
38
|
+
write_records_jsonl,
|
|
39
|
+
)
|
|
40
|
+
from paperproof.client import PaperProofClient, create_paperproof_sdk
|
|
41
|
+
from paperproof.coin_utils import CoinLike, CoinSelection, CoinSummary, select_coins_covering, summarize_coins
|
|
42
|
+
from paperproof.constants import (
|
|
43
|
+
ARTIFACT_TYPES,
|
|
44
|
+
COMMENT_MODE,
|
|
45
|
+
COMMENT_STATUS,
|
|
46
|
+
DIRECT_AUTHORITY_MODE,
|
|
47
|
+
FEE_LEVEL,
|
|
48
|
+
GOVERNANCE,
|
|
49
|
+
MAX_PROPOSER_THRESHOLD,
|
|
50
|
+
MIN_PROPOSER_THRESHOLD,
|
|
51
|
+
PROTOCOL_LIMITS,
|
|
52
|
+
SERIES_STATUS,
|
|
53
|
+
TREE_STATUS,
|
|
54
|
+
)
|
|
55
|
+
from paperproof.deployment_update import (
|
|
56
|
+
DEFAULT_DEPLOYMENT_MANIFEST_BASE_URL,
|
|
57
|
+
DEFAULT_MAINNET_DEPLOYMENT_MANIFEST_URL,
|
|
58
|
+
check_deployment_update,
|
|
59
|
+
default_deployment_manifest_url,
|
|
60
|
+
format_deployment_update_check,
|
|
61
|
+
)
|
|
62
|
+
from paperproof.deployment_verifier import format_deployment_verification, verify_deployment
|
|
63
|
+
from paperproof.deployments import MAINNET_DEPLOYMENT
|
|
64
|
+
from paperproof.errors import (
|
|
65
|
+
ContractCallError,
|
|
66
|
+
EventParseError,
|
|
67
|
+
InsufficientBalanceError,
|
|
68
|
+
InvalidAddressError,
|
|
69
|
+
InvalidInputError,
|
|
70
|
+
InvalidObjectIdError,
|
|
71
|
+
InvalidPackageIdError,
|
|
72
|
+
NetworkError,
|
|
73
|
+
ObjectNotFoundError,
|
|
74
|
+
PaperProofError,
|
|
75
|
+
TransactionBuildError,
|
|
76
|
+
TransactionExecutionError,
|
|
77
|
+
WalletNotConnectedError,
|
|
78
|
+
)
|
|
79
|
+
from paperproof.events import (
|
|
80
|
+
extract_add_version_result,
|
|
81
|
+
extract_artifact_status_changed_event,
|
|
82
|
+
extract_comment_result,
|
|
83
|
+
extract_comment_status_changed_event,
|
|
84
|
+
extract_events_by_struct,
|
|
85
|
+
extract_like_event,
|
|
86
|
+
extract_owner_transferred_event,
|
|
87
|
+
extract_proposal_executed_event,
|
|
88
|
+
extract_proposal_expired_event,
|
|
89
|
+
extract_proposal_finalized_event,
|
|
90
|
+
extract_proposal_result,
|
|
91
|
+
extract_protocol_paused_changed_event,
|
|
92
|
+
extract_publish_result,
|
|
93
|
+
extract_tree_status_changed_event,
|
|
94
|
+
extract_unlike_event,
|
|
95
|
+
extract_vote_cast_events,
|
|
96
|
+
extract_vote_claimed_event,
|
|
97
|
+
)
|
|
98
|
+
from paperproof.pysui_executor import (
|
|
99
|
+
PysuiCompileResult,
|
|
100
|
+
PysuiExecutionProvider,
|
|
101
|
+
PysuiExecutionResult,
|
|
102
|
+
PysuiTransactionCompiler,
|
|
103
|
+
PysuiTransactionService,
|
|
104
|
+
normalize_pysui_execution_result,
|
|
105
|
+
)
|
|
106
|
+
from paperproof.query import PaperProofQueryClient, SeriesDetails
|
|
107
|
+
from paperproof.query_providers import (
|
|
108
|
+
DEFAULT_GRAPHQL_ENDPOINTS,
|
|
109
|
+
FallbackQueryProvider,
|
|
110
|
+
GraphQLQueryProvider,
|
|
111
|
+
JsonRpcQueryProvider,
|
|
112
|
+
PaperProofQueryProvider,
|
|
113
|
+
)
|
|
114
|
+
from paperproof.robust import RetryOptions, robust_execute_plan, with_retries
|
|
115
|
+
from paperproof.service import PaperProofService
|
|
116
|
+
from paperproof.sync import PaperProofSyncClient, create_paperproof_sync_sdk, run_sync
|
|
117
|
+
from paperproof.transactions import MoveCall, TransactionPlan
|
|
118
|
+
from paperproof.types import (
|
|
119
|
+
ArtifactPublishedRecord,
|
|
120
|
+
EventPage,
|
|
121
|
+
EventQuery,
|
|
122
|
+
MyVoteRecord,
|
|
123
|
+
Pagination,
|
|
124
|
+
PaperProofQueryTransport,
|
|
125
|
+
PaperProofTransport,
|
|
126
|
+
TransactionExecutionResult,
|
|
127
|
+
)
|
|
128
|
+
from paperproof.walrus_robust import (
|
|
129
|
+
ContentPublishResult,
|
|
130
|
+
ContentReadResult,
|
|
131
|
+
PaperProofContentService,
|
|
132
|
+
RobustWalrusClient,
|
|
133
|
+
WalrusExtendResult,
|
|
134
|
+
WalrusTransferResult,
|
|
135
|
+
WalrusUploadResult,
|
|
136
|
+
blob_digest,
|
|
137
|
+
)
|
|
138
|
+
from paperproof.watch import PaperProofEventWatcher, PaperProofWatchClient, WatchOptions
|
|
139
|
+
|
|
140
|
+
__all__ = [
|
|
141
|
+
"ARTIFACT_TYPES",
|
|
142
|
+
"ArtifactPublishedRecord",
|
|
143
|
+
"COMMENT_MODE",
|
|
144
|
+
"COMMENT_STATUS",
|
|
145
|
+
"CoinLike",
|
|
146
|
+
"CoinSelection",
|
|
147
|
+
"CoinSummary",
|
|
148
|
+
"ContentPublishResult",
|
|
149
|
+
"ContentReadResult",
|
|
150
|
+
"ContractCallError",
|
|
151
|
+
"DEFAULT_GRAPHQL_ENDPOINTS",
|
|
152
|
+
"DEFAULT_DEPLOYMENT_MANIFEST_BASE_URL",
|
|
153
|
+
"DEFAULT_MAINNET_DEPLOYMENT_MANIFEST_URL",
|
|
154
|
+
"DIRECT_AUTHORITY_MODE",
|
|
155
|
+
"FEE_LEVEL",
|
|
156
|
+
"FallbackQueryProvider",
|
|
157
|
+
"GOVERNANCE",
|
|
158
|
+
"GraphQLQueryProvider",
|
|
159
|
+
"EventPage",
|
|
160
|
+
"EventQuery",
|
|
161
|
+
"EventParseError",
|
|
162
|
+
"InsufficientBalanceError",
|
|
163
|
+
"InvalidAddressError",
|
|
164
|
+
"InvalidInputError",
|
|
165
|
+
"InvalidObjectIdError",
|
|
166
|
+
"InvalidPackageIdError",
|
|
167
|
+
"JsonRpcQueryProvider",
|
|
168
|
+
"MAINNET_DEPLOYMENT",
|
|
169
|
+
"MAX_PROPOSER_THRESHOLD",
|
|
170
|
+
"MIN_PROPOSER_THRESHOLD",
|
|
171
|
+
"MoveAbortInfo",
|
|
172
|
+
"MoveCall",
|
|
173
|
+
"MyVoteRecord",
|
|
174
|
+
"NetworkError",
|
|
175
|
+
"ObjectNotFoundError",
|
|
176
|
+
"PROTOCOL_LIMITS",
|
|
177
|
+
"Pagination",
|
|
178
|
+
"PaperProofErrorExplanation",
|
|
179
|
+
"PaperProofClient",
|
|
180
|
+
"PaperProofContentService",
|
|
181
|
+
"PaperProofError",
|
|
182
|
+
"PaperProofQueryProvider",
|
|
183
|
+
"PaperProofQueryClient",
|
|
184
|
+
"PaperProofQueryTransport",
|
|
185
|
+
"PaperProofService",
|
|
186
|
+
"PaperProofSyncClient",
|
|
187
|
+
"PaperProofEventWatcher",
|
|
188
|
+
"PaperProofWatchClient",
|
|
189
|
+
"PaperProofTransport",
|
|
190
|
+
"PysuiCompileResult",
|
|
191
|
+
"PysuiExecutionProvider",
|
|
192
|
+
"PysuiExecutionResult",
|
|
193
|
+
"PysuiTransactionCompiler",
|
|
194
|
+
"PysuiTransactionService",
|
|
195
|
+
"RetryOptions",
|
|
196
|
+
"RobustWalrusClient",
|
|
197
|
+
"SERIES_STATUS",
|
|
198
|
+
"SeriesDetails",
|
|
199
|
+
"TREE_STATUS",
|
|
200
|
+
"TransactionPlan",
|
|
201
|
+
"TransactionBuildError",
|
|
202
|
+
"TransactionExecutionResult",
|
|
203
|
+
"TransactionExecutionError",
|
|
204
|
+
"WalletNotConnectedError",
|
|
205
|
+
"WatchOptions",
|
|
206
|
+
"WalrusExtendResult",
|
|
207
|
+
"WalrusTransferResult",
|
|
208
|
+
"WalrusUploadResult",
|
|
209
|
+
"artifact_records_to_csv",
|
|
210
|
+
"artifact_records_to_dataframe",
|
|
211
|
+
"artifact_records_to_dicts",
|
|
212
|
+
"artifact_records_to_jsonl",
|
|
213
|
+
"batch_get_objects",
|
|
214
|
+
"blob_digest",
|
|
215
|
+
"check_deployment_update",
|
|
216
|
+
"collect_events",
|
|
217
|
+
"create_paperproof_sdk",
|
|
218
|
+
"create_paperproof_sync_sdk",
|
|
219
|
+
"default_deployment_manifest_url",
|
|
220
|
+
"event_page_to_dicts",
|
|
221
|
+
"event_to_dict",
|
|
222
|
+
"events_to_csv",
|
|
223
|
+
"events_to_dataframe",
|
|
224
|
+
"events_to_dicts",
|
|
225
|
+
"events_to_jsonl",
|
|
226
|
+
"extract_add_version_result",
|
|
227
|
+
"extract_artifact_status_changed_event",
|
|
228
|
+
"extract_comment_result",
|
|
229
|
+
"extract_comment_status_changed_event",
|
|
230
|
+
"extract_events_by_struct",
|
|
231
|
+
"extract_like_event",
|
|
232
|
+
"extract_owner_transferred_event",
|
|
233
|
+
"extract_proposal_executed_event",
|
|
234
|
+
"extract_proposal_expired_event",
|
|
235
|
+
"extract_proposal_finalized_event",
|
|
236
|
+
"extract_proposal_result",
|
|
237
|
+
"extract_protocol_paused_changed_event",
|
|
238
|
+
"extract_publish_result",
|
|
239
|
+
"extract_tree_status_changed_event",
|
|
240
|
+
"extract_unlike_event",
|
|
241
|
+
"extract_vote_cast_events",
|
|
242
|
+
"extract_vote_claimed_event",
|
|
243
|
+
"explain_paperproof_error",
|
|
244
|
+
"format_deployment_update_check",
|
|
245
|
+
"format_deployment_verification",
|
|
246
|
+
"format_paperproof_error_explanation",
|
|
247
|
+
"normalize_pysui_execution_result",
|
|
248
|
+
"parse_move_abort",
|
|
249
|
+
"query_governance_history",
|
|
250
|
+
"query_recent_activity",
|
|
251
|
+
"record_to_dict",
|
|
252
|
+
"records_to_csv",
|
|
253
|
+
"records_to_dataframe",
|
|
254
|
+
"records_to_dicts",
|
|
255
|
+
"records_to_jsonl",
|
|
256
|
+
"robust_execute_plan",
|
|
257
|
+
"run_sync",
|
|
258
|
+
"select_coins_covering",
|
|
259
|
+
"summarize_coins",
|
|
260
|
+
"verify_deployment",
|
|
261
|
+
"vote_records_to_csv",
|
|
262
|
+
"vote_records_to_dataframe",
|
|
263
|
+
"vote_records_to_dicts",
|
|
264
|
+
"vote_records_to_jsonl",
|
|
265
|
+
"with_retries",
|
|
266
|
+
"write_events_csv",
|
|
267
|
+
"write_events_jsonl",
|
|
268
|
+
"write_records_csv",
|
|
269
|
+
"write_records_jsonl",
|
|
270
|
+
]
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
# Copyright (c) 2026 PaperProof Labs
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import re
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
|
|
10
|
+
MODULE_HINTS = (
|
|
11
|
+
"comments",
|
|
12
|
+
"governance_voting",
|
|
13
|
+
"governance",
|
|
14
|
+
"publishing",
|
|
15
|
+
"validation",
|
|
16
|
+
"artifact_types",
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass(frozen=True)
|
|
21
|
+
class MoveAbortInfo:
|
|
22
|
+
package_id: str | None = None
|
|
23
|
+
module: str | None = None
|
|
24
|
+
code: int | None = None
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass(frozen=True)
|
|
28
|
+
class PaperProofErrorExplanation:
|
|
29
|
+
matched: bool
|
|
30
|
+
title: str
|
|
31
|
+
detail: str
|
|
32
|
+
raw: str
|
|
33
|
+
suggestion: str | None = None
|
|
34
|
+
move_abort: MoveAbortInfo | None = None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
_ABORTS: dict[str, dict[int, tuple[str, str, str]]] = {
|
|
38
|
+
"comments": {
|
|
39
|
+
2: (
|
|
40
|
+
"Comments tree is not open",
|
|
41
|
+
"The target comments tree is locked or archived.",
|
|
42
|
+
"Read the tree status and only add comments when it is open.",
|
|
43
|
+
),
|
|
44
|
+
3: (
|
|
45
|
+
"Parent comment not found",
|
|
46
|
+
"The parent comment id does not exist in this tree.",
|
|
47
|
+
"Use root parent id 0 or read the comment node before replying.",
|
|
48
|
+
),
|
|
49
|
+
4: ("Empty on-chain comment", "The on-chain comment content is empty.", "Provide non-empty comment text."),
|
|
50
|
+
5: (
|
|
51
|
+
"On-chain comment too large",
|
|
52
|
+
"The on-chain comment exceeds the tree limit.",
|
|
53
|
+
"Use a blob comment or shorten the content.",
|
|
54
|
+
),
|
|
55
|
+
8: (
|
|
56
|
+
"Not the comments tree owner",
|
|
57
|
+
"The signer is not authorized as tree owner.",
|
|
58
|
+
"Use the current tree owner account or transfer tree ownership first.",
|
|
59
|
+
),
|
|
60
|
+
11: (
|
|
61
|
+
"Comment not found",
|
|
62
|
+
"The requested comment id does not exist in this tree.",
|
|
63
|
+
"Read the comment node or check the tree id/comment id pair.",
|
|
64
|
+
),
|
|
65
|
+
12: (
|
|
66
|
+
"Comment status permission denied",
|
|
67
|
+
"The signer is not authorized for this transition.",
|
|
68
|
+
"Authors can delete their own comments; tree owners can hide/delete according to protocol rules.",
|
|
69
|
+
),
|
|
70
|
+
16: (
|
|
71
|
+
"Insufficient PPRF proof balance for like",
|
|
72
|
+
"The supplied PPRF coin has less than the required proof balance.",
|
|
73
|
+
"Use a PPRF coin with at least 1 PPRF.",
|
|
74
|
+
),
|
|
75
|
+
17: (
|
|
76
|
+
"Already liked",
|
|
77
|
+
"The liker has already liked this artifact.",
|
|
78
|
+
"Call unlike before liking again, or treat the current state as success.",
|
|
79
|
+
),
|
|
80
|
+
18: ("Not liked yet", "The liker has no existing like to remove.", "Check has_liked before calling unlike."),
|
|
81
|
+
20: (
|
|
82
|
+
"Parent comment is not active",
|
|
83
|
+
"Replies are not allowed under hidden or deleted comments.",
|
|
84
|
+
"Reply to an active comment or the root.",
|
|
85
|
+
),
|
|
86
|
+
25: (
|
|
87
|
+
"Root comment is immutable",
|
|
88
|
+
"The root comment cannot be hidden or deleted.",
|
|
89
|
+
"Only update real user comment ids.",
|
|
90
|
+
),
|
|
91
|
+
26: (
|
|
92
|
+
"Deleted comment is final",
|
|
93
|
+
"A deleted comment cannot be restored or changed.",
|
|
94
|
+
"Treat deleted as a terminal state.",
|
|
95
|
+
),
|
|
96
|
+
},
|
|
97
|
+
"governance": {
|
|
98
|
+
3: (
|
|
99
|
+
"Not governance authority",
|
|
100
|
+
"The signer is not the configured governance authority.",
|
|
101
|
+
"Use governance voting flow or the current governance authority account.",
|
|
102
|
+
),
|
|
103
|
+
6: (
|
|
104
|
+
"Invalid registry binding",
|
|
105
|
+
"One or more governance objects are from different registries.",
|
|
106
|
+
"Use canonical objects from the same PaperProof deployment.",
|
|
107
|
+
),
|
|
108
|
+
11: (
|
|
109
|
+
"Insufficient fee payment",
|
|
110
|
+
"The supplied payment coin is below the required fee.",
|
|
111
|
+
"Select a larger SUI coin or split enough SUI before the call.",
|
|
112
|
+
),
|
|
113
|
+
12: (
|
|
114
|
+
"Not upgrade authority",
|
|
115
|
+
"The signer is not the configured upgrade authority.",
|
|
116
|
+
"Use the upgrade authority account or migrate authority through governance.",
|
|
117
|
+
),
|
|
118
|
+
16: (
|
|
119
|
+
"Direct authority disabled",
|
|
120
|
+
"Direct authority mode does not allow this operation.",
|
|
121
|
+
"Use the governance proposal execution path.",
|
|
122
|
+
),
|
|
123
|
+
18: (
|
|
124
|
+
"Governance config already bound",
|
|
125
|
+
"The vault already has a GovernanceConfig binding.",
|
|
126
|
+
"Do not initialize/bind GovernanceConfig twice.",
|
|
127
|
+
),
|
|
128
|
+
},
|
|
129
|
+
"governance_voting": {
|
|
130
|
+
2: (
|
|
131
|
+
"Proposal creation paused",
|
|
132
|
+
"Governance proposal creation is paused.",
|
|
133
|
+
"Wait for governance to unpause proposal creation.",
|
|
134
|
+
),
|
|
135
|
+
5: (
|
|
136
|
+
"Proposal not active",
|
|
137
|
+
"The proposal is not in active voting state.",
|
|
138
|
+
"Read proposal status before voting or finalizing.",
|
|
139
|
+
),
|
|
140
|
+
6: (
|
|
141
|
+
"Already voted",
|
|
142
|
+
"This voter has already voted on the proposal.",
|
|
143
|
+
"Claim locked tokens after finalization instead of voting again.",
|
|
144
|
+
),
|
|
145
|
+
7: (
|
|
146
|
+
"Voting has not ended",
|
|
147
|
+
"The proposal cannot be finalized until its end epoch.",
|
|
148
|
+
"Wait until end_epoch or use early resolve only when outcome is determinable.",
|
|
149
|
+
),
|
|
150
|
+
8: ("Proposal already finalized", "The proposal is no longer active.", "Do not finalize/resolve it again."),
|
|
151
|
+
9: (
|
|
152
|
+
"Proposal not passed",
|
|
153
|
+
"Only passed executable proposals can be executed.",
|
|
154
|
+
"Check proposal status and votes before execution.",
|
|
155
|
+
),
|
|
156
|
+
11: (
|
|
157
|
+
"Proposal already executed",
|
|
158
|
+
"The proposal action has already been consumed.",
|
|
159
|
+
"Do not execute the same proposal twice.",
|
|
160
|
+
),
|
|
161
|
+
13: (
|
|
162
|
+
"Invalid governance vault/config binding",
|
|
163
|
+
"Proposal, config, vault, or executor cap are not bound to the same registry.",
|
|
164
|
+
"Use canonical deployment objects and resolve proposal object id from GovernanceConfig.",
|
|
165
|
+
),
|
|
166
|
+
17: (
|
|
167
|
+
"Another active proposal exists",
|
|
168
|
+
"Only one active proposal is allowed at a time.",
|
|
169
|
+
"Finalize, execute, expire, or wait for the active proposal before creating another.",
|
|
170
|
+
),
|
|
171
|
+
19: (
|
|
172
|
+
"No vote to claim",
|
|
173
|
+
"The signer has no locked vote tokens to claim for this proposal.",
|
|
174
|
+
"Check voter address and proposal id.",
|
|
175
|
+
),
|
|
176
|
+
20: (
|
|
177
|
+
"Voting power below minimum",
|
|
178
|
+
"The supplied PPRF coin is below minimum voting stake.",
|
|
179
|
+
"Use a PPRF coin with at least MIN_VOTE_STAKE.",
|
|
180
|
+
),
|
|
181
|
+
21: (
|
|
182
|
+
"Proposer stake below threshold",
|
|
183
|
+
"The proposer PPRF coin is below the proposer threshold.",
|
|
184
|
+
"Use enough PPRF or lower the threshold through governance.",
|
|
185
|
+
),
|
|
186
|
+
31: (
|
|
187
|
+
"Invalid proposal/config binding",
|
|
188
|
+
"The proposal object is not bound to the supplied GovernanceConfig.",
|
|
189
|
+
"Resolve the proposal object id via get_proposal_object_id.",
|
|
190
|
+
),
|
|
191
|
+
},
|
|
192
|
+
"publishing": {
|
|
193
|
+
1: (
|
|
194
|
+
"Publishing is paused",
|
|
195
|
+
"The root paused flag blocks publish and add-version calls.",
|
|
196
|
+
"Wait until publishing is unpaused.",
|
|
197
|
+
),
|
|
198
|
+
5: ("Invalid artifact type", "The artifact type is not supported.", "Use ARTIFACT_TYPES constants."),
|
|
199
|
+
6: (
|
|
200
|
+
"Artifact type disabled",
|
|
201
|
+
"The selected artifact type is disabled for publishing/versioning.",
|
|
202
|
+
"Choose an enabled type or wait for governance to enable it.",
|
|
203
|
+
),
|
|
204
|
+
8: (
|
|
205
|
+
"Invalid governance vault",
|
|
206
|
+
"The supplied GovernanceVault is not the canonical object bound to root.",
|
|
207
|
+
"Use MAINNET_DEPLOYMENT.objects.governance_vault.",
|
|
208
|
+
),
|
|
209
|
+
9: (
|
|
210
|
+
"Invalid fee manager",
|
|
211
|
+
"The supplied FeeManager is not the canonical object bound to root.",
|
|
212
|
+
"Use MAINNET_DEPLOYMENT.objects.fee_manager.",
|
|
213
|
+
),
|
|
214
|
+
21: (
|
|
215
|
+
"Not series owner",
|
|
216
|
+
"Only the series owner can perform this action.",
|
|
217
|
+
"Use the current owner account or transfer ownership first.",
|
|
218
|
+
),
|
|
219
|
+
23: (
|
|
220
|
+
"Invalid comments tree",
|
|
221
|
+
"The comments tree does not belong to the series.",
|
|
222
|
+
"Use the comments_tree_id emitted when the series was published.",
|
|
223
|
+
),
|
|
224
|
+
25: (
|
|
225
|
+
"Too many versions",
|
|
226
|
+
"The series reached MAX_VERSIONS_PER_SERIES.",
|
|
227
|
+
"Start a new series or stop appending versions.",
|
|
228
|
+
),
|
|
229
|
+
29: (
|
|
230
|
+
"Duplicate metadata key",
|
|
231
|
+
"metadata_extensions contains duplicate keys.",
|
|
232
|
+
"Deduplicate keys before building the transaction.",
|
|
233
|
+
),
|
|
234
|
+
},
|
|
235
|
+
"validation": {
|
|
236
|
+
10: (
|
|
237
|
+
"Empty content hash",
|
|
238
|
+
"content_hash must not be empty.",
|
|
239
|
+
"Provide the content hash for the artifact bytes.",
|
|
240
|
+
),
|
|
241
|
+
11: (
|
|
242
|
+
"Empty Walrus blob id",
|
|
243
|
+
"walrus_blob_id must not be empty.",
|
|
244
|
+
"Upload to Walrus first or use an explicit smoke-test fallback.",
|
|
245
|
+
),
|
|
246
|
+
12: (
|
|
247
|
+
"Empty Walrus blob object id",
|
|
248
|
+
"walrus_blob_object_id must not be empty.",
|
|
249
|
+
"Pass the Walrus blob object id.",
|
|
250
|
+
),
|
|
251
|
+
14: ("Empty title", "The artifact title/project name is empty.", "Provide a non-empty title."),
|
|
252
|
+
17: ("Empty author list", "At least one author is required.", "Provide authors."),
|
|
253
|
+
21: ("Text too long", "A text field exceeds protocol limits.", "Run SDK validation before submitting."),
|
|
254
|
+
23: ("Empty vector item", "A vector field contains an empty item.", "Remove empty authors/keywords/tags."),
|
|
255
|
+
},
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def _raw_text(error: object) -> str:
|
|
260
|
+
if isinstance(error, BaseException):
|
|
261
|
+
return str(error)
|
|
262
|
+
if isinstance(error, str):
|
|
263
|
+
return error
|
|
264
|
+
try:
|
|
265
|
+
return json.dumps(error, ensure_ascii=False, default=str)
|
|
266
|
+
except TypeError:
|
|
267
|
+
return repr(error)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def parse_move_abort(error: object) -> MoveAbortInfo | None:
|
|
271
|
+
raw = _raw_text(error)
|
|
272
|
+
if not raw:
|
|
273
|
+
return None
|
|
274
|
+
package_match = re.search(r"(0x[0-9a-fA-F]{1,64})::[A-Za-z_][A-Za-z0-9_]*::", raw)
|
|
275
|
+
module_match = re.search(r"(?:MoveAbort|move abort).*?([A-Za-z_][A-Za-z0-9_]*)\s*[,):]", raw, re.IGNORECASE)
|
|
276
|
+
module = module_match.group(1) if module_match and module_match.group(1) in MODULE_HINTS else None
|
|
277
|
+
if module is None:
|
|
278
|
+
module = next((hint for hint in MODULE_HINTS if f"::{hint}::" in raw or hint in raw), None)
|
|
279
|
+
code_match = (
|
|
280
|
+
re.search(r"abort(?:ed)?(?: with)?(?: code)?\s*(0x[0-9a-fA-F]+|\d+)", raw, re.IGNORECASE)
|
|
281
|
+
or re.search(r"code[:=]\s*(0x[0-9a-fA-F]+|\d+)", raw, re.IGNORECASE)
|
|
282
|
+
or re.search(r",\s*(\d+)\s*\)", raw)
|
|
283
|
+
)
|
|
284
|
+
code = None
|
|
285
|
+
if code_match:
|
|
286
|
+
text = code_match.group(1)
|
|
287
|
+
code = int(text, 16) if text.lower().startswith("0x") else int(text)
|
|
288
|
+
if not package_match and module is None and code is None:
|
|
289
|
+
return None
|
|
290
|
+
return MoveAbortInfo(
|
|
291
|
+
package_id=package_match.group(1) if package_match else None,
|
|
292
|
+
module=module,
|
|
293
|
+
code=code,
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def explain_paperproof_error(error: object) -> PaperProofErrorExplanation:
|
|
298
|
+
raw = _raw_text(error)
|
|
299
|
+
move_abort = parse_move_abort(error)
|
|
300
|
+
if move_abort and move_abort.module and move_abort.code is not None:
|
|
301
|
+
known = _ABORTS.get(move_abort.module, {}).get(move_abort.code)
|
|
302
|
+
if known:
|
|
303
|
+
title, detail, suggestion = known
|
|
304
|
+
return PaperProofErrorExplanation(True, title, detail, raw, suggestion, move_abort)
|
|
305
|
+
if re.search(
|
|
306
|
+
r"insufficient.*(balance|coin|fund)|not enough.*(balance|coin|fund)|balance.*too low", raw, re.IGNORECASE
|
|
307
|
+
):
|
|
308
|
+
return PaperProofErrorExplanation(
|
|
309
|
+
True,
|
|
310
|
+
"Insufficient coin balance",
|
|
311
|
+
"The signer or selected payment/proof coin does not hold enough balance for this operation.",
|
|
312
|
+
raw,
|
|
313
|
+
"Top up the required SUI/WAL/PPRF balance or select a larger coin before submitting.",
|
|
314
|
+
move_abort,
|
|
315
|
+
)
|
|
316
|
+
if re.search(r"insufficient.*gas|gas", raw, re.IGNORECASE):
|
|
317
|
+
return PaperProofErrorExplanation(
|
|
318
|
+
True,
|
|
319
|
+
"Gas or coin selection problem",
|
|
320
|
+
"The transaction failed while selecting or charging gas/payment coins.",
|
|
321
|
+
raw,
|
|
322
|
+
"Check SUI balance for gas and avoid using the same coin for multiple roles.",
|
|
323
|
+
move_abort,
|
|
324
|
+
)
|
|
325
|
+
if re.search(r"needs to be rebuilt|unavailable for consumption|current version", raw, re.IGNORECASE):
|
|
326
|
+
return PaperProofErrorExplanation(
|
|
327
|
+
True,
|
|
328
|
+
"Transaction needs rebuilding",
|
|
329
|
+
"A shared or owned input object advanced to a newer version before submission.",
|
|
330
|
+
raw,
|
|
331
|
+
"Rebuild the transaction and retry.",
|
|
332
|
+
move_abort,
|
|
333
|
+
)
|
|
334
|
+
return PaperProofErrorExplanation(
|
|
335
|
+
False,
|
|
336
|
+
"Unrecognized PaperProof/Sui error",
|
|
337
|
+
raw or "The SDK could not extract a detailed error message.",
|
|
338
|
+
raw,
|
|
339
|
+
"Inspect the transaction digest, Sui explorer details, and PaperProof object bindings.",
|
|
340
|
+
move_abort,
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def format_paperproof_error_explanation(explanation: PaperProofErrorExplanation) -> str:
|
|
345
|
+
abort = explanation.move_abort
|
|
346
|
+
abort_text = (
|
|
347
|
+
f" module={abort.module or 'unknown'} code={abort.code if abort.code is not None else 'unknown'}"
|
|
348
|
+
if abort
|
|
349
|
+
else ""
|
|
350
|
+
)
|
|
351
|
+
suggestion = f" Suggestion: {explanation.suggestion}" if explanation.suggestion else ""
|
|
352
|
+
return f"{explanation.title}.{abort_text} {explanation.detail}{suggestion}"
|