@frontiercompute/zcash-ika 0.5.0 → 0.6.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/dist/index.d.ts +58 -0
- package/dist/index.js +208 -7
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -216,6 +216,64 @@ export declare function setPolicy(config: ZcashIkaConfig, walletId: string, poli
|
|
|
216
216
|
export declare function checkPolicy(config: ZcashIkaConfig, policyId: string, amount?: number, recipient?: string): Promise<PolicyState & {
|
|
217
217
|
allowed: boolean;
|
|
218
218
|
}>;
|
|
219
|
+
export interface VaultResult {
|
|
220
|
+
/** CustodyVault shared object ID on Sui */
|
|
221
|
+
vaultId: string;
|
|
222
|
+
/** AdminCap object ID (vault creator holds this) */
|
|
223
|
+
adminCapId: string;
|
|
224
|
+
/** Sui transaction digest */
|
|
225
|
+
txDigest: string;
|
|
226
|
+
}
|
|
227
|
+
export interface AgentResult {
|
|
228
|
+
/** AgentCap object ID (issued to the registered agent) */
|
|
229
|
+
agentCapId: string;
|
|
230
|
+
/** Sui transaction digest */
|
|
231
|
+
txDigest: string;
|
|
232
|
+
}
|
|
233
|
+
export interface VaultState {
|
|
234
|
+
vaultId: string;
|
|
235
|
+
dwalletId: string;
|
|
236
|
+
maxPerTx: number;
|
|
237
|
+
maxDaily: number;
|
|
238
|
+
dailySpent: number;
|
|
239
|
+
totalSpent: number;
|
|
240
|
+
totalTxCount: number;
|
|
241
|
+
agentCount: number;
|
|
242
|
+
frozen: boolean;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Create a CustodyVault for a dWallet.
|
|
246
|
+
* The vault enforces spend policy on-chain and tracks agent access.
|
|
247
|
+
* Returns the vault ID and AdminCap (transferred to caller).
|
|
248
|
+
*/
|
|
249
|
+
export declare function createVault(config: ZcashIkaConfig, dwalletId: string, maxPerTx: number, maxDaily: number): Promise<VaultResult>;
|
|
250
|
+
/**
|
|
251
|
+
* Register an agent on a CustodyVault.
|
|
252
|
+
* Only the admin (holder of AdminCap) can do this.
|
|
253
|
+
* Returns the AgentCap which should be transferred to the agent.
|
|
254
|
+
*/
|
|
255
|
+
export declare function registerAgent(config: ZcashIkaConfig, vaultId: string, adminCapId: string, agentAddress: string, agentName: string): Promise<AgentResult>;
|
|
256
|
+
/**
|
|
257
|
+
* Request a spend through the CustodyVault.
|
|
258
|
+
* The Move contract checks all policy constraints on-chain.
|
|
259
|
+
* Aborts if the spend violates any limit.
|
|
260
|
+
*/
|
|
261
|
+
export declare function requestSpend(config: ZcashIkaConfig, vaultId: string, agentCapId: string, amount: number, recipient: string, chain: string): Promise<{
|
|
262
|
+
approved: boolean;
|
|
263
|
+
txDigest: string;
|
|
264
|
+
}>;
|
|
265
|
+
/**
|
|
266
|
+
* Read the on-chain state of a CustodyVault.
|
|
267
|
+
*/
|
|
268
|
+
export declare function getVaultState(config: ZcashIkaConfig, vaultId: string): Promise<VaultState>;
|
|
269
|
+
/**
|
|
270
|
+
* Freeze a CustodyVault. All spend requests will be rejected until unfrozen.
|
|
271
|
+
*/
|
|
272
|
+
export declare function freezeVault(config: ZcashIkaConfig, vaultId: string, adminCapId: string): Promise<string>;
|
|
273
|
+
/**
|
|
274
|
+
* Unfreeze a CustodyVault. Resumes normal spend processing.
|
|
275
|
+
*/
|
|
276
|
+
export declare function unfreezeVault(config: ZcashIkaConfig, vaultId: string, adminCapId: string): Promise<string>;
|
|
219
277
|
/**
|
|
220
278
|
* Spend from a Zcash transparent wallet.
|
|
221
279
|
*
|
package/dist/index.js
CHANGED
|
@@ -517,9 +517,9 @@ export async function sign(config, request) {
|
|
|
517
517
|
signTxDigest: signResult.digest,
|
|
518
518
|
};
|
|
519
519
|
}
|
|
520
|
-
//
|
|
521
|
-
// Override via POLICY_PACKAGE_ID env var or
|
|
522
|
-
const DEFAULT_POLICY_PACKAGE_ID = "
|
|
520
|
+
// Sui testnet deployment (zap1_policy package)
|
|
521
|
+
// Override via POLICY_PACKAGE_ID env var for mainnet or redeployments
|
|
522
|
+
const DEFAULT_POLICY_PACKAGE_ID = "0xb0468033d854e95ad89de4b6fec8f6d8e8187778c9d8337a6aa30a5c24775a77";
|
|
523
523
|
function getPolicyPackageId() {
|
|
524
524
|
return process.env.POLICY_PACKAGE_ID || DEFAULT_POLICY_PACKAGE_ID;
|
|
525
525
|
}
|
|
@@ -530,10 +530,6 @@ function getPolicyPackageId() {
|
|
|
530
530
|
*/
|
|
531
531
|
export async function setPolicy(config, walletId, policy) {
|
|
532
532
|
const packageId = getPolicyPackageId();
|
|
533
|
-
if (packageId === "0x0") {
|
|
534
|
-
throw new Error("Policy Move module not deployed. Set POLICY_PACKAGE_ID env var " +
|
|
535
|
-
"after running: sui client publish --path move/");
|
|
536
|
-
}
|
|
537
533
|
const { suiClient, keypair } = await initClients(config);
|
|
538
534
|
const tx = new Transaction();
|
|
539
535
|
// 0x6 is the shared Clock object on Sui
|
|
@@ -655,6 +651,211 @@ export async function checkPolicy(config, policyId, amount, recipient) {
|
|
|
655
651
|
}
|
|
656
652
|
return { ...state, allowed };
|
|
657
653
|
}
|
|
654
|
+
/**
|
|
655
|
+
* Create a CustodyVault for a dWallet.
|
|
656
|
+
* The vault enforces spend policy on-chain and tracks agent access.
|
|
657
|
+
* Returns the vault ID and AdminCap (transferred to caller).
|
|
658
|
+
*/
|
|
659
|
+
export async function createVault(config, dwalletId, maxPerTx, maxDaily) {
|
|
660
|
+
const packageId = getPolicyPackageId();
|
|
661
|
+
const { suiClient, keypair } = await initClients(config);
|
|
662
|
+
const sender = keypair.getPublicKey().toSuiAddress();
|
|
663
|
+
const tx = new Transaction();
|
|
664
|
+
const adminCap = tx.moveCall({
|
|
665
|
+
target: `${packageId}::custody::create_vault`,
|
|
666
|
+
arguments: [
|
|
667
|
+
tx.pure.address(dwalletId),
|
|
668
|
+
tx.pure.u64(maxPerTx),
|
|
669
|
+
tx.pure.u64(maxDaily),
|
|
670
|
+
tx.object("0x6"), // Clock
|
|
671
|
+
],
|
|
672
|
+
});
|
|
673
|
+
tx.transferObjects([adminCap], sender);
|
|
674
|
+
const result = await suiClient.signAndExecuteTransaction({
|
|
675
|
+
transaction: tx,
|
|
676
|
+
signer: keypair,
|
|
677
|
+
options: { showEffects: true, showObjectChanges: true },
|
|
678
|
+
});
|
|
679
|
+
if (result.effects?.status?.status !== "success") {
|
|
680
|
+
throw new Error(`createVault TX failed: ${result.effects?.status?.error}`);
|
|
681
|
+
}
|
|
682
|
+
let vaultId = "";
|
|
683
|
+
let adminCapId = "";
|
|
684
|
+
const changes = result.objectChanges || [];
|
|
685
|
+
for (const change of changes) {
|
|
686
|
+
if (change.type !== "created")
|
|
687
|
+
continue;
|
|
688
|
+
const objType = change.objectType || "";
|
|
689
|
+
if (objType.includes("::custody::CustodyVault")) {
|
|
690
|
+
vaultId = change.objectId;
|
|
691
|
+
}
|
|
692
|
+
else if (objType.includes("::custody::AdminCap")) {
|
|
693
|
+
adminCapId = change.objectId;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
if (!vaultId || !adminCapId) {
|
|
697
|
+
const created = result.effects?.created || [];
|
|
698
|
+
for (const obj of created) {
|
|
699
|
+
const id = obj.reference?.objectId || obj.objectId;
|
|
700
|
+
if (id && !vaultId)
|
|
701
|
+
vaultId = id;
|
|
702
|
+
else if (id && !adminCapId)
|
|
703
|
+
adminCapId = id;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
return { vaultId, adminCapId, txDigest: result.digest };
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Register an agent on a CustodyVault.
|
|
710
|
+
* Only the admin (holder of AdminCap) can do this.
|
|
711
|
+
* Returns the AgentCap which should be transferred to the agent.
|
|
712
|
+
*/
|
|
713
|
+
export async function registerAgent(config, vaultId, adminCapId, agentAddress, agentName) {
|
|
714
|
+
const packageId = getPolicyPackageId();
|
|
715
|
+
const { suiClient, keypair } = await initClients(config);
|
|
716
|
+
const sender = keypair.getPublicKey().toSuiAddress();
|
|
717
|
+
const tx = new Transaction();
|
|
718
|
+
const nameBytes = Array.from(new TextEncoder().encode(agentName));
|
|
719
|
+
const agentCap = tx.moveCall({
|
|
720
|
+
target: `${packageId}::custody::register_agent`,
|
|
721
|
+
arguments: [
|
|
722
|
+
tx.object(vaultId),
|
|
723
|
+
tx.object(adminCapId),
|
|
724
|
+
tx.pure.address(agentAddress),
|
|
725
|
+
tx.pure.vector("u8", nameBytes),
|
|
726
|
+
tx.object("0x6"), // Clock
|
|
727
|
+
],
|
|
728
|
+
});
|
|
729
|
+
// Transfer AgentCap to the agent address
|
|
730
|
+
tx.transferObjects([agentCap], agentAddress);
|
|
731
|
+
const result = await suiClient.signAndExecuteTransaction({
|
|
732
|
+
transaction: tx,
|
|
733
|
+
signer: keypair,
|
|
734
|
+
options: { showEffects: true, showObjectChanges: true },
|
|
735
|
+
});
|
|
736
|
+
if (result.effects?.status?.status !== "success") {
|
|
737
|
+
throw new Error(`registerAgent TX failed: ${result.effects?.status?.error}`);
|
|
738
|
+
}
|
|
739
|
+
let agentCapId = "";
|
|
740
|
+
const changes = result.objectChanges || [];
|
|
741
|
+
for (const change of changes) {
|
|
742
|
+
if (change.type !== "created")
|
|
743
|
+
continue;
|
|
744
|
+
const objType = change.objectType || "";
|
|
745
|
+
if (objType.includes("::custody::AgentCap")) {
|
|
746
|
+
agentCapId = change.objectId;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
return { agentCapId, txDigest: result.digest };
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Request a spend through the CustodyVault.
|
|
753
|
+
* The Move contract checks all policy constraints on-chain.
|
|
754
|
+
* Aborts if the spend violates any limit.
|
|
755
|
+
*/
|
|
756
|
+
export async function requestSpend(config, vaultId, agentCapId, amount, recipient, chain) {
|
|
757
|
+
const packageId = getPolicyPackageId();
|
|
758
|
+
const { suiClient, keypair } = await initClients(config);
|
|
759
|
+
const tx = new Transaction();
|
|
760
|
+
const recipientBytes = Array.from(new TextEncoder().encode(recipient));
|
|
761
|
+
const chainBytes = Array.from(new TextEncoder().encode(chain));
|
|
762
|
+
tx.moveCall({
|
|
763
|
+
target: `${packageId}::custody::request_spend_entry`,
|
|
764
|
+
arguments: [
|
|
765
|
+
tx.object(vaultId),
|
|
766
|
+
tx.object(agentCapId),
|
|
767
|
+
tx.pure.u64(amount),
|
|
768
|
+
tx.pure.vector("u8", recipientBytes),
|
|
769
|
+
tx.pure.vector("u8", chainBytes),
|
|
770
|
+
tx.object("0x6"), // Clock
|
|
771
|
+
],
|
|
772
|
+
});
|
|
773
|
+
const result = await suiClient.signAndExecuteTransaction({
|
|
774
|
+
transaction: tx,
|
|
775
|
+
signer: keypair,
|
|
776
|
+
options: { showEffects: true },
|
|
777
|
+
});
|
|
778
|
+
if (result.effects?.status?.status !== "success") {
|
|
779
|
+
return { approved: false, txDigest: result.digest };
|
|
780
|
+
}
|
|
781
|
+
return { approved: true, txDigest: result.digest };
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* Read the on-chain state of a CustodyVault.
|
|
785
|
+
*/
|
|
786
|
+
export async function getVaultState(config, vaultId) {
|
|
787
|
+
const { suiClient } = await initClients(config);
|
|
788
|
+
const obj = await suiClient.getObject({
|
|
789
|
+
id: vaultId,
|
|
790
|
+
options: { showContent: true },
|
|
791
|
+
});
|
|
792
|
+
const content = obj.data?.content;
|
|
793
|
+
if (!content || content.dataType !== "moveObject") {
|
|
794
|
+
throw new Error(`Vault object ${vaultId} not found or not a Move object`);
|
|
795
|
+
}
|
|
796
|
+
const fields = content.fields;
|
|
797
|
+
return {
|
|
798
|
+
vaultId,
|
|
799
|
+
dwalletId: fields.dwallet_id,
|
|
800
|
+
maxPerTx: Number(fields.max_per_tx),
|
|
801
|
+
maxDaily: Number(fields.max_daily),
|
|
802
|
+
dailySpent: Number(fields.daily_spent),
|
|
803
|
+
totalSpent: Number(fields.total_spent),
|
|
804
|
+
totalTxCount: Number(fields.total_tx_count),
|
|
805
|
+
agentCount: Number(fields.agent_count),
|
|
806
|
+
frozen: fields.frozen,
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* Freeze a CustodyVault. All spend requests will be rejected until unfrozen.
|
|
811
|
+
*/
|
|
812
|
+
export async function freezeVault(config, vaultId, adminCapId) {
|
|
813
|
+
const packageId = getPolicyPackageId();
|
|
814
|
+
const { suiClient, keypair } = await initClients(config);
|
|
815
|
+
const tx = new Transaction();
|
|
816
|
+
tx.moveCall({
|
|
817
|
+
target: `${packageId}::custody::freeze_vault`,
|
|
818
|
+
arguments: [
|
|
819
|
+
tx.object(vaultId),
|
|
820
|
+
tx.object(adminCapId),
|
|
821
|
+
tx.object("0x6"), // Clock
|
|
822
|
+
],
|
|
823
|
+
});
|
|
824
|
+
const result = await suiClient.signAndExecuteTransaction({
|
|
825
|
+
transaction: tx,
|
|
826
|
+
signer: keypair,
|
|
827
|
+
options: { showEffects: true },
|
|
828
|
+
});
|
|
829
|
+
if (result.effects?.status?.status !== "success") {
|
|
830
|
+
throw new Error(`freezeVault TX failed: ${result.effects?.status?.error}`);
|
|
831
|
+
}
|
|
832
|
+
return result.digest;
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* Unfreeze a CustodyVault. Resumes normal spend processing.
|
|
836
|
+
*/
|
|
837
|
+
export async function unfreezeVault(config, vaultId, adminCapId) {
|
|
838
|
+
const packageId = getPolicyPackageId();
|
|
839
|
+
const { suiClient, keypair } = await initClients(config);
|
|
840
|
+
const tx = new Transaction();
|
|
841
|
+
tx.moveCall({
|
|
842
|
+
target: `${packageId}::custody::unfreeze_vault`,
|
|
843
|
+
arguments: [
|
|
844
|
+
tx.object(vaultId),
|
|
845
|
+
tx.object(adminCapId),
|
|
846
|
+
tx.object("0x6"), // Clock
|
|
847
|
+
],
|
|
848
|
+
});
|
|
849
|
+
const result = await suiClient.signAndExecuteTransaction({
|
|
850
|
+
transaction: tx,
|
|
851
|
+
signer: keypair,
|
|
852
|
+
options: { showEffects: true },
|
|
853
|
+
});
|
|
854
|
+
if (result.effects?.status?.status !== "success") {
|
|
855
|
+
throw new Error(`unfreezeVault TX failed: ${result.effects?.status?.error}`);
|
|
856
|
+
}
|
|
857
|
+
return result.digest;
|
|
858
|
+
}
|
|
658
859
|
/**
|
|
659
860
|
* Spend from a Zcash transparent wallet.
|
|
660
861
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontiercompute/zcash-ika",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Split-key custody for Zcash, Bitcoin, and EVM. 2PC-MPC signing, on-chain spend policy, transparent TX builder, ZAP1 attestation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|