@sequence0/sdk 1.2.0 → 2.0.1
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/core/atomic.d.ts +76 -0
- package/dist/core/atomic.d.ts.map +1 -0
- package/dist/core/atomic.js +39 -0
- package/dist/core/atomic.js.map +1 -0
- package/dist/core/client.d.ts +238 -0
- package/dist/core/client.d.ts.map +1 -1
- package/dist/core/client.js +536 -4
- package/dist/core/client.js.map +1 -1
- package/dist/core/delegation.d.ts +184 -0
- package/dist/core/delegation.d.ts.map +1 -0
- package/dist/core/delegation.js +37 -0
- package/dist/core/delegation.js.map +1 -0
- package/dist/core/programmable.d.ts +66 -0
- package/dist/core/programmable.d.ts.map +1 -0
- package/dist/core/programmable.js +36 -0
- package/dist/core/programmable.js.map +1 -0
- package/dist/core/solvency.d.ts +223 -0
- package/dist/core/solvency.d.ts.map +1 -0
- package/dist/core/solvency.js +267 -0
- package/dist/core/solvency.js.map +1 -0
- package/dist/core/types.d.ts +11 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/universal-account.d.ts +438 -0
- package/dist/core/universal-account.d.ts.map +1 -0
- package/dist/core/universal-account.js +597 -0
- package/dist/core/universal-account.js.map +1 -0
- package/dist/core/witness.d.ts +197 -0
- package/dist/core/witness.d.ts.map +1 -0
- package/dist/core/witness.js +298 -0
- package/dist/core/witness.js.map +1 -0
- package/dist/erc4337/types.js +2 -2
- package/dist/index.d.ts +12 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -3
- package/dist/index.js.map +1 -1
- package/dist/settlement/settlement.d.ts +152 -0
- package/dist/settlement/settlement.d.ts.map +1 -0
- package/dist/settlement/settlement.js +172 -0
- package/dist/settlement/settlement.js.map +1 -0
- package/dist/utils/discovery.js +4 -5
- package/dist/utils/discovery.js.map +1 -1
- package/dist/utils/eip712.js +2 -2
- package/dist/utils/fee.d.ts +2 -2
- package/dist/utils/fee.js +2 -2
- package/dist/utils/http.d.ts.map +1 -1
- package/dist/utils/http.js +6 -1
- package/dist/utils/http.js.map +1 -1
- package/dist/utils/logger.d.ts +3 -3
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +3 -3
- package/dist/utils/logger.js.map +1 -1
- package/dist/wallet/wallet.d.ts +52 -0
- package/dist/wallet/wallet.d.ts.map +1 -1
- package/dist/wallet/wallet.js +204 -0
- package/dist/wallet/wallet.js.map +1 -1
- package/package.json +1 -1
package/dist/core/client.js
CHANGED
|
@@ -31,6 +31,8 @@ const http_1 = require("../utils/http");
|
|
|
31
31
|
const websocket_1 = require("../utils/websocket");
|
|
32
32
|
const discovery_1 = require("../utils/discovery");
|
|
33
33
|
const fee_1 = require("../utils/fee");
|
|
34
|
+
const settlement_1 = require("../settlement/settlement");
|
|
35
|
+
const universal_account_1 = require("./universal-account");
|
|
34
36
|
const errors_1 = require("../utils/errors");
|
|
35
37
|
const eip712_1 = require("../utils/eip712");
|
|
36
38
|
const validation_1 = require("../utils/validation");
|
|
@@ -63,14 +65,20 @@ const SEQUENCE_RPC = {
|
|
|
63
65
|
};
|
|
64
66
|
/** AgentRegistry contract addresses */
|
|
65
67
|
const REGISTRY_ADDRESSES = {
|
|
66
|
-
testnet: '
|
|
67
|
-
mainnet: '
|
|
68
|
+
testnet: '0xb2c218e154d4374e721eab6293af3eeeaa117400',
|
|
69
|
+
mainnet: '0xdefa5ab7ea6a87ac51628f4cde55bb4d49e62f50',
|
|
68
70
|
};
|
|
69
71
|
/** FeeCollector contract addresses */
|
|
70
72
|
const FEE_COLLECTOR_ADDRESSES = {
|
|
71
|
-
testnet: '
|
|
72
|
-
mainnet: '
|
|
73
|
+
testnet: '0xc017d0a5da9369003095325229de1e70f0e33a1c',
|
|
74
|
+
mainnet: '0xccd70007534c33b0ab3997d81207fea5e59ca54a',
|
|
73
75
|
};
|
|
76
|
+
/** ProgramRegistry contract selectors (SIGNET: Programmable Signing) */
|
|
77
|
+
const PROGRAM_REGISTRY_DEPLOY_SELECTOR = '0x2e1a7d4d'; // deployProgram(bytes,string,uint256,uint256)
|
|
78
|
+
const PROGRAM_REGISTRY_ATTACH_SELECTOR = '0x51cff8d9'; // attachProgram(string,bytes32)
|
|
79
|
+
const PROGRAM_REGISTRY_DETACH_SELECTOR = '0x5e2c576e'; // detachProgram(string,bytes32)
|
|
80
|
+
const PROGRAM_REGISTRY_GET_PROGRAMS_SELECTOR = '0x0e316ab7'; // getWalletPrograms(string)
|
|
81
|
+
const PROGRAM_REGISTRY_GET_INFO_SELECTOR = '0x553eca1f'; // getProgramInfo(bytes32)
|
|
74
82
|
/** Default chain RPC URLs */
|
|
75
83
|
const CHAIN_RPCS = {
|
|
76
84
|
testnet: {
|
|
@@ -178,6 +186,10 @@ class Sequence0 {
|
|
|
178
186
|
this.ownerSigner = null;
|
|
179
187
|
/** Owner's Ethereum address (derived from private key when provided) */
|
|
180
188
|
this.ownerAddress = null;
|
|
189
|
+
/** Optional delegate signer for AEGIS delegated signing */
|
|
190
|
+
this.delegateSigner = null;
|
|
191
|
+
/** Delegation grant ID for delegated signing */
|
|
192
|
+
this.delegationId = null;
|
|
181
193
|
const network = config.network || 'mainnet';
|
|
182
194
|
this.config = {
|
|
183
195
|
...config,
|
|
@@ -200,6 +212,19 @@ class Sequence0 {
|
|
|
200
212
|
return sig.r + sig.s.slice(2) + v;
|
|
201
213
|
};
|
|
202
214
|
}
|
|
215
|
+
// Set up delegate signer for AEGIS delegated signing
|
|
216
|
+
if (config.delegatePrivateKey && config.delegationId) {
|
|
217
|
+
this.delegationId = config.delegationId;
|
|
218
|
+
const delegateKey = config.delegatePrivateKey.startsWith('0x')
|
|
219
|
+
? config.delegatePrivateKey
|
|
220
|
+
: '0x' + config.delegatePrivateKey;
|
|
221
|
+
const delegateSigningKey = new ethers_1.SigningKey(delegateKey);
|
|
222
|
+
this.delegateSigner = async (messageHash) => {
|
|
223
|
+
const sig = delegateSigningKey.sign(messageHash);
|
|
224
|
+
const v = sig.v === 27 ? '1b' : '1c';
|
|
225
|
+
return sig.r + sig.s.slice(2) + v;
|
|
226
|
+
};
|
|
227
|
+
}
|
|
203
228
|
const httpOpts = {
|
|
204
229
|
timeout: config.timeout || 30000,
|
|
205
230
|
maxRetries: config.maxRetries,
|
|
@@ -723,6 +748,392 @@ class Sequence0 {
|
|
|
723
748
|
return this.feeManager.buildCollectFeeTx(walletId, agentAddresses);
|
|
724
749
|
}
|
|
725
750
|
// ────────────────────────────────────────────────
|
|
751
|
+
// SIGNET: Programmable Signing (WASM Policies)
|
|
752
|
+
// ────────────────────────────────────────────────
|
|
753
|
+
/**
|
|
754
|
+
* Deploy a WASM signing policy program to the Sequence0 chain.
|
|
755
|
+
*
|
|
756
|
+
* The WASM bytecode is uploaded to the ProgramRegistry contract and
|
|
757
|
+
* assigned a unique programId (bytes32). Once deployed, the program
|
|
758
|
+
* can be attached to any wallet owned by the deployer.
|
|
759
|
+
*
|
|
760
|
+
* @param options - Program deployment options (bytecode, metadata, limits)
|
|
761
|
+
* @returns programId as a bytes32 hex string
|
|
762
|
+
*
|
|
763
|
+
* @throws {Sequence0Error} If no ownerSigner is configured
|
|
764
|
+
* @throws {NetworkError} If the deployment transaction fails
|
|
765
|
+
*
|
|
766
|
+
* @example
|
|
767
|
+
* ```typescript
|
|
768
|
+
* const programId = await s0.deployProgram({
|
|
769
|
+
* bytecode: fs.readFileSync('spending-limit.wasm'),
|
|
770
|
+
* metadataUri: 'ipfs://Qm.../metadata.json',
|
|
771
|
+
* gasLimit: 5_000_000,
|
|
772
|
+
* memoryLimit: 16,
|
|
773
|
+
* });
|
|
774
|
+
* console.log('Deployed program:', programId);
|
|
775
|
+
* ```
|
|
776
|
+
*/
|
|
777
|
+
async deployProgram(options) {
|
|
778
|
+
if (!this.ownerSigner) {
|
|
779
|
+
throw new errors_1.Sequence0Error('ownerSigner or ownerPrivateKey is required to deploy programs. ' +
|
|
780
|
+
'Provide one in NetworkConfig.');
|
|
781
|
+
}
|
|
782
|
+
// Convert bytecode to hex string if ArrayBuffer
|
|
783
|
+
let bytecodeHex;
|
|
784
|
+
if (options.bytecode instanceof ArrayBuffer) {
|
|
785
|
+
const bytes = new Uint8Array(options.bytecode);
|
|
786
|
+
bytecodeHex = Array.from(bytes)
|
|
787
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
788
|
+
.join('');
|
|
789
|
+
}
|
|
790
|
+
else {
|
|
791
|
+
bytecodeHex = options.bytecode.startsWith('0x')
|
|
792
|
+
? options.bytecode.slice(2)
|
|
793
|
+
: options.bytecode;
|
|
794
|
+
}
|
|
795
|
+
const metadataUri = options.metadataUri || '';
|
|
796
|
+
const gasLimit = options.gasLimit ?? 10000000;
|
|
797
|
+
const memoryLimit = options.memoryLimit ?? 16;
|
|
798
|
+
// Build ownership proof for the deployment
|
|
799
|
+
const proof = await this.signOwnershipProof('program-deploy', 'deploy');
|
|
800
|
+
if (!proof) {
|
|
801
|
+
throw new errors_1.Sequence0Error('Failed to generate ownership proof for program deployment');
|
|
802
|
+
}
|
|
803
|
+
return this.withFailover(async (http) => {
|
|
804
|
+
const response = await http.post('/programs/deploy', {
|
|
805
|
+
bytecode: bytecodeHex,
|
|
806
|
+
metadata_uri: metadataUri,
|
|
807
|
+
gas_limit: gasLimit,
|
|
808
|
+
memory_limit: memoryLimit,
|
|
809
|
+
owner_signature: proof.owner_signature,
|
|
810
|
+
timestamp: proof.timestamp,
|
|
811
|
+
});
|
|
812
|
+
if (!response || typeof response.program_id !== 'string') {
|
|
813
|
+
throw new errors_1.Sequence0Error('Invalid response from /programs/deploy: missing program_id');
|
|
814
|
+
}
|
|
815
|
+
return response.program_id;
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
/**
|
|
819
|
+
* Attach a WASM program to a wallet.
|
|
820
|
+
*
|
|
821
|
+
* Only the wallet owner can attach programs. Once attached, the program
|
|
822
|
+
* runs on every sign request for this wallet -- the agent evaluates it
|
|
823
|
+
* in a sandboxed WASM environment and rejects the request if the program
|
|
824
|
+
* returns "deny".
|
|
825
|
+
*
|
|
826
|
+
* @param walletId - The wallet to attach the program to
|
|
827
|
+
* @param programId - The program ID (bytes32 hex) from deployProgram()
|
|
828
|
+
*
|
|
829
|
+
* @throws {Sequence0Error} If no ownerSigner is configured
|
|
830
|
+
* @throws {NetworkError} If the attach transaction fails
|
|
831
|
+
*
|
|
832
|
+
* @example
|
|
833
|
+
* ```typescript
|
|
834
|
+
* await s0.attachProgram('my-wallet', programId);
|
|
835
|
+
* ```
|
|
836
|
+
*/
|
|
837
|
+
async attachProgram(walletId, programId) {
|
|
838
|
+
(0, validation_1.validateWalletId)(walletId);
|
|
839
|
+
if (!programId || typeof programId !== 'string') {
|
|
840
|
+
throw new errors_1.Sequence0Error('programId must be a non-empty string');
|
|
841
|
+
}
|
|
842
|
+
const proof = await this.signOwnershipProof(walletId, 'attach-program');
|
|
843
|
+
if (!proof) {
|
|
844
|
+
throw new errors_1.Sequence0Error('ownerSigner or ownerPrivateKey is required to attach programs');
|
|
845
|
+
}
|
|
846
|
+
return this.withFailover(async (http) => {
|
|
847
|
+
await http.post('/programs/attach', {
|
|
848
|
+
wallet_id: walletId,
|
|
849
|
+
program_id: programId,
|
|
850
|
+
owner_signature: proof.owner_signature,
|
|
851
|
+
timestamp: proof.timestamp,
|
|
852
|
+
});
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
/**
|
|
856
|
+
* Detach a WASM program from a wallet.
|
|
857
|
+
*
|
|
858
|
+
* Only the wallet owner can detach programs. The program is no longer
|
|
859
|
+
* evaluated on sign requests for this wallet after detachment.
|
|
860
|
+
*
|
|
861
|
+
* @param walletId - The wallet to detach the program from
|
|
862
|
+
* @param programId - The program ID (bytes32 hex) to detach
|
|
863
|
+
*
|
|
864
|
+
* @throws {Sequence0Error} If no ownerSigner is configured
|
|
865
|
+
* @throws {NetworkError} If the detach transaction fails
|
|
866
|
+
*
|
|
867
|
+
* @example
|
|
868
|
+
* ```typescript
|
|
869
|
+
* await s0.detachProgram('my-wallet', programId);
|
|
870
|
+
* ```
|
|
871
|
+
*/
|
|
872
|
+
async detachProgram(walletId, programId) {
|
|
873
|
+
(0, validation_1.validateWalletId)(walletId);
|
|
874
|
+
if (!programId || typeof programId !== 'string') {
|
|
875
|
+
throw new errors_1.Sequence0Error('programId must be a non-empty string');
|
|
876
|
+
}
|
|
877
|
+
const proof = await this.signOwnershipProof(walletId, 'detach-program');
|
|
878
|
+
if (!proof) {
|
|
879
|
+
throw new errors_1.Sequence0Error('ownerSigner or ownerPrivateKey is required to detach programs');
|
|
880
|
+
}
|
|
881
|
+
return this.withFailover(async (http) => {
|
|
882
|
+
await http.post('/programs/detach', {
|
|
883
|
+
wallet_id: walletId,
|
|
884
|
+
program_id: programId,
|
|
885
|
+
owner_signature: proof.owner_signature,
|
|
886
|
+
timestamp: proof.timestamp,
|
|
887
|
+
});
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
/**
|
|
891
|
+
* Get all WASM programs attached to a wallet.
|
|
892
|
+
*
|
|
893
|
+
* @param walletId - The wallet to query
|
|
894
|
+
* @returns Array of program info objects
|
|
895
|
+
*
|
|
896
|
+
* @throws {NetworkError} If the agent is unreachable
|
|
897
|
+
*
|
|
898
|
+
* @example
|
|
899
|
+
* ```typescript
|
|
900
|
+
* const programs = await s0.getWalletPrograms('my-wallet');
|
|
901
|
+
* for (const p of programs) {
|
|
902
|
+
* console.log(`${p.programId}: active=${p.isActive}, gas=${p.gasLimit}`);
|
|
903
|
+
* }
|
|
904
|
+
* ```
|
|
905
|
+
*/
|
|
906
|
+
async getWalletPrograms(walletId) {
|
|
907
|
+
(0, validation_1.validateWalletId)(walletId);
|
|
908
|
+
return this.withFailover(async (http) => {
|
|
909
|
+
const response = await http.get(`/programs/wallet/${walletId}`);
|
|
910
|
+
if (!response || !Array.isArray(response.programs)) {
|
|
911
|
+
return [];
|
|
912
|
+
}
|
|
913
|
+
return response.programs.map((p) => ({
|
|
914
|
+
programId: p.program_id,
|
|
915
|
+
deployer: p.deployer,
|
|
916
|
+
createdAt: p.created_at,
|
|
917
|
+
isActive: p.is_active,
|
|
918
|
+
metadataUri: p.metadata_uri,
|
|
919
|
+
gasLimit: p.gas_limit,
|
|
920
|
+
memoryLimit: p.memory_limit,
|
|
921
|
+
}));
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
// ────────────────────────────────────────────────
|
|
925
|
+
// NEXUS: Atomic Cross-Chain Signing
|
|
926
|
+
// ────────────────────────────────────────────────
|
|
927
|
+
/**
|
|
928
|
+
* Sign multiple transactions across chains atomically (all-or-nothing).
|
|
929
|
+
*
|
|
930
|
+
* Submits a batch of signing operations to the agent network. The agents
|
|
931
|
+
* coordinate via a 2-phase commit protocol: either all operations produce
|
|
932
|
+
* valid signatures, or the entire batch is aborted and no signatures are
|
|
933
|
+
* released.
|
|
934
|
+
*
|
|
935
|
+
* This is essential for:
|
|
936
|
+
* - Cross-chain arbitrage (buy on chain A, sell on chain B)
|
|
937
|
+
* - Bridge transfers (lock on source, mint on destination)
|
|
938
|
+
* - Multi-leg DeFi strategies
|
|
939
|
+
*
|
|
940
|
+
* @param options - Atomic signing options with operations array
|
|
941
|
+
* @returns Result with all signatures (if committed) or error (if aborted)
|
|
942
|
+
*
|
|
943
|
+
* @throws {Sequence0Error} If no ownerSigner is configured or operations are empty
|
|
944
|
+
* @throws {TimeoutError} If the atomic signing times out
|
|
945
|
+
*
|
|
946
|
+
* @example
|
|
947
|
+
* ```typescript
|
|
948
|
+
* const result = await s0.signAtomic({
|
|
949
|
+
* operations: [
|
|
950
|
+
* { walletId: 'eth-wallet', chain: 'ethereum', message: '0x...' },
|
|
951
|
+
* { walletId: 'arb-wallet', chain: 'arbitrum', message: '0x...' },
|
|
952
|
+
* ],
|
|
953
|
+
* timeout: 60000,
|
|
954
|
+
* });
|
|
955
|
+
*
|
|
956
|
+
* if (result.status === 'committed') {
|
|
957
|
+
* for (const [reqId, sig] of result.signatures) {
|
|
958
|
+
* console.log(`${reqId}: ${sig}`);
|
|
959
|
+
* }
|
|
960
|
+
* } else {
|
|
961
|
+
* console.error('Atomic signing aborted:', result.error);
|
|
962
|
+
* }
|
|
963
|
+
* ```
|
|
964
|
+
*/
|
|
965
|
+
async signAtomic(options) {
|
|
966
|
+
if (!options.operations || options.operations.length === 0) {
|
|
967
|
+
throw new errors_1.Sequence0Error('operations array must not be empty');
|
|
968
|
+
}
|
|
969
|
+
// Validate all operations
|
|
970
|
+
for (const op of options.operations) {
|
|
971
|
+
(0, validation_1.validateWalletId)(op.walletId);
|
|
972
|
+
(0, validation_1.validateChain)(op.chain);
|
|
973
|
+
(0, validation_1.validateHexMessage)(op.message);
|
|
974
|
+
}
|
|
975
|
+
const timeout = options.timeout ?? 60000;
|
|
976
|
+
const deadlineBlocks = options.deadlineBlocks ?? 50;
|
|
977
|
+
// Build ownership proofs for all unique wallet IDs in the batch
|
|
978
|
+
const uniqueWalletIds = [...new Set(options.operations.map((op) => op.walletId))];
|
|
979
|
+
const proofs = {};
|
|
980
|
+
for (const walletId of uniqueWalletIds) {
|
|
981
|
+
const proof = await this.signOwnershipProof(walletId, 'atomic-sign');
|
|
982
|
+
if (!proof) {
|
|
983
|
+
throw new errors_1.Sequence0Error('ownerSigner or ownerPrivateKey is required for atomic signing. ' +
|
|
984
|
+
'Provide one in NetworkConfig.');
|
|
985
|
+
}
|
|
986
|
+
proofs[walletId] = proof;
|
|
987
|
+
}
|
|
988
|
+
// Build the request payload
|
|
989
|
+
const operationsPayload = options.operations.map((op) => ({
|
|
990
|
+
wallet_id: op.walletId,
|
|
991
|
+
chain: op.chain,
|
|
992
|
+
message: op.message,
|
|
993
|
+
owner_signature: proofs[op.walletId].owner_signature,
|
|
994
|
+
timestamp: proofs[op.walletId].timestamp,
|
|
995
|
+
}));
|
|
996
|
+
// Submit the atomic signing request
|
|
997
|
+
const submitResponse = await this.withFailover(async (http) => {
|
|
998
|
+
return http.post('/sign-atomic', {
|
|
999
|
+
operations: operationsPayload,
|
|
1000
|
+
deadline_blocks: deadlineBlocks,
|
|
1001
|
+
});
|
|
1002
|
+
});
|
|
1003
|
+
if (!submitResponse || typeof submitResponse.manifest_id !== 'string') {
|
|
1004
|
+
throw new errors_1.Sequence0Error('Invalid response from /sign-atomic: missing manifest_id');
|
|
1005
|
+
}
|
|
1006
|
+
const manifestId = submitResponse.manifest_id;
|
|
1007
|
+
// Poll for completion
|
|
1008
|
+
const deadline = Date.now() + timeout;
|
|
1009
|
+
while (Date.now() < deadline) {
|
|
1010
|
+
const result = await this.withFailover(async (http) => {
|
|
1011
|
+
return http.get(`/sign-atomic/${manifestId}`);
|
|
1012
|
+
});
|
|
1013
|
+
if (result.status === 'committed') {
|
|
1014
|
+
const signatures = new Map();
|
|
1015
|
+
if (result.signatures) {
|
|
1016
|
+
for (const [reqId, sig] of Object.entries(result.signatures)) {
|
|
1017
|
+
signatures.set(reqId, sig);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
return {
|
|
1021
|
+
manifestId,
|
|
1022
|
+
status: 'committed',
|
|
1023
|
+
signatures,
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
if (result.status === 'aborted') {
|
|
1027
|
+
return {
|
|
1028
|
+
manifestId,
|
|
1029
|
+
status: 'aborted',
|
|
1030
|
+
signatures: new Map(),
|
|
1031
|
+
error: result.error || 'Atomic signing batch aborted by the agent network',
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
1034
|
+
// Still pending -- wait and retry
|
|
1035
|
+
await sleep(1000);
|
|
1036
|
+
}
|
|
1037
|
+
throw new errors_1.TimeoutError(`Atomic signing manifest ${manifestId} timed out after ${timeout}ms`);
|
|
1038
|
+
}
|
|
1039
|
+
// ────────────────────────────────────────────────
|
|
1040
|
+
// MERIDIAN: Settlement
|
|
1041
|
+
// ────────────────────────────────────────────────
|
|
1042
|
+
/**
|
|
1043
|
+
* Get a SettlementClient for MERIDIAN Universal Settlement Network operations.
|
|
1044
|
+
*
|
|
1045
|
+
* The settlement client provides methods to submit payment intents,
|
|
1046
|
+
* query cycle status, and retrieve settlement history. Intents are
|
|
1047
|
+
* batched and netted off-chain, then settled atomically via NEXUS.
|
|
1048
|
+
*
|
|
1049
|
+
* @returns A SettlementClient instance bound to the current agent
|
|
1050
|
+
*
|
|
1051
|
+
* @example
|
|
1052
|
+
* ```typescript
|
|
1053
|
+
* const settlement = s0.getSettlementClient();
|
|
1054
|
+
*
|
|
1055
|
+
* const { intentHash, cycleId } = await settlement.submitIntent(
|
|
1056
|
+
* {
|
|
1057
|
+
* senderWalletId: 'alice-wallet',
|
|
1058
|
+
* recipientWalletId: 'bob-wallet',
|
|
1059
|
+
* chain: 'ethereum',
|
|
1060
|
+
* amount: '1000000000000000000',
|
|
1061
|
+
* },
|
|
1062
|
+
* ownerSignature,
|
|
1063
|
+
* timestamp,
|
|
1064
|
+
* );
|
|
1065
|
+
*
|
|
1066
|
+
* const cycle = await settlement.getCurrentCycle();
|
|
1067
|
+
* console.log(`Cycle ${cycle.cycleId}: ${cycle.status}`);
|
|
1068
|
+
* ```
|
|
1069
|
+
*/
|
|
1070
|
+
async getSettlementClient() {
|
|
1071
|
+
const http = await this.getHttp();
|
|
1072
|
+
return new settlement_1.SettlementClient(this.resolvedAgentUrl, http);
|
|
1073
|
+
}
|
|
1074
|
+
// ────────────────────────────────────────────────
|
|
1075
|
+
// KEYSTONE: Universal Account
|
|
1076
|
+
// ────────────────────────────────────────────────
|
|
1077
|
+
/**
|
|
1078
|
+
* Get a UniversalAccountClient bound to a healthy agent.
|
|
1079
|
+
*
|
|
1080
|
+
* The client communicates directly with the agent's `/universal/*`
|
|
1081
|
+
* endpoints for account creation, balance queries, and sends.
|
|
1082
|
+
*
|
|
1083
|
+
* @returns A UniversalAccountClient instance
|
|
1084
|
+
*
|
|
1085
|
+
* @example
|
|
1086
|
+
* ```typescript
|
|
1087
|
+
* const ua = await s0.getUniversalAccountClient();
|
|
1088
|
+
*
|
|
1089
|
+
* const balance = await ua.getUnifiedBalance('ua-abc123');
|
|
1090
|
+
* console.log('Chains:', balance.totalChains);
|
|
1091
|
+
*
|
|
1092
|
+
* const route = await ua.previewRoute({
|
|
1093
|
+
* accountId: 'ua-abc123',
|
|
1094
|
+
* to: '0x...',
|
|
1095
|
+
* amount: '1.0',
|
|
1096
|
+
* token: 'ETH',
|
|
1097
|
+
* });
|
|
1098
|
+
* console.log(`Route: ${route.sourceChain} -> ${route.destinationChain}`);
|
|
1099
|
+
* ```
|
|
1100
|
+
*/
|
|
1101
|
+
async getUniversalAccountClient() {
|
|
1102
|
+
await this.getHttp(); // Ensure agent URL is resolved
|
|
1103
|
+
return new universal_account_1.UniversalAccountClient(this.resolvedAgentUrl);
|
|
1104
|
+
}
|
|
1105
|
+
/**
|
|
1106
|
+
* Create a new universal account — one identity across all 81 chains.
|
|
1107
|
+
*
|
|
1108
|
+
* This is a convenience method that discovers a healthy agent,
|
|
1109
|
+
* creates a UniversalAccountClient, and calls createAccount.
|
|
1110
|
+
* For repeated operations, prefer `getUniversalAccountClient()`
|
|
1111
|
+
* and reuse the client.
|
|
1112
|
+
*
|
|
1113
|
+
* @param options - Account creation options
|
|
1114
|
+
* @returns The created account info with all chain addresses
|
|
1115
|
+
*
|
|
1116
|
+
* @example
|
|
1117
|
+
* ```typescript
|
|
1118
|
+
* const account = await s0.createUniversalAccount({
|
|
1119
|
+
* ownerSignature: '0x...',
|
|
1120
|
+
* timestamp: Date.now(),
|
|
1121
|
+
* });
|
|
1122
|
+
*
|
|
1123
|
+
* console.log('Account ID:', account.accountId);
|
|
1124
|
+
* console.log('Ethereum:', account.chainAddresses.ethereum.address);
|
|
1125
|
+
* console.log('Bitcoin:', account.chainAddresses.bitcoin.address);
|
|
1126
|
+
* console.log('Solana:', account.chainAddresses.solana.address);
|
|
1127
|
+
* ```
|
|
1128
|
+
*
|
|
1129
|
+
* @throws {Sequence0Error} If the creation parameters are invalid
|
|
1130
|
+
* @throws {NetworkError} If no healthy agent is available
|
|
1131
|
+
*/
|
|
1132
|
+
async createUniversalAccount(options) {
|
|
1133
|
+
const client = await this.getUniversalAccountClient();
|
|
1134
|
+
return client.createAccount(options);
|
|
1135
|
+
}
|
|
1136
|
+
// ────────────────────────────────────────────────
|
|
726
1137
|
// WebSocket Events
|
|
727
1138
|
// ────────────────────────────────────────────────
|
|
728
1139
|
/**
|
|
@@ -870,6 +1281,127 @@ class Sequence0 {
|
|
|
870
1281
|
const random = secureRandom().toString(36).slice(2, 8);
|
|
871
1282
|
return `s0-${timestamp}-${random}`;
|
|
872
1283
|
}
|
|
1284
|
+
// ────────────────────────────────────────────────
|
|
1285
|
+
// AEGIS: Sovereign Agency Protocol — Delegation
|
|
1286
|
+
// ────────────────────────────────────────────────
|
|
1287
|
+
/**
|
|
1288
|
+
* Create a delegation grant for a wallet (owner only).
|
|
1289
|
+
*/
|
|
1290
|
+
async createDelegation(walletId, options) {
|
|
1291
|
+
(0, validation_1.validateWalletId)(walletId);
|
|
1292
|
+
const proof = await this.signOwnershipProof(walletId, 'delegate');
|
|
1293
|
+
if (!proof) {
|
|
1294
|
+
throw new errors_1.Sequence0Error('ownerSigner or ownerPrivateKey is required to create delegation grants');
|
|
1295
|
+
}
|
|
1296
|
+
return this.withFailover(async (http) => {
|
|
1297
|
+
return http.post('/delegations', {
|
|
1298
|
+
wallet_id: walletId,
|
|
1299
|
+
delegate: options.to,
|
|
1300
|
+
chains: options.chains,
|
|
1301
|
+
wasm_policy_id: options.wasmPolicyId,
|
|
1302
|
+
constraints: options.constraints,
|
|
1303
|
+
valid_from: options.validFrom || new Date().toISOString(),
|
|
1304
|
+
valid_until: options.validUntil,
|
|
1305
|
+
sub_delegation: options.subDelegation ?? false,
|
|
1306
|
+
max_sub_depth: options.maxSubDepth ?? 0,
|
|
1307
|
+
activation: options.activation,
|
|
1308
|
+
owner_signature: proof.owner_signature,
|
|
1309
|
+
timestamp: proof.timestamp,
|
|
1310
|
+
});
|
|
1311
|
+
});
|
|
1312
|
+
}
|
|
1313
|
+
/**
|
|
1314
|
+
* Create a sub-delegation from an existing delegation grant.
|
|
1315
|
+
*/
|
|
1316
|
+
async createSubDelegation(walletId, options) {
|
|
1317
|
+
(0, validation_1.validateWalletId)(walletId);
|
|
1318
|
+
const signerKey = options.signerKey.startsWith('0x') ? options.signerKey : '0x' + options.signerKey;
|
|
1319
|
+
const delegateSigningKey = new ethers_1.SigningKey(signerKey);
|
|
1320
|
+
const timestamp = Math.floor(Date.now() / 1000);
|
|
1321
|
+
const network = this.config.network;
|
|
1322
|
+
const chainId = eip712_1.SEQUENCE0_CHAIN_IDS[network] || eip712_1.SEQUENCE0_CHAIN_IDS.mainnet;
|
|
1323
|
+
const walletFactory = eip712_1.WALLET_FACTORY_ADDRESSES[network] || eip712_1.WALLET_FACTORY_ADDRESSES.mainnet;
|
|
1324
|
+
const digest = (0, eip712_1.computeEip712Digest)(walletId, 'sub-delegate', timestamp, chainId, walletFactory);
|
|
1325
|
+
const sig = delegateSigningKey.sign(digest);
|
|
1326
|
+
const v = sig.v === 27 ? '1b' : '1c';
|
|
1327
|
+
const delegateSignature = '0x' + sig.r.slice(2) + sig.s.slice(2) + v;
|
|
1328
|
+
return this.withFailover(async (http) => {
|
|
1329
|
+
return http.post('/delegations/sub', {
|
|
1330
|
+
wallet_id: walletId,
|
|
1331
|
+
parent_grant_id: options.parentGrantId,
|
|
1332
|
+
delegate: options.to,
|
|
1333
|
+
chains: options.chains,
|
|
1334
|
+
constraints: options.constraints,
|
|
1335
|
+
valid_from: options.validFrom || new Date().toISOString(),
|
|
1336
|
+
valid_until: options.validUntil,
|
|
1337
|
+
sub_delegation: options.subDelegation ?? false,
|
|
1338
|
+
max_sub_depth: options.maxSubDepth ?? 0,
|
|
1339
|
+
activation: options.activation,
|
|
1340
|
+
delegate_signature: delegateSignature,
|
|
1341
|
+
timestamp,
|
|
1342
|
+
});
|
|
1343
|
+
});
|
|
1344
|
+
}
|
|
1345
|
+
/**
|
|
1346
|
+
* Revoke a delegation grant (cascading to all sub-grants).
|
|
1347
|
+
*/
|
|
1348
|
+
async revokeDelegation(walletId, delegationId) {
|
|
1349
|
+
(0, validation_1.validateWalletId)(walletId);
|
|
1350
|
+
const proof = await this.signOwnershipProof(walletId, 'revoke');
|
|
1351
|
+
if (!proof) {
|
|
1352
|
+
throw new errors_1.Sequence0Error('ownerSigner or ownerPrivateKey is required to revoke delegation grants');
|
|
1353
|
+
}
|
|
1354
|
+
await this.withFailover(async (http) => {
|
|
1355
|
+
return http.post(`/delegations/${delegationId}/revoke`, {
|
|
1356
|
+
owner_signature: proof.owner_signature,
|
|
1357
|
+
timestamp: proof.timestamp,
|
|
1358
|
+
});
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
1361
|
+
/**
|
|
1362
|
+
* List all delegation grants for a wallet.
|
|
1363
|
+
*/
|
|
1364
|
+
async listDelegations(walletId) {
|
|
1365
|
+
(0, validation_1.validateWalletId)(walletId);
|
|
1366
|
+
return this.withFailover(async (http) => {
|
|
1367
|
+
const res = await http.get(`/delegations?wallet_id=${encodeURIComponent(walletId)}`);
|
|
1368
|
+
return res.delegations;
|
|
1369
|
+
});
|
|
1370
|
+
}
|
|
1371
|
+
/**
|
|
1372
|
+
* Get the delegation tree for a wallet.
|
|
1373
|
+
*/
|
|
1374
|
+
async getDelegationTree(walletId) {
|
|
1375
|
+
(0, validation_1.validateWalletId)(walletId);
|
|
1376
|
+
return this.withFailover(async (http) => {
|
|
1377
|
+
return http.get(`/delegations/tree?wallet_id=${encodeURIComponent(walletId)}`);
|
|
1378
|
+
});
|
|
1379
|
+
}
|
|
1380
|
+
/**
|
|
1381
|
+
* Send heartbeat for dead-man's switch delegation grants.
|
|
1382
|
+
*/
|
|
1383
|
+
async heartbeat(walletId) {
|
|
1384
|
+
(0, validation_1.validateWalletId)(walletId);
|
|
1385
|
+
const proof = await this.signOwnershipProof(walletId, 'heartbeat');
|
|
1386
|
+
if (!proof) {
|
|
1387
|
+
throw new errors_1.Sequence0Error('ownerSigner or ownerPrivateKey is required for heartbeat');
|
|
1388
|
+
}
|
|
1389
|
+
await this.withFailover(async (http) => {
|
|
1390
|
+
return http.post(`/delegations/heartbeat`, {
|
|
1391
|
+
wallet_id: walletId,
|
|
1392
|
+
owner_signature: proof.owner_signature,
|
|
1393
|
+
timestamp: proof.timestamp,
|
|
1394
|
+
});
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
/**
|
|
1398
|
+
* Check remaining authority status of a delegation.
|
|
1399
|
+
*/
|
|
1400
|
+
async checkAuthority(delegationId) {
|
|
1401
|
+
return this.withFailover(async (http) => {
|
|
1402
|
+
return http.get(`/delegations/${delegationId}/status`);
|
|
1403
|
+
});
|
|
1404
|
+
}
|
|
873
1405
|
}
|
|
874
1406
|
exports.Sequence0 = Sequence0;
|
|
875
1407
|
function sleep(ms) {
|