@interest-protocol/blast-partners-sdk 0.0.0-stage → 0.2.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.
- package/README.md +8 -2
- package/dist/events.d.ts +89 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +105 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/reducer.d.ts +39 -0
- package/dist/reducer.d.ts.map +1 -0
- package/dist/reducer.js +105 -0
- package/dist/reducer.js.map +1 -0
- package/dist/state.d.ts +127 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +100 -0
- package/dist/state.js.map +1 -0
- package/dist/transactions.d.ts +129 -0
- package/dist/transactions.d.ts.map +1 -0
- package/dist/transactions.js +214 -0
- package/dist/transactions.js.map +1 -0
- package/package.json +56 -4
- package/src/events.ts +160 -0
- package/src/index.ts +4 -0
- package/src/reducer.ts +162 -0
- package/src/state.ts +166 -0
- package/src/transactions.ts +327 -0
package/src/reducer.ts
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { U64_MAX } from "@interest-protocol/blast-core/integers";
|
|
2
|
+
import type {
|
|
3
|
+
DecodedPartnerDelayedEvent,
|
|
4
|
+
DecodedPartnerEvent,
|
|
5
|
+
PartnerEventKind,
|
|
6
|
+
} from "./events.ts";
|
|
7
|
+
import { partnerEventBcs, partnerEventId } from "./events.ts";
|
|
8
|
+
|
|
9
|
+
/** A proposed share or cap: it applies only when someone applies it, at or after `readyAtMs`. */
|
|
10
|
+
export type PartnerProposal<T> = { value: T; readyAtMs: bigint };
|
|
11
|
+
|
|
12
|
+
export type PartnerProjection = {
|
|
13
|
+
partnerId: string;
|
|
14
|
+
/** Null until the partner's `PartnerUpdated`. */
|
|
15
|
+
recipient: string | null;
|
|
16
|
+
/** The applied share in basis points; null until its `DelayedCreated`. */
|
|
17
|
+
shareBps: bigint | null;
|
|
18
|
+
/** The applied managing cap; null until its `DelayedCreated`. */
|
|
19
|
+
capId: string | null;
|
|
20
|
+
pendingShare: PartnerProposal<bigint> | null;
|
|
21
|
+
pendingCap: PartnerProposal<string> | null;
|
|
22
|
+
/** Everything sent to the partner, by coin type. */
|
|
23
|
+
paid: Readonly<Record<string, bigint>>;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Partners rebuilt from their events and their `blast_admin::delayed` events
|
|
28
|
+
* (`decodePartnerDelayedEvent`); terms match `PartnerState` once replayed.
|
|
29
|
+
*/
|
|
30
|
+
export type PartnersEventProjection = {
|
|
31
|
+
appliedEventIds: Readonly<Record<string, true>>;
|
|
32
|
+
/** Counts `blast_partners` events only. */
|
|
33
|
+
eventCounts: Readonly<Record<PartnerEventKind, number>>;
|
|
34
|
+
partners: Readonly<Record<string, PartnerProjection>>;
|
|
35
|
+
/**
|
|
36
|
+
* Each `PartnerList` by parent (the product configuration's ID): every
|
|
37
|
+
* partner it named and the millisecond its acceptance ends (`U64_MAX`
|
|
38
|
+
* while accepted without end). A destroyed list is removed.
|
|
39
|
+
*/
|
|
40
|
+
lists: Readonly<Record<string, Readonly<Record<string, bigint>>>>;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export function createPartnersEventProjection(): PartnersEventProjection {
|
|
44
|
+
return {
|
|
45
|
+
appliedEventIds: {},
|
|
46
|
+
eventCounts: Object.fromEntries(
|
|
47
|
+
Object.keys(partnerEventBcs).map((kind) => [kind, 0]),
|
|
48
|
+
) as Record<PartnerEventKind, number>,
|
|
49
|
+
partners: {},
|
|
50
|
+
lists: {},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Applies one event once; replaying an applied event returns `state` unchanged. */
|
|
55
|
+
export function reducePartnerEvent(
|
|
56
|
+
state: PartnersEventProjection,
|
|
57
|
+
event: DecodedPartnerEvent | DecodedPartnerDelayedEvent,
|
|
58
|
+
): PartnersEventProjection {
|
|
59
|
+
const eventId = partnerEventId(event);
|
|
60
|
+
if (state.appliedEventIds[eventId]) return state;
|
|
61
|
+
const applied = { ...state.appliedEventIds, [eventId]: true as const };
|
|
62
|
+
if (event.source === "delayed") {
|
|
63
|
+
const partnerId = event.payload.parent;
|
|
64
|
+
return withPartner(
|
|
65
|
+
{ ...state, appliedEventIds: applied },
|
|
66
|
+
reduceTerms(state.partners[partnerId] ?? empty(partnerId), event),
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
const next: PartnersEventProjection = {
|
|
70
|
+
...state,
|
|
71
|
+
appliedEventIds: applied,
|
|
72
|
+
eventCounts: {
|
|
73
|
+
...state.eventCounts,
|
|
74
|
+
[event.kind]: state.eventCounts[event.kind] + 1,
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
if (event.kind === "PartnerListDestroyed") {
|
|
78
|
+
const { [event.payload.parent]: _, ...lists } = state.lists;
|
|
79
|
+
return { ...next, lists };
|
|
80
|
+
}
|
|
81
|
+
if (event.kind === "PartnerAdded" || event.kind === "PartnerRemoved") {
|
|
82
|
+
const { parent, partner_id } = event.payload;
|
|
83
|
+
const acceptanceEndsAtMs =
|
|
84
|
+
event.kind === "PartnerAdded"
|
|
85
|
+
? U64_MAX
|
|
86
|
+
: event.payload.acceptance_ends_at_ms;
|
|
87
|
+
return {
|
|
88
|
+
...next,
|
|
89
|
+
lists: {
|
|
90
|
+
...state.lists,
|
|
91
|
+
[parent]: { ...state.lists[parent], [partner_id]: acceptanceEndsAtMs },
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const partnerId = event.payload.partner_id;
|
|
96
|
+
const current = state.partners[partnerId];
|
|
97
|
+
if (event.kind === "PartnerUpdated")
|
|
98
|
+
return withPartner(next, {
|
|
99
|
+
...(current ?? empty(partnerId)),
|
|
100
|
+
recipient: event.payload.recipient,
|
|
101
|
+
});
|
|
102
|
+
// A partner is registered before it can be paid.
|
|
103
|
+
if (!current) return next;
|
|
104
|
+
const coinType = event.coinType;
|
|
105
|
+
return withPartner(next, {
|
|
106
|
+
...current,
|
|
107
|
+
paid: {
|
|
108
|
+
...current.paid,
|
|
109
|
+
[coinType]: (current.paid[coinType] ?? 0n) + event.payload.amount,
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Applied and proposed terms; readiness alone changes nothing. */
|
|
115
|
+
function reduceTerms(
|
|
116
|
+
partner: PartnerProjection,
|
|
117
|
+
event: DecodedPartnerDelayedEvent,
|
|
118
|
+
): PartnerProjection {
|
|
119
|
+
const [applied, pending] =
|
|
120
|
+
event.name === "Share"
|
|
121
|
+
? (["shareBps", "pendingShare"] as const)
|
|
122
|
+
: (["capId", "pendingCap"] as const);
|
|
123
|
+
switch (event.kind) {
|
|
124
|
+
case "DelayedCreated":
|
|
125
|
+
case "DelayedApplied":
|
|
126
|
+
return { ...partner, [applied]: event.payload.value, [pending]: null };
|
|
127
|
+
case "DelayedScheduled":
|
|
128
|
+
return {
|
|
129
|
+
...partner,
|
|
130
|
+
[pending]: {
|
|
131
|
+
value: event.payload.value,
|
|
132
|
+
readyAtMs: event.payload.ready_at_ms,
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
case "DelayedCancelled":
|
|
136
|
+
return { ...partner, [pending]: null };
|
|
137
|
+
default:
|
|
138
|
+
return partner;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function empty(partnerId: string): PartnerProjection {
|
|
143
|
+
return {
|
|
144
|
+
partnerId,
|
|
145
|
+
recipient: null,
|
|
146
|
+
shareBps: null,
|
|
147
|
+
capId: null,
|
|
148
|
+
pendingShare: null,
|
|
149
|
+
pendingCap: null,
|
|
150
|
+
paid: {},
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function withPartner(
|
|
155
|
+
state: PartnersEventProjection,
|
|
156
|
+
partner: PartnerProjection,
|
|
157
|
+
): PartnersEventProjection {
|
|
158
|
+
return {
|
|
159
|
+
...state,
|
|
160
|
+
partners: { ...state.partners, [partner.partnerId]: partner },
|
|
161
|
+
};
|
|
162
|
+
}
|
package/src/state.ts
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import type { Delayed } from "@interest-protocol/blast-core/bcs";
|
|
2
|
+
import {
|
|
3
|
+
addressBcs,
|
|
4
|
+
delayedBcs,
|
|
5
|
+
suiObjectIdBcs,
|
|
6
|
+
suiUidBcs,
|
|
7
|
+
tableBcs,
|
|
8
|
+
u64Bcs,
|
|
9
|
+
unitKeyBcs,
|
|
10
|
+
} from "@interest-protocol/blast-core/bcs";
|
|
11
|
+
import {
|
|
12
|
+
BASIS_POINTS_DENOMINATOR,
|
|
13
|
+
mulDivDown,
|
|
14
|
+
normalizePositiveU64,
|
|
15
|
+
} from "@interest-protocol/blast-core/integers";
|
|
16
|
+
import type { SharedObjectIdentity } from "@interest-protocol/blast-core/sui";
|
|
17
|
+
import { bcs } from "@mysten/sui/bcs";
|
|
18
|
+
import type { ClientWithCoreApi } from "@mysten/sui/client";
|
|
19
|
+
import { ObjectError } from "@mysten/sui/client";
|
|
20
|
+
import { normalizeSuiObjectId, parseStructTag } from "@mysten/sui/utils";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* `blast_partners::delay_ms`: the fixed notice before a share or cap Blast
|
|
24
|
+
* proposes can be applied.
|
|
25
|
+
*/
|
|
26
|
+
export const PARTNER_DELAY_MS = 604_800_000n;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The partner's recipient, share and managing cap, as Move stores them. A
|
|
30
|
+
* share or cap proposal changes nothing until someone applies it.
|
|
31
|
+
*/
|
|
32
|
+
export type PartnerTerms = {
|
|
33
|
+
recipient: string;
|
|
34
|
+
/** Basis points of Blast's fee on each trade naming the partner. */
|
|
35
|
+
shareBps: Delayed<null, bigint>;
|
|
36
|
+
/** The only `PartnerCap` that may set `recipient`. */
|
|
37
|
+
capId: Delayed<null, string>;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const partnerTermsBcs = {
|
|
41
|
+
recipient: addressBcs,
|
|
42
|
+
share_bps: delayedBcs(unitKeyBcs, u64Bcs),
|
|
43
|
+
cap_id: delayedBcs(unitKeyBcs, suiObjectIdBcs),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/** BCS layout of `blast_partners::blast_partners::Partner`. */
|
|
47
|
+
export const partnerBcs = bcs.struct("Partner", {
|
|
48
|
+
id: suiUidBcs,
|
|
49
|
+
...partnerTermsBcs,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
export type PartnerState = SharedObjectIdentity & PartnerTerms;
|
|
53
|
+
|
|
54
|
+
export type PartnerObject = SharedObjectIdentity & {
|
|
55
|
+
type: string;
|
|
56
|
+
content: Uint8Array;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export function decodePartnerObject(
|
|
60
|
+
object: PartnerObject,
|
|
61
|
+
partnersPackageId: string,
|
|
62
|
+
): PartnerState {
|
|
63
|
+
const tag = parseStructTag(object.type);
|
|
64
|
+
if (
|
|
65
|
+
tag.address !== normalizeSuiObjectId(partnersPackageId) ||
|
|
66
|
+
tag.module !== "blast_partners" ||
|
|
67
|
+
tag.name !== "Partner"
|
|
68
|
+
) {
|
|
69
|
+
throw new TypeError(`object ${object.objectId} is not a Blast partner`);
|
|
70
|
+
}
|
|
71
|
+
const parsed = partnerBcs.parse(object.content);
|
|
72
|
+
const objectId = normalizeSuiObjectId(object.objectId);
|
|
73
|
+
if (
|
|
74
|
+
normalizeSuiObjectId(parsed.id.id.bytes) !== objectId ||
|
|
75
|
+
parsed.share_bps.parent !== objectId ||
|
|
76
|
+
parsed.cap_id.parent !== objectId
|
|
77
|
+
) {
|
|
78
|
+
throw new TypeError(`partner ${object.objectId} has a mismatched UID`);
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
objectId,
|
|
82
|
+
initialSharedVersion: normalizePositiveU64(
|
|
83
|
+
"initialSharedVersion",
|
|
84
|
+
object.initialSharedVersion,
|
|
85
|
+
),
|
|
86
|
+
recipient: parsed.recipient,
|
|
87
|
+
shareBps: parsed.share_bps,
|
|
88
|
+
capId: parsed.cap_id,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export async function getPartner(
|
|
93
|
+
client: ClientWithCoreApi,
|
|
94
|
+
objectId: string,
|
|
95
|
+
partnersPackageId: string,
|
|
96
|
+
): Promise<PartnerState> {
|
|
97
|
+
const { object } = await client.core.getObject({
|
|
98
|
+
objectId,
|
|
99
|
+
include: { content: true },
|
|
100
|
+
});
|
|
101
|
+
if (object.owner.$kind !== "Shared") {
|
|
102
|
+
throw new TypeError(`partner ${object.objectId} is not a shared object`);
|
|
103
|
+
}
|
|
104
|
+
return decodePartnerObject(
|
|
105
|
+
{
|
|
106
|
+
objectId: object.objectId,
|
|
107
|
+
initialSharedVersion: object.owner.Shared.initialSharedVersion,
|
|
108
|
+
type: object.type,
|
|
109
|
+
content: object.content,
|
|
110
|
+
},
|
|
111
|
+
partnersPackageId,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Mirrors `blast_partners::pay`: the partner's applied share of `fee`
|
|
117
|
+
* (Blast's fee on one trade, in that coin's atoms), rounded down; Blast keeps
|
|
118
|
+
* the remainder.
|
|
119
|
+
*/
|
|
120
|
+
export function partnerPayment(
|
|
121
|
+
partner: Pick<PartnerTerms, "shareBps">,
|
|
122
|
+
fee: bigint,
|
|
123
|
+
): bigint {
|
|
124
|
+
return mulDivDown(fee, partner.shareBps.value, BASIS_POINTS_DENOMINATOR);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* BCS layout of `blast_partners::partner_list::PartnerList`, embedded in a
|
|
129
|
+
* product's configuration (`LaunchConfig.partners`,
|
|
130
|
+
* `CreationPolicy.partners`). `parent` is that configuration's ID; each
|
|
131
|
+
* accepted partner is an entry of the `acceptance_ends_at_ms` table.
|
|
132
|
+
*/
|
|
133
|
+
export const partnerListBcs = bcs.struct("PartnerList", {
|
|
134
|
+
parent: suiObjectIdBcs,
|
|
135
|
+
acceptance_ends_at_ms: tableBcs,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
export type PartnerList = ReturnType<typeof partnerListBcs.parse>;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Reads one entry of a `PartnerList`'s `acceptance_ends_at_ms` table (its
|
|
142
|
+
* `id`): the millisecond from which new sales stop naming `partnerId`, or
|
|
143
|
+
* `U64_MAX` while it is accepted without end. Null when the list never
|
|
144
|
+
* accepted the partner. A partner is accepted at `now` when `now` is before
|
|
145
|
+
* the returned time (`partner_list::is_accepted`).
|
|
146
|
+
*/
|
|
147
|
+
export async function getPartnerAcceptance(
|
|
148
|
+
client: ClientWithCoreApi,
|
|
149
|
+
listTableId: string,
|
|
150
|
+
partnerId: string,
|
|
151
|
+
): Promise<bigint | null> {
|
|
152
|
+
try {
|
|
153
|
+
const { dynamicField } = await client.core.getDynamicField({
|
|
154
|
+
parentId: normalizeSuiObjectId(listTableId),
|
|
155
|
+
name: {
|
|
156
|
+
type: "0x2::object::ID",
|
|
157
|
+
bcs: suiObjectIdBcs.serialize(partnerId).toBytes(),
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
return u64Bcs.parse(dynamicField.value.bcs);
|
|
161
|
+
} catch (error) {
|
|
162
|
+
if (error instanceof ObjectError && error.reason === "notFound")
|
|
163
|
+
return null;
|
|
164
|
+
throw error;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import type { AdminDeployment } from "@interest-protocol/blast-admin-sdk/transactions";
|
|
2
|
+
import {
|
|
3
|
+
AdminCalls,
|
|
4
|
+
normalizeAdminDeployment,
|
|
5
|
+
} from "@interest-protocol/blast-admin-sdk/transactions";
|
|
6
|
+
import { requireBasisPoints } from "@interest-protocol/blast-core/integers";
|
|
7
|
+
import type { SharedObjectReference } from "@interest-protocol/blast-core/sui";
|
|
8
|
+
import { normalizeSharedObjectReference } from "@interest-protocol/blast-core/sui";
|
|
9
|
+
import type {
|
|
10
|
+
TransactionObjectArgument,
|
|
11
|
+
TransactionObjectInput,
|
|
12
|
+
TransactionResult,
|
|
13
|
+
} from "@mysten/sui/transactions";
|
|
14
|
+
import { Transaction } from "@mysten/sui/transactions";
|
|
15
|
+
import { normalizeSuiAddress, normalizeSuiObjectId } from "@mysten/sui/utils";
|
|
16
|
+
|
|
17
|
+
/** The canonical `blast_partners` package (immutability deferred) and the ACL its `PartnerAdmin` signs in to. */
|
|
18
|
+
export type PartnersDeployment = {
|
|
19
|
+
packageId: string;
|
|
20
|
+
admin: AdminDeployment;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/** `blast_partners::blast_partners` calls. */
|
|
24
|
+
export class PartnersCalls {
|
|
25
|
+
readonly deployment: PartnersDeployment;
|
|
26
|
+
readonly admin: AdminCalls;
|
|
27
|
+
|
|
28
|
+
constructor(deployment: PartnersDeployment) {
|
|
29
|
+
this.deployment = {
|
|
30
|
+
packageId: normalizeSuiObjectId(deployment.packageId),
|
|
31
|
+
admin: normalizeAdminDeployment(deployment.admin),
|
|
32
|
+
};
|
|
33
|
+
this.admin = new AdminCalls(this.deployment.admin);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** The `PartnerAdmin` role type, for `AdminCalls.grantRole`. */
|
|
37
|
+
roleType(): string {
|
|
38
|
+
return `${this.deployment.packageId}::blast_partners::PartnerAdmin`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** This PTB's `AdminWitness<PartnerAdmin>`. */
|
|
42
|
+
signIn(options: { adminCap: TransactionObjectInput }) {
|
|
43
|
+
return this.admin.signIn({
|
|
44
|
+
adminCap: options.adminCap,
|
|
45
|
+
role: this.roleType(),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** `new_cap`: anyone may mint one; it controls nothing until a partner names it. */
|
|
50
|
+
newCap() {
|
|
51
|
+
return (tx: Transaction): TransactionResult =>
|
|
52
|
+
tx.moveCall({ target: this.#target("new_cap") });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* `register` (`PartnerAdmin`): shares a partner managed by the cap
|
|
57
|
+
* `capId`, its share and cap in force at once.
|
|
58
|
+
*/
|
|
59
|
+
register(options: {
|
|
60
|
+
adminWitness: TransactionObjectInput;
|
|
61
|
+
capId: string;
|
|
62
|
+
recipient: string;
|
|
63
|
+
shareBps: bigint;
|
|
64
|
+
}) {
|
|
65
|
+
const capId = normalizeSuiObjectId(options.capId);
|
|
66
|
+
const recipient = normalizeSuiAddress(options.recipient);
|
|
67
|
+
const shareBps = requireBasisPoints("shareBps", options.shareBps);
|
|
68
|
+
return (tx: Transaction): void => {
|
|
69
|
+
tx.moveCall({
|
|
70
|
+
target: this.#target("register"),
|
|
71
|
+
arguments: [
|
|
72
|
+
tx.object(options.adminWitness),
|
|
73
|
+
tx.pure.id(capId),
|
|
74
|
+
tx.pure.address(recipient),
|
|
75
|
+
tx.pure.u64(shareBps),
|
|
76
|
+
],
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* `schedule_share` (`PartnerAdmin`): proposes the share, which `applyShare`
|
|
83
|
+
* applies once `PARTNER_DELAY_MS` has passed. A new proposal replaces a
|
|
84
|
+
* pending one and restarts the notice.
|
|
85
|
+
*/
|
|
86
|
+
scheduleShare(options: {
|
|
87
|
+
partner: SharedObjectReference<true>;
|
|
88
|
+
adminWitness: TransactionObjectInput;
|
|
89
|
+
shareBps: bigint;
|
|
90
|
+
}) {
|
|
91
|
+
const shareBps = requireBasisPoints("shareBps", options.shareBps);
|
|
92
|
+
return (tx: Transaction): void => {
|
|
93
|
+
tx.moveCall({
|
|
94
|
+
target: this.#target("schedule_share"),
|
|
95
|
+
arguments: [
|
|
96
|
+
partner(tx, options.partner),
|
|
97
|
+
tx.object(options.adminWitness),
|
|
98
|
+
tx.pure.u64(shareBps),
|
|
99
|
+
tx.object.clock(),
|
|
100
|
+
],
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* `schedule_cap` (`PartnerAdmin`): proposes moving the partner to the cap
|
|
107
|
+
* `capId`, which `applyCap` applies once `PARTNER_DELAY_MS` has passed.
|
|
108
|
+
*/
|
|
109
|
+
scheduleCap(options: {
|
|
110
|
+
partner: SharedObjectReference<true>;
|
|
111
|
+
adminWitness: TransactionObjectInput;
|
|
112
|
+
capId: string;
|
|
113
|
+
}) {
|
|
114
|
+
const capId = normalizeSuiObjectId(options.capId);
|
|
115
|
+
return (tx: Transaction): void => {
|
|
116
|
+
tx.moveCall({
|
|
117
|
+
target: this.#target("schedule_cap"),
|
|
118
|
+
arguments: [
|
|
119
|
+
partner(tx, options.partner),
|
|
120
|
+
tx.object(options.adminWitness),
|
|
121
|
+
tx.pure.id(capId),
|
|
122
|
+
tx.object.clock(),
|
|
123
|
+
],
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** `apply_share`: anyone applies the proposed share once its notice has passed. */
|
|
129
|
+
applyShare(options: { partner: SharedObjectReference<true> }) {
|
|
130
|
+
return (tx: Transaction): void => {
|
|
131
|
+
tx.moveCall({
|
|
132
|
+
target: this.#target("apply_share"),
|
|
133
|
+
arguments: [partner(tx, options.partner), tx.object.clock()],
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** `apply_cap`: anyone applies the proposed managing cap once its notice has passed. */
|
|
139
|
+
applyCap(options: { partner: SharedObjectReference<true> }) {
|
|
140
|
+
return (tx: Transaction): void => {
|
|
141
|
+
tx.moveCall({
|
|
142
|
+
target: this.#target("apply_cap"),
|
|
143
|
+
arguments: [partner(tx, options.partner), tx.object.clock()],
|
|
144
|
+
});
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** `cancel_share` (`PartnerAdmin`): discards the proposed share, even a ready one. */
|
|
149
|
+
cancelShare(options: {
|
|
150
|
+
partner: SharedObjectReference<true>;
|
|
151
|
+
adminWitness: TransactionObjectInput;
|
|
152
|
+
}) {
|
|
153
|
+
return (tx: Transaction): void => {
|
|
154
|
+
tx.moveCall({
|
|
155
|
+
target: this.#target("cancel_share"),
|
|
156
|
+
arguments: [
|
|
157
|
+
partner(tx, options.partner),
|
|
158
|
+
tx.object(options.adminWitness),
|
|
159
|
+
],
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** `cancel_cap` (`PartnerAdmin`): discards the proposed managing cap, even a ready one. */
|
|
165
|
+
cancelCap(options: {
|
|
166
|
+
partner: SharedObjectReference<true>;
|
|
167
|
+
adminWitness: TransactionObjectInput;
|
|
168
|
+
}) {
|
|
169
|
+
return (tx: Transaction): void => {
|
|
170
|
+
tx.moveCall({
|
|
171
|
+
target: this.#target("cancel_cap"),
|
|
172
|
+
arguments: [
|
|
173
|
+
partner(tx, options.partner),
|
|
174
|
+
tx.object(options.adminWitness),
|
|
175
|
+
],
|
|
176
|
+
});
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** `set_recipient`: the partner's applied cap sets where it is paid, at once. */
|
|
181
|
+
setRecipient(options: {
|
|
182
|
+
partner: SharedObjectReference<true>;
|
|
183
|
+
partnerCap: TransactionObjectInput;
|
|
184
|
+
recipient: string;
|
|
185
|
+
}) {
|
|
186
|
+
const recipient = normalizeSuiAddress(options.recipient);
|
|
187
|
+
return (tx: Transaction): void => {
|
|
188
|
+
tx.moveCall({
|
|
189
|
+
target: this.#target("set_recipient"),
|
|
190
|
+
arguments: [
|
|
191
|
+
partner(tx, options.partner),
|
|
192
|
+
tx.object(options.partnerCap),
|
|
193
|
+
tx.pure.address(recipient),
|
|
194
|
+
],
|
|
195
|
+
});
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
destroyCap(options: { partnerCap: TransactionObjectInput }) {
|
|
200
|
+
return (tx: Transaction): void => {
|
|
201
|
+
tx.moveCall({
|
|
202
|
+
target: this.#target("destroy_cap"),
|
|
203
|
+
arguments: [tx.object(options.partnerCap)],
|
|
204
|
+
});
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
#target(functionName: string): string {
|
|
209
|
+
return `${this.deployment.packageId}::blast_partners::${functionName}`;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export class PartnersTransactions {
|
|
214
|
+
readonly call: PartnersCalls;
|
|
215
|
+
|
|
216
|
+
constructor(deployment: PartnersDeployment) {
|
|
217
|
+
this.call = new PartnersCalls(deployment);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** Mints a `PartnerCap` and sends it to `recipient`. */
|
|
221
|
+
newCap(options: { recipient: string }): Transaction {
|
|
222
|
+
const tx = new Transaction();
|
|
223
|
+
const cap = tx.add(this.call.newCap());
|
|
224
|
+
tx.transferObjects([cap], normalizeSuiAddress(options.recipient));
|
|
225
|
+
return tx;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
register(options: {
|
|
229
|
+
adminCapId: string;
|
|
230
|
+
capId: string;
|
|
231
|
+
recipient: string;
|
|
232
|
+
shareBps: bigint;
|
|
233
|
+
}): Transaction {
|
|
234
|
+
return this.#asPartnerAdmin(options.adminCapId, (adminWitness) =>
|
|
235
|
+
this.call.register({ ...options, adminWitness }),
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
scheduleShare(options: {
|
|
240
|
+
adminCapId: string;
|
|
241
|
+
partner: SharedObjectReference<true>;
|
|
242
|
+
shareBps: bigint;
|
|
243
|
+
}): Transaction {
|
|
244
|
+
return this.#asPartnerAdmin(options.adminCapId, (adminWitness) =>
|
|
245
|
+
this.call.scheduleShare({ ...options, adminWitness }),
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
scheduleCap(options: {
|
|
250
|
+
adminCapId: string;
|
|
251
|
+
partner: SharedObjectReference<true>;
|
|
252
|
+
capId: string;
|
|
253
|
+
}): Transaction {
|
|
254
|
+
return this.#asPartnerAdmin(options.adminCapId, (adminWitness) =>
|
|
255
|
+
this.call.scheduleCap({ ...options, adminWitness }),
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
applyShare(options: { partner: SharedObjectReference<true> }): Transaction {
|
|
260
|
+
const tx = new Transaction();
|
|
261
|
+
tx.add(this.call.applyShare(options));
|
|
262
|
+
return tx;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
applyCap(options: { partner: SharedObjectReference<true> }): Transaction {
|
|
266
|
+
const tx = new Transaction();
|
|
267
|
+
tx.add(this.call.applyCap(options));
|
|
268
|
+
return tx;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
cancelShare(options: {
|
|
272
|
+
adminCapId: string;
|
|
273
|
+
partner: SharedObjectReference<true>;
|
|
274
|
+
}): Transaction {
|
|
275
|
+
return this.#asPartnerAdmin(options.adminCapId, (adminWitness) =>
|
|
276
|
+
this.call.cancelShare({ ...options, adminWitness }),
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
cancelCap(options: {
|
|
281
|
+
adminCapId: string;
|
|
282
|
+
partner: SharedObjectReference<true>;
|
|
283
|
+
}): Transaction {
|
|
284
|
+
return this.#asPartnerAdmin(options.adminCapId, (adminWitness) =>
|
|
285
|
+
this.call.cancelCap({ ...options, adminWitness }),
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
setRecipient(options: {
|
|
290
|
+
partner: SharedObjectReference<true>;
|
|
291
|
+
partnerCapId: string;
|
|
292
|
+
recipient: string;
|
|
293
|
+
}): Transaction {
|
|
294
|
+
const tx = new Transaction();
|
|
295
|
+
tx.add(
|
|
296
|
+
this.call.setRecipient({ ...options, partnerCap: options.partnerCapId }),
|
|
297
|
+
);
|
|
298
|
+
return tx;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
destroyCap(options: { partnerCapId: string }): Transaction {
|
|
302
|
+
const tx = new Transaction();
|
|
303
|
+
tx.add(this.call.destroyCap({ partnerCap: options.partnerCapId }));
|
|
304
|
+
return tx;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
#asPartnerAdmin(
|
|
308
|
+
adminCapId: string,
|
|
309
|
+
call: (
|
|
310
|
+
adminWitness: TransactionObjectArgument,
|
|
311
|
+
) => (tx: Transaction) => void,
|
|
312
|
+
): Transaction {
|
|
313
|
+
const tx = new Transaction();
|
|
314
|
+
const adminWitness = tx.add(this.call.signIn({ adminCap: adminCapId }));
|
|
315
|
+
tx.add(call(adminWitness));
|
|
316
|
+
return tx;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function partner(
|
|
321
|
+
tx: Transaction,
|
|
322
|
+
reference: SharedObjectReference<true>,
|
|
323
|
+
): TransactionObjectArgument {
|
|
324
|
+
return tx.sharedObjectRef(
|
|
325
|
+
normalizeSharedObjectReference("partner", reference, true),
|
|
326
|
+
);
|
|
327
|
+
}
|