@interest-protocol/blast-admin-sdk 0.0.0-stage → 0.1.0

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.
@@ -0,0 +1,198 @@
1
+ import { normalizeSharedObjectIdentity } from "@interest-protocol/blast-core/sui";
2
+ import { Transaction } from "@mysten/sui/transactions";
3
+ import { normalizeStructTag, normalizeSuiAddress, normalizeSuiObjectId, } from "@mysten/sui/utils";
4
+ export function normalizeAdminDeployment(deployment) {
5
+ return {
6
+ packageId: normalizeSuiObjectId(deployment.packageId),
7
+ acl: normalizeSharedObjectIdentity("admin.acl", deployment.acl),
8
+ };
9
+ }
10
+ /**
11
+ * `blast_admin::blast_acl` calls. A role is a Move type its consumer package
12
+ * declares (for example `<launchpad>::blast_fun_domain::FeeAdmin`); each
13
+ * product's `roleType` names its own.
14
+ */
15
+ export class AdminCalls {
16
+ deployment;
17
+ constructor(deployment) {
18
+ this.deployment = normalizeAdminDeployment(deployment);
19
+ }
20
+ /** `sign_in<Role>`: this PTB's `AdminWitness<Role>`; the `AdminCap` must hold `role`. */
21
+ signIn(options) {
22
+ const role = normalizeStructTag(options.role);
23
+ return (tx) => tx.moveCall({
24
+ target: this.#target("sign_in"),
25
+ typeArguments: [role],
26
+ arguments: [this.#acl(tx, false), tx.object(options.adminCap)],
27
+ });
28
+ }
29
+ /** `grant_admin`: delivers a new `AdminCap` with no role to `recipient`. */
30
+ grantAdmin(options) {
31
+ const recipient = normalizeSuiAddress(options.recipient);
32
+ return (tx) => {
33
+ tx.moveCall({
34
+ target: this.#target("grant_admin"),
35
+ arguments: [
36
+ this.#acl(tx, true),
37
+ tx.object(options.superAdminCap),
38
+ tx.pure.address(recipient),
39
+ ],
40
+ });
41
+ };
42
+ }
43
+ /** `revoke_admin`: retires a live `AdminCap` and every role it holds. */
44
+ revokeAdmin(options) {
45
+ const adminCapId = normalizeSuiObjectId(options.adminCapId);
46
+ return (tx) => {
47
+ tx.moveCall({
48
+ target: this.#target("revoke_admin"),
49
+ arguments: [
50
+ this.#acl(tx, true),
51
+ tx.object(options.superAdminCap),
52
+ tx.pure.id(adminCapId),
53
+ ],
54
+ });
55
+ };
56
+ }
57
+ /** `grant_role<Role>` to a live administrator. */
58
+ grantRole(options) {
59
+ return this.#roleCall("grant_role", options);
60
+ }
61
+ /** `revoke_role<Role>` from a live administrator. */
62
+ revokeRole(options) {
63
+ return this.#roleCall("revoke_role", options);
64
+ }
65
+ /** `destroy_admin_cap`: deletes the holder's own live or revoked cap. */
66
+ destroyAdminCap(options) {
67
+ return (tx) => {
68
+ tx.moveCall({
69
+ target: this.#target("destroy_admin_cap"),
70
+ arguments: [this.#acl(tx, true), tx.object(options.adminCap)],
71
+ });
72
+ };
73
+ }
74
+ /**
75
+ * `begin_super_admin_transfer`: nominates `recipient`, who may accept once
76
+ * the ACL's seven-day delay passes; it replaces a pending nomination.
77
+ */
78
+ beginSuperAdminTransfer(options) {
79
+ const recipient = normalizeSuiAddress(options.recipient);
80
+ return (tx) => {
81
+ tx.moveCall({
82
+ target: this.#target("begin_super_admin_transfer"),
83
+ arguments: [
84
+ this.#acl(tx, true),
85
+ tx.object(options.superAdminCap),
86
+ tx.pure.address(recipient),
87
+ tx.object.clock(),
88
+ ],
89
+ });
90
+ };
91
+ }
92
+ cancelSuperAdminTransfer(options) {
93
+ return (tx) => {
94
+ tx.moveCall({
95
+ target: this.#target("cancel_super_admin_transfer"),
96
+ arguments: [this.#acl(tx, true), tx.object(options.superAdminCap)],
97
+ });
98
+ };
99
+ }
100
+ /** `accept_super_admin_transfer`: the sender must be the ready nominee. */
101
+ acceptSuperAdminTransfer() {
102
+ return (tx) => {
103
+ tx.moveCall({
104
+ target: this.#target("accept_super_admin_transfer"),
105
+ arguments: [this.#acl(tx, true), tx.object.clock()],
106
+ });
107
+ };
108
+ }
109
+ /** `destroy_retired_super_admin_cap`: deletes a root an accepted transfer replaced. */
110
+ destroyRetiredSuperAdminCap(options) {
111
+ return (tx) => {
112
+ tx.moveCall({
113
+ target: this.#target("destroy_retired_super_admin_cap"),
114
+ arguments: [this.#acl(tx, false), tx.object(options.superAdminCap)],
115
+ });
116
+ };
117
+ }
118
+ #roleCall(functionName, options) {
119
+ const role = normalizeStructTag(options.role);
120
+ const adminCapId = normalizeSuiObjectId(options.adminCapId);
121
+ return (tx) => {
122
+ tx.moveCall({
123
+ target: this.#target(functionName),
124
+ typeArguments: [role],
125
+ arguments: [
126
+ this.#acl(tx, true),
127
+ tx.object(options.superAdminCap),
128
+ tx.pure.id(adminCapId),
129
+ ],
130
+ });
131
+ };
132
+ }
133
+ #target(functionName) {
134
+ return `${this.deployment.packageId}::blast_acl::${functionName}`;
135
+ }
136
+ #acl(tx, mutable) {
137
+ return tx.sharedObjectRef({ ...this.deployment.acl, mutable });
138
+ }
139
+ }
140
+ /** One-call PTBs for the ACL's root and administrators. */
141
+ export class AdminTransactions {
142
+ call;
143
+ constructor(deployment) {
144
+ this.call = new AdminCalls(deployment);
145
+ }
146
+ grantAdmin(options) {
147
+ return single(this.call.grantAdmin({
148
+ superAdminCap: options.superAdminCapId,
149
+ recipient: options.recipient,
150
+ }));
151
+ }
152
+ revokeAdmin(options) {
153
+ return single(this.call.revokeAdmin({
154
+ superAdminCap: options.superAdminCapId,
155
+ adminCapId: options.adminCapId,
156
+ }));
157
+ }
158
+ grantRole(options) {
159
+ return single(this.call.grantRole({
160
+ ...options,
161
+ superAdminCap: options.superAdminCapId,
162
+ }));
163
+ }
164
+ revokeRole(options) {
165
+ return single(this.call.revokeRole({
166
+ ...options,
167
+ superAdminCap: options.superAdminCapId,
168
+ }));
169
+ }
170
+ destroyAdminCap(options) {
171
+ return single(this.call.destroyAdminCap({ adminCap: options.adminCapId }));
172
+ }
173
+ beginSuperAdminTransfer(options) {
174
+ return single(this.call.beginSuperAdminTransfer({
175
+ superAdminCap: options.superAdminCapId,
176
+ recipient: options.recipient,
177
+ }));
178
+ }
179
+ cancelSuperAdminTransfer(options) {
180
+ return single(this.call.cancelSuperAdminTransfer({
181
+ superAdminCap: options.superAdminCapId,
182
+ }));
183
+ }
184
+ acceptSuperAdminTransfer() {
185
+ return single(this.call.acceptSuperAdminTransfer());
186
+ }
187
+ destroyRetiredSuperAdminCap(options) {
188
+ return single(this.call.destroyRetiredSuperAdminCap({
189
+ superAdminCap: options.superAdminCapId,
190
+ }));
191
+ }
192
+ }
193
+ function single(call) {
194
+ const tx = new Transaction();
195
+ tx.add(call);
196
+ return tx;
197
+ }
198
+ //# sourceMappingURL=transactions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transactions.js","sourceRoot":"","sources":["../src/transactions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,mCAAmC,CAAC;AAKlF,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAQ3B,MAAM,UAAU,wBAAwB,CACtC,UAA2B;IAE3B,OAAO;QACL,SAAS,EAAE,oBAAoB,CAAC,UAAU,CAAC,SAAS,CAAC;QACrD,GAAG,EAAE,6BAA6B,CAAC,WAAW,EAAE,UAAU,CAAC,GAAG,CAAC;KAChE,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,UAAU;IACZ,UAAU,CAAkB;IAErC,YAAY,UAA2B;QACrC,IAAI,CAAC,UAAU,GAAG,wBAAwB,CAAC,UAAU,CAAC,CAAC;IACzD,CAAC;IAED,yFAAyF;IACzF,MAAM,CAAC,OAA2D;QAChE,MAAM,IAAI,GAAG,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9C,OAAO,CAAC,EAAe,EAA6B,EAAE,CACpD,EAAE,CAAC,QAAQ,CAAC;YACV,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;YAC/B,aAAa,EAAE,CAAC,IAAI,CAAC;YACrB,SAAS,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;SAC/D,CAAC,CAAC;IACP,CAAC;IAED,4EAA4E;IAC5E,UAAU,CAAC,OAGV;QACC,MAAM,SAAS,GAAG,mBAAmB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACzD,OAAO,CAAC,EAAe,EAAQ,EAAE;YAC/B,EAAE,CAAC,QAAQ,CAAC;gBACV,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC;gBACnC,SAAS,EAAE;oBACT,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC;oBACnB,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC;oBAChC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;iBAC3B;aACF,CAAC,CAAC;QACL,CAAC,CAAC;IACJ,CAAC;IAED,yEAAyE;IACzE,WAAW,CAAC,OAGX;QACC,MAAM,UAAU,GAAG,oBAAoB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAC5D,OAAO,CAAC,EAAe,EAAQ,EAAE;YAC/B,EAAE,CAAC,QAAQ,CAAC;gBACV,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC;gBACpC,SAAS,EAAE;oBACT,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC;oBACnB,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC;oBAChC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC;iBACvB;aACF,CAAC,CAAC;QACL,CAAC,CAAC;IACJ,CAAC;IAED,kDAAkD;IAClD,SAAS,CAAC,OAIT;QACC,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;IAED,qDAAqD;IACrD,UAAU,CAAC,OAIV;QACC,OAAO,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IAChD,CAAC;IAED,yEAAyE;IACzE,eAAe,CAAC,OAA6C;QAC3D,OAAO,CAAC,EAAe,EAAQ,EAAE;YAC/B,EAAE,CAAC,QAAQ,CAAC;gBACV,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC;gBACzC,SAAS,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;aAC9D,CAAC,CAAC;QACL,CAAC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,uBAAuB,CAAC,OAGvB;QACC,MAAM,SAAS,GAAG,mBAAmB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACzD,OAAO,CAAC,EAAe,EAAQ,EAAE;YAC/B,EAAE,CAAC,QAAQ,CAAC;gBACV,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,4BAA4B,CAAC;gBAClD,SAAS,EAAE;oBACT,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC;oBACnB,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC;oBAChC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;oBAC1B,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE;iBAClB;aACF,CAAC,CAAC;QACL,CAAC,CAAC;IACJ,CAAC;IAED,wBAAwB,CAAC,OAAkD;QACzE,OAAO,CAAC,EAAe,EAAQ,EAAE;YAC/B,EAAE,CAAC,QAAQ,CAAC;gBACV,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,6BAA6B,CAAC;gBACnD,SAAS,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;aACnE,CAAC,CAAC;QACL,CAAC,CAAC;IACJ,CAAC;IAED,2EAA2E;IAC3E,wBAAwB;QACtB,OAAO,CAAC,EAAe,EAAQ,EAAE;YAC/B,EAAE,CAAC,QAAQ,CAAC;gBACV,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,6BAA6B,CAAC;gBACnD,SAAS,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;aACpD,CAAC,CAAC;QACL,CAAC,CAAC;IACJ,CAAC;IAED,uFAAuF;IACvF,2BAA2B,CAAC,OAE3B;QACC,OAAO,CAAC,EAAe,EAAQ,EAAE;YAC/B,EAAE,CAAC,QAAQ,CAAC;gBACV,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,iCAAiC,CAAC;gBACvD,SAAS,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;aACpE,CAAC,CAAC;QACL,CAAC,CAAC;IACJ,CAAC;IAED,SAAS,CACP,YAA0C,EAC1C,OAIC;QAED,MAAM,IAAI,GAAG,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9C,MAAM,UAAU,GAAG,oBAAoB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAC5D,OAAO,CAAC,EAAe,EAAQ,EAAE;YAC/B,EAAE,CAAC,QAAQ,CAAC;gBACV,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC;gBAClC,aAAa,EAAE,CAAC,IAAI,CAAC;gBACrB,SAAS,EAAE;oBACT,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC;oBACnB,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC;oBAChC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC;iBACvB;aACF,CAAC,CAAC;QACL,CAAC,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,YAAoB;QAC1B,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,gBAAgB,YAAY,EAAE,CAAC;IACpE,CAAC;IAED,IAAI,CAAC,EAAe,EAAE,OAAgB;QACpC,OAAO,EAAE,CAAC,eAAe,CAAC,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;IACjE,CAAC;CACF;AAED,2DAA2D;AAC3D,MAAM,OAAO,iBAAiB;IACnB,IAAI,CAAa;IAE1B,YAAY,UAA2B;QACrC,IAAI,CAAC,IAAI,GAAG,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC;IACzC,CAAC;IAED,UAAU,CAAC,OAAuD;QAChE,OAAO,MAAM,CACX,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC;YACnB,aAAa,EAAE,OAAO,CAAC,eAAe;YACtC,SAAS,EAAE,OAAO,CAAC,SAAS;SAC7B,CAAC,CACH,CAAC;IACJ,CAAC;IAED,WAAW,CAAC,OAAwD;QAClE,OAAO,MAAM,CACX,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC;YACpB,aAAa,EAAE,OAAO,CAAC,eAAe;YACtC,UAAU,EAAE,OAAO,CAAC,UAAU;SAC/B,CAAC,CACH,CAAC;IACJ,CAAC;IAED,SAAS,CAAC,OAIT;QACC,OAAO,MAAM,CACX,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;YAClB,GAAG,OAAO;YACV,aAAa,EAAE,OAAO,CAAC,eAAe;SACvC,CAAC,CACH,CAAC;IACJ,CAAC;IAED,UAAU,CAAC,OAIV;QACC,OAAO,MAAM,CACX,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC;YACnB,GAAG,OAAO;YACV,aAAa,EAAE,OAAO,CAAC,eAAe;SACvC,CAAC,CACH,CAAC;IACJ,CAAC;IAED,eAAe,CAAC,OAA+B;QAC7C,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IAC7E,CAAC;IAED,uBAAuB,CAAC,OAGvB;QACC,OAAO,MAAM,CACX,IAAI,CAAC,IAAI,CAAC,uBAAuB,CAAC;YAChC,aAAa,EAAE,OAAO,CAAC,eAAe;YACtC,SAAS,EAAE,OAAO,CAAC,SAAS;SAC7B,CAAC,CACH,CAAC;IACJ,CAAC;IAED,wBAAwB,CAAC,OAAoC;QAC3D,OAAO,MAAM,CACX,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAAC;YACjC,aAAa,EAAE,OAAO,CAAC,eAAe;SACvC,CAAC,CACH,CAAC;IACJ,CAAC;IAED,wBAAwB;QACtB,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,wBAAwB,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,2BAA2B,CAAC,OAAoC;QAC9D,OAAO,MAAM,CACX,IAAI,CAAC,IAAI,CAAC,2BAA2B,CAAC;YACpC,aAAa,EAAE,OAAO,CAAC,eAAe;SACvC,CAAC,CACH,CAAC;IACJ,CAAC;CACF;AAED,SAAS,MAAM,CAAC,IAA+B;IAC7C,MAAM,EAAE,GAAG,IAAI,WAAW,EAAE,CAAC;IAC7B,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACb,OAAO,EAAE,CAAC;AACZ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,57 @@
1
1
  {
2
2
  "name": "@interest-protocol/blast-admin-sdk",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Blast admin SDK",
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/interest-protocol/blast-v2-sdk.git",
9
+ "directory": "packages/admin"
10
+ },
11
+ "sideEffects": false,
12
+ "files": [
13
+ "dist",
14
+ "src"
15
+ ],
16
+ "exports": {
17
+ "./events": {
18
+ "types": "./dist/events.d.ts",
19
+ "default": "./dist/events.js"
20
+ },
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "default": "./dist/index.js"
24
+ },
25
+ "./reducer": {
26
+ "types": "./dist/reducer.d.ts",
27
+ "default": "./dist/reducer.js"
28
+ },
29
+ "./state": {
30
+ "types": "./dist/state.d.ts",
31
+ "default": "./dist/state.js"
32
+ },
33
+ "./transactions": {
34
+ "types": "./dist/transactions.d.ts",
35
+ "default": "./dist/transactions.js"
36
+ },
37
+ "./package.json": "./package.json"
38
+ },
39
+ "engines": {
40
+ "node": ">=22"
41
+ },
42
+ "scripts": {
43
+ "build": "node --eval \"fs.rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.json",
44
+ "typecheck": "tsc -p tsconfig.json --noEmit",
45
+ "check:package": "publint --strict && attw --pack . --profile esm-only",
46
+ "prepack": "npm run build"
47
+ },
48
+ "publishConfig": {
49
+ "access": "public"
50
+ },
51
+ "dependencies": {
52
+ "@interest-protocol/blast-core": "0.1.0"
53
+ },
54
+ "peerDependencies": {
55
+ "@mysten/sui": "^2.26.2"
56
+ }
57
+ }
package/src/events.ts ADDED
@@ -0,0 +1,103 @@
1
+ import {
2
+ addressBcs,
3
+ moveTypeNameBcs,
4
+ suiObjectIdBcs,
5
+ u64Bcs,
6
+ } from "@interest-protocol/blast-core/bcs";
7
+ import type { SuiEventPosition } from "@interest-protocol/blast-core/events";
8
+ import {
9
+ normalizeSuiEventPosition,
10
+ suiEventId,
11
+ } from "@interest-protocol/blast-core/events";
12
+ import { bcs } from "@mysten/sui/bcs";
13
+ import type { SuiClientTypes } from "@mysten/sui/client";
14
+ import { normalizeSuiAddress, parseStructTag } from "@mysten/sui/utils";
15
+
16
+ const roles = bcs.vector(moveTypeNameBcs);
17
+ const transfer = { recipient: addressBcs, execute_after_ms: u64Bcs };
18
+
19
+ /**
20
+ * The `blast_admin::blast_admin_events` the ACL emits, in Move field order.
21
+ * The generic upgrade-custody and operational-version events belong to
22
+ * package upgrades, which the SDK leaves to publish tooling.
23
+ */
24
+ export const aclEventBcs = {
25
+ AdminGranted: bcs.struct("AdminGranted", {
26
+ admin_cap_id: suiObjectIdBcs,
27
+ recipient: addressBcs,
28
+ }),
29
+ AdminRevoked: bcs.struct("AdminRevoked", {
30
+ admin_cap_id: suiObjectIdBcs,
31
+ roles,
32
+ }),
33
+ AdminRoleGranted: bcs.struct("AdminRoleGranted", {
34
+ admin_cap_id: suiObjectIdBcs,
35
+ role: moveTypeNameBcs,
36
+ }),
37
+ AdminRoleRevoked: bcs.struct("AdminRoleRevoked", {
38
+ admin_cap_id: suiObjectIdBcs,
39
+ role: moveTypeNameBcs,
40
+ }),
41
+ AdminDestroyed: bcs.struct("AdminDestroyed", {
42
+ admin_cap_id: suiObjectIdBcs,
43
+ roles,
44
+ was_active: bcs.bool(),
45
+ }),
46
+ SuperAdminTransferStarted: bcs.struct("SuperAdminTransferStarted", transfer),
47
+ SuperAdminTransferCancelled: bcs.struct(
48
+ "SuperAdminTransferCancelled",
49
+ transfer,
50
+ ),
51
+ SuperAdminTransferred: bcs.struct("SuperAdminTransferred", {
52
+ previous_super_admin_cap_id: suiObjectIdBcs,
53
+ new_super_admin_cap_id: suiObjectIdBcs,
54
+ recipient: addressBcs,
55
+ }),
56
+ SuperAdminCapDestroyed: bcs.struct("SuperAdminCapDestroyed", {
57
+ super_admin_cap_id: suiObjectIdBcs,
58
+ }),
59
+ };
60
+
61
+ export type AclEventKind = keyof typeof aclEventBcs;
62
+
63
+ export type AclEventPayloads = {
64
+ [Kind in AclEventKind]: ReturnType<(typeof aclEventBcs)[Kind]["parse"]>;
65
+ };
66
+
67
+ export type DecodedAclEvent = {
68
+ [Kind in AclEventKind]: {
69
+ source: "admin";
70
+ kind: Kind;
71
+ payload: AclEventPayloads[Kind];
72
+ sender: string;
73
+ position: SuiEventPosition;
74
+ };
75
+ }[AclEventKind];
76
+
77
+ /** Decodes one `<adminPackageId>::blast_admin_events::<Kind>` ACL event. */
78
+ export function decodeAclEvent(
79
+ event: SuiClientTypes.EventEntry,
80
+ adminPackageId: string,
81
+ ): DecodedAclEvent {
82
+ const tag = parseStructTag(event.eventType);
83
+ if (
84
+ tag.address !== normalizeSuiAddress(adminPackageId) ||
85
+ tag.module !== "blast_admin_events" ||
86
+ tag.typeParams.length > 0 ||
87
+ !Object.hasOwn(aclEventBcs, tag.name)
88
+ ) {
89
+ throw new TypeError(`unexpected ACL event type ${event.eventType}`);
90
+ }
91
+ const kind = tag.name as AclEventKind;
92
+ return {
93
+ source: "admin",
94
+ kind,
95
+ payload: aclEventBcs[kind].parse(event.bcs),
96
+ sender: normalizeSuiAddress(event.sender),
97
+ position: normalizeSuiEventPosition(event),
98
+ } as DecodedAclEvent;
99
+ }
100
+
101
+ export function aclEventId(event: DecodedAclEvent): string {
102
+ return suiEventId(event.position);
103
+ }
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from "./events.ts";
2
+ export * from "./reducer.ts";
3
+ export * from "./state.ts";
4
+ export * from "./transactions.ts";
package/src/reducer.ts ADDED
@@ -0,0 +1,97 @@
1
+ import type { AclEventKind, DecodedAclEvent } from "./events.ts";
2
+ import { aclEventBcs, aclEventId } from "./events.ts";
3
+ import type { PendingSuperAdmin } from "./state.ts";
4
+
5
+ /**
6
+ * The ACL rebuilt from its events. Its `init` emits nothing, so
7
+ * `superAdminCapId` stays null until the first accepted transfer; the publish
8
+ * effects name the first root. `admins` matches `AclState.admins` once every
9
+ * event is applied.
10
+ */
11
+ export type AclProjection = {
12
+ appliedEventIds: Readonly<Record<string, true>>;
13
+ eventCounts: Readonly<Record<AclEventKind, number>>;
14
+ superAdminCapId: string | null;
15
+ admins: Readonly<Record<string, readonly string[]>>;
16
+ pendingSuperAdmin: PendingSuperAdmin | null;
17
+ };
18
+
19
+ export function createAclProjection(): AclProjection {
20
+ return {
21
+ appliedEventIds: {},
22
+ eventCounts: Object.fromEntries(
23
+ Object.keys(aclEventBcs).map((kind) => [kind, 0]),
24
+ ) as Record<AclEventKind, number>,
25
+ superAdminCapId: null,
26
+ admins: {},
27
+ pendingSuperAdmin: null,
28
+ };
29
+ }
30
+
31
+ /** Applies one event once; replaying an applied event returns `state` unchanged. */
32
+ export function reduceAclEvent(
33
+ state: AclProjection,
34
+ event: DecodedAclEvent,
35
+ ): AclProjection {
36
+ const eventId = aclEventId(event);
37
+ if (state.appliedEventIds[eventId]) return state;
38
+ const next: AclProjection = {
39
+ ...state,
40
+ appliedEventIds: { ...state.appliedEventIds, [eventId]: true },
41
+ eventCounts: {
42
+ ...state.eventCounts,
43
+ [event.kind]: state.eventCounts[event.kind] + 1,
44
+ },
45
+ };
46
+ switch (event.kind) {
47
+ case "AdminGranted":
48
+ return withRoles(next, event.payload.admin_cap_id, []);
49
+ case "AdminRevoked":
50
+ case "AdminDestroyed":
51
+ return withRoles(next, event.payload.admin_cap_id, null);
52
+ case "AdminRoleGranted": {
53
+ const { admin_cap_id, role } = event.payload;
54
+ const roles = next.admins[admin_cap_id] ?? [];
55
+ return withRoles(next, admin_cap_id, [...roles, role]);
56
+ }
57
+ case "AdminRoleRevoked": {
58
+ const { admin_cap_id, role } = event.payload;
59
+ const roles = next.admins[admin_cap_id] ?? [];
60
+ return withRoles(
61
+ next,
62
+ admin_cap_id,
63
+ roles.filter((held) => held !== role),
64
+ );
65
+ }
66
+ case "SuperAdminTransferStarted":
67
+ return {
68
+ ...next,
69
+ pendingSuperAdmin: {
70
+ recipient: event.payload.recipient,
71
+ executeAfterMs: event.payload.execute_after_ms,
72
+ },
73
+ };
74
+ case "SuperAdminTransferCancelled":
75
+ return { ...next, pendingSuperAdmin: null };
76
+ case "SuperAdminTransferred":
77
+ return {
78
+ ...next,
79
+ superAdminCapId: event.payload.new_super_admin_cap_id,
80
+ pendingSuperAdmin: null,
81
+ };
82
+ case "SuperAdminCapDestroyed":
83
+ return next;
84
+ }
85
+ }
86
+
87
+ function withRoles(
88
+ state: AclProjection,
89
+ adminCapId: string,
90
+ roles: readonly string[] | null,
91
+ ): AclProjection {
92
+ const { [adminCapId]: _, ...admins } = state.admins;
93
+ return {
94
+ ...state,
95
+ admins: roles === null ? admins : { ...admins, [adminCapId]: roles },
96
+ };
97
+ }
package/src/state.ts ADDED
@@ -0,0 +1,102 @@
1
+ import {
2
+ addressBcs,
3
+ moveTypeNameBcs,
4
+ suiObjectIdBcs,
5
+ suiUidBcs,
6
+ } from "@interest-protocol/blast-core/bcs";
7
+ import { normalizePositiveU64 } from "@interest-protocol/blast-core/integers";
8
+ import type { SharedObjectIdentity } from "@interest-protocol/blast-core/sui";
9
+ import { timelockedBcs } from "@interest-protocol/blast-core/timelock";
10
+ import { bcs } from "@mysten/sui/bcs";
11
+ import type { ClientWithCoreApi } from "@mysten/sui/client";
12
+ import { normalizeSuiObjectId, parseStructTag } from "@mysten/sui/utils";
13
+
14
+ /** BCS layout of `blast_admin::blast_acl::ACL`. */
15
+ export const aclBcs = bcs.struct("ACL", {
16
+ id: suiUidBcs,
17
+ super_admin_cap_id: suiObjectIdBcs,
18
+ admins: bcs.vector(
19
+ bcs.struct("Entry", {
20
+ key: suiObjectIdBcs,
21
+ value: bcs.vector(moveTypeNameBcs),
22
+ }),
23
+ ),
24
+ pending_super_admin: timelockedBcs(bcs.option(addressBcs)),
25
+ });
26
+
27
+ /** A nominated super admin, who may accept from `executeAfterMs`. */
28
+ export type PendingSuperAdmin = { recipient: string; executeAfterMs: bigint };
29
+
30
+ export type AclState = SharedObjectIdentity & {
31
+ /** The one live `SuperAdminCap`. */
32
+ superAdminCapId: string;
33
+ /** Every live `AdminCap` and the role types it holds. */
34
+ admins: Readonly<Record<string, readonly string[]>>;
35
+ pendingSuperAdmin: PendingSuperAdmin | null;
36
+ };
37
+
38
+ export type AclObject = SharedObjectIdentity & {
39
+ type: string;
40
+ content: Uint8Array;
41
+ };
42
+
43
+ export function decodeAclObject(
44
+ object: AclObject,
45
+ adminPackageId: string,
46
+ ): AclState {
47
+ const tag = parseStructTag(object.type);
48
+ if (
49
+ tag.address !== normalizeSuiObjectId(adminPackageId) ||
50
+ tag.module !== "blast_acl" ||
51
+ tag.name !== "ACL"
52
+ ) {
53
+ throw new TypeError(`object ${object.objectId} is not the Blast ACL`);
54
+ }
55
+ const parsed = aclBcs.parse(object.content);
56
+ const objectId = normalizeSuiObjectId(object.objectId);
57
+ if (normalizeSuiObjectId(parsed.id.id.bytes) !== objectId) {
58
+ throw new TypeError(`ACL ${object.objectId} has a mismatched UID`);
59
+ }
60
+ const nominee = parsed.pending_super_admin.after;
61
+ return {
62
+ objectId,
63
+ initialSharedVersion: normalizePositiveU64(
64
+ "initialSharedVersion",
65
+ object.initialSharedVersion,
66
+ ),
67
+ superAdminCapId: parsed.super_admin_cap_id,
68
+ admins: Object.fromEntries(
69
+ parsed.admins.map(({ key, value }) => [key, value]),
70
+ ),
71
+ pendingSuperAdmin:
72
+ nominee == null
73
+ ? null
74
+ : {
75
+ recipient: nominee,
76
+ executeAfterMs: parsed.pending_super_admin.atMs,
77
+ },
78
+ };
79
+ }
80
+
81
+ export async function getAcl(
82
+ client: ClientWithCoreApi,
83
+ objectId: string,
84
+ adminPackageId: string,
85
+ ): Promise<AclState> {
86
+ const { object } = await client.core.getObject({
87
+ objectId,
88
+ include: { content: true },
89
+ });
90
+ if (object.owner.$kind !== "Shared") {
91
+ throw new TypeError(`ACL ${object.objectId} is not a shared object`);
92
+ }
93
+ return decodeAclObject(
94
+ {
95
+ objectId: object.objectId,
96
+ initialSharedVersion: object.owner.Shared.initialSharedVersion,
97
+ type: object.type,
98
+ content: object.content,
99
+ },
100
+ adminPackageId,
101
+ );
102
+ }