emblem-vault-sdk 2.9.0 → 2.9.2

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/docs/index.html CHANGED
@@ -122,7 +122,8 @@
122
122
  let contract = window.curatedContracts[index];
123
123
  let template = contract.generateCreateTemplate(contract)
124
124
  template.chainId = 1
125
- template.toAddress = document.getElementById('ethAddress').value;
125
+ let toAddr = document.getElementById('toAddress').value;
126
+ template.toAddress = toAddr ? toAddr : document.getElementById('ethAddress').value;
126
127
  template.fromAddress = document.getElementById('ethAddress').value;
127
128
  window.contract = contract;
128
129
  window.template = template;
@@ -204,6 +205,8 @@
204
205
  </script>
205
206
  <input type="text" id="ethAddress" placeholder="Enter ETH Address" oninput="localStorage.setItem('ethAddress', this.value)" value="">
206
207
 
208
+ <input type="text" id="toAddress" placeholder="To Address (optional)" oninput="localStorage.setItem('toAddress', this.value)" value="">
209
+
207
210
  <input type="checkbox" id="hideNotMintableCheckbox" checked onchange="generateDropdown(window.curatedContracts)">
208
211
  <label for="hideNotMintableCheckbox">Hide Not Mintable</label>
209
212
 
@@ -243,6 +246,9 @@
243
246
  <a href="steps.html" target="_blank">Full Create / Mint : Demo</a>
244
247
  </div>
245
248
 
246
- <script>document.getElementById('ethAddress').value = localStorage.getItem('ethAddress');</script>
249
+ <script>
250
+ document.getElementById('ethAddress').value = localStorage.getItem('ethAddress');
251
+ document.getElementById('toAddress').value = localStorage.getItem('toAddress');
252
+ </script>
247
253
  </body>
248
254
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emblem-vault-sdk",
3
- "version": "2.9.0",
3
+ "version": "2.9.2",
4
4
  "description": "Emblem Vault Software Development Kit",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -12,7 +12,7 @@
12
12
  "test:browser": "JEST_ENV=browser jest",
13
13
  "test:all": "npm run test:node && npm run test:browser",
14
14
  "build": "tsc",
15
- "postbuild": "node ./script/version.js && mv dist/index.d.ts types/index.d.ts && mv dist/types.d.ts types/types.d.ts && mv dist/utils.d.ts types/utils.d.ts && mv dist/derive.d.ts types/derive.d.ts",
15
+ "postbuild": "node ./script/version.js && mv dist/index.d.ts types/index.d.ts && mv dist/types.d.ts types/types.d.ts && mv dist/utils.d.ts types/utils.d.ts && mv dist/derive.d.ts types/derive.d.ts && mv dist/constants.d.ts types/constants.d.ts && mv dist/evm-operations.d.ts types/evm-operations.d.ts && mv dist/signing-messages.d.ts types/signing-messages.d.ts && mv dist/vault-utils.d.ts types/vault-utils.d.ts",
16
16
  "bundle": "npm run build && browserify dist/index.js -o dist/bundle.js && cp dist/bundle.js docs/bundle.js",
17
17
  "watch": "onchange 'src/*.ts' -- npm run bundle"
18
18
  },
@@ -24,6 +24,7 @@
24
24
  "@types/crypto-js": "^4.2.2",
25
25
  "@types/jest": "^29.5.11",
26
26
  "browserify": "^17.0.0",
27
+ "esmify": "^2.1.1",
27
28
  "jest": "^29.7.0",
28
29
  "jest-environment-jsdom": "^29.7.0",
29
30
  "jest-puppeteer": "^9.0.2",
@@ -44,6 +45,7 @@
44
45
  "bitcore-mnemonic": "^10.0.23",
45
46
  "crypto-js": "^4.2.0",
46
47
  "ethereumjs-util": "^7.1.5",
48
+ "ethers": "^5.7.2",
47
49
  "install": "^0.13.0",
48
50
  "npm": "^10.4.0",
49
51
  "sats-connect": "^1.4.1",
@@ -0,0 +1,47 @@
1
+ // ============================================================================
2
+ // Supported Chains
3
+ // ============================================================================
4
+
5
+ export const ETHEREUM_MAINNET_CHAIN_ID = 1;
6
+ export const POLYGON_MAINNET_CHAIN_ID = 137;
7
+ export const SOLANA_CHAIN_IDENTIFIER = 'solana';
8
+
9
+ export type ChainType = 'evm' | 'solana';
10
+
11
+ export interface ChainConfig {
12
+ type: ChainType;
13
+ name: string;
14
+ handlerContract?: string;
15
+ unvaultingContract?: string;
16
+ }
17
+
18
+ export const SUPPORTED_CHAINS: Record<number | string, ChainConfig> = {
19
+ [ETHEREUM_MAINNET_CHAIN_ID]: {
20
+ type: 'evm',
21
+ name: 'Ethereum Mainnet',
22
+ handlerContract: '0x23859b51117dbFBcdEf5b757028B18d7759a4460',
23
+ unvaultingContract: '0x214C964bBd3640971E111d3a994CbB89b296a9ad',
24
+ },
25
+ [POLYGON_MAINNET_CHAIN_ID]: {
26
+ type: 'evm',
27
+ name: 'Polygon Mainnet',
28
+ handlerContract: '0x23859b51117dbFBcdEf5b757028B18d7759a4460',
29
+ unvaultingContract: '0x214C964bBd3640971E111d3a994CbB89b296a9ad',
30
+ },
31
+ };
32
+
33
+ // ============================================================================
34
+ // Contract Addresses (default to Ethereum mainnet)
35
+ // ============================================================================
36
+
37
+ export const HANDLER_CONTRACT_ADDRESS = '0x23859b51117dbFBcdEf5b757028B18d7759a4460';
38
+ export const UNVAULTING_DIAMOND_ADDRESS = '0x214C964bBd3640971E111d3a994CbB89b296a9ad';
39
+ export const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
40
+
41
+ // ============================================================================
42
+ // API Endpoints
43
+ // ============================================================================
44
+
45
+ export const EMBLEM_API_V2 = 'https://v2.emblemvault.io';
46
+ export const EMBLEM_API_2 = 'https://api2.emblemvault.io';
47
+ export const TORUS_SIGNER_API = 'https://tor-us-signer-coval.vercel.app';
@@ -668143,7 +668143,7 @@
668143
668143
  "price": 1040.9323103174047,
668144
668144
  "lastPrice": 1314.8618656640904
668145
668145
  },
668146
- "video": "https://arweave.net/Fb7BMNWJQwNCrRxdw_dbMC01t6iSVUytBtg5LziOOlI/2o51ir_video.mp4\\",
668146
+ "video": "https://arweave.net/Fb7BMNWJQwNCrRxdw_dbMC01t6iSVUytBtg5LziOOlI/2o51ir_video.mp4",
668147
668147
  "projectProtocol": "Counterparty"
668148
668148
  },
668149
668149
  "DGAPEPE": {
@@ -0,0 +1,386 @@
1
+ import type {
2
+ EvmSigner,
3
+ EmblemVaultClient,
4
+ ProgressCallback,
5
+ MintResult,
6
+ ClaimResult,
7
+ RemoteMintSignature,
8
+ RemoteUnvaultSignature,
9
+ MetaData,
10
+ SdkContext,
11
+ } from './types';
12
+
13
+ import {
14
+ ZERO_ADDRESS,
15
+ EMBLEM_API_2,
16
+ TORUS_SIGNER_API,
17
+ } from './constants';
18
+
19
+ import {
20
+ buildMintMessage,
21
+ buildClaimMessage,
22
+ buildUnvaultMessage,
23
+ buildDeleteMessage,
24
+ } from './signing-messages';
25
+
26
+ import {
27
+ getHandlerContractAddress,
28
+ getUnvaultingContractAddress,
29
+ } from './vault-utils';
30
+
31
+ import { fetchData, parseBigIntValue } from './utils';
32
+
33
+ const EVM_RPC_URLS: Record<number, string> = {
34
+ 1: 'https://eth.llamarpc.com',
35
+ 137: 'https://polygon-rpc.com',
36
+ };
37
+
38
+ function getEvmRpcUrl(chainId: number): string {
39
+ return EVM_RPC_URLS[chainId] || EVM_RPC_URLS[1];
40
+ }
41
+
42
+ export async function performMintEvm(
43
+ ctx: SdkContext,
44
+ client: EmblemVaultClient,
45
+ tokenId: string,
46
+ chainId: number,
47
+ callback?: ProgressCallback
48
+ ): Promise<MintResult> {
49
+ callback?.('Initializing EVM signer...');
50
+ const { ethers } = await import('ethers');
51
+ const provider = new ethers.providers.JsonRpcProvider(getEvmRpcUrl(chainId));
52
+ const wallet = await client.toEthersWallet(provider);
53
+ wallet.setChainId?.(chainId);
54
+
55
+ callback?.('Signing mint request...');
56
+ const mintMessage = buildMintMessage(tokenId);
57
+ const mintRequestSig = await wallet.signMessage(mintMessage);
58
+
59
+ callback?.('Getting remote mint signature...');
60
+ const remoteMintSig = await requestRemoteMintSignature(ctx, tokenId, mintRequestSig, chainId);
61
+
62
+ callback?.('Submitting mint transaction...');
63
+ const txHash = await submitMintTransaction(wallet, remoteMintSig, chainId, callback);
64
+
65
+ callback?.('Mint complete!', { txHash });
66
+ return { txHash, tokenId, chainId };
67
+ }
68
+
69
+ export async function performClaimEvm(
70
+ ctx: SdkContext,
71
+ client: EmblemVaultClient,
72
+ tokenId: string,
73
+ chainId: number,
74
+ metadata: MetaData,
75
+ claimIdentifier: string,
76
+ vaultIsV2: boolean,
77
+ needsOnChainUnvault: boolean,
78
+ callback?: ProgressCallback
79
+ ): Promise<ClaimResult> {
80
+ callback?.('Initializing EVM signer...');
81
+ const { ethers } = await import('ethers');
82
+ const provider = new ethers.providers.JsonRpcProvider(getEvmRpcUrl(chainId));
83
+ const wallet = await client.toEthersWallet(provider);
84
+ wallet.setChainId?.(chainId);
85
+
86
+ // Determine if vault needs on-chain claim/unvault before getting keys
87
+ // For minted vaults (live=true, status=unclaimed), we must claim on-chain first
88
+ const isMinted = metadata.live === true || metadata.status === 'unclaimed';
89
+ const isAlreadyClaimed = metadata.status === 'claimed' || Boolean(metadata.claimedBy);
90
+
91
+ if (isMinted && !isAlreadyClaimed) {
92
+ if (needsOnChainUnvault) {
93
+ // V2 vault: use unvaultWithSignedPrice
94
+ await performOnChainUnvault(
95
+ ctx,
96
+ wallet,
97
+ tokenId,
98
+ claimIdentifier,
99
+ metadata.collectionAddress,
100
+ chainId,
101
+ callback
102
+ );
103
+ } else {
104
+ // Non-V2 vault: use handler's claim function
105
+ const targetContractAddress = metadata.targetContract?.[chainId] || metadata.collectionAddress;
106
+ if (targetContractAddress) {
107
+ callback?.('Performing on-chain claim...');
108
+ await performLegacyClaim(wallet, targetContractAddress, claimIdentifier, chainId, callback);
109
+ }
110
+ }
111
+ }
112
+
113
+ callback?.('Signing claim message...');
114
+ const claimMessage = buildClaimMessage(claimIdentifier, vaultIsV2);
115
+ const signature = await wallet.signMessage(claimMessage);
116
+
117
+ callback?.('Requesting claim token...');
118
+ const jwt = await requestClaimToken(tokenId, signature, chainId);
119
+
120
+ callback?.('Requesting remote key...');
121
+ const decryptionKeys = await ctx.requestRemoteKey(tokenId, jwt, callback);
122
+ if (!decryptionKeys) {
123
+ throw new Error('Failed to get decryption key');
124
+ }
125
+
126
+ callback?.('Decrypting vault keys...');
127
+ return await ctx.decryptVaultKeys(tokenId, decryptionKeys, callback);
128
+ }
129
+
130
+ export async function deleteVaultEvm(
131
+ client: EmblemVaultClient,
132
+ tokenId: string,
133
+ chainId: number,
134
+ callback?: ProgressCallback
135
+ ): Promise<boolean> {
136
+ callback?.('Initializing EVM signer...');
137
+ const wallet = await client.toEthersWallet(null);
138
+ wallet.setChainId?.(chainId);
139
+
140
+ callback?.('Signing delete message...');
141
+ const deleteMessage = buildDeleteMessage(tokenId);
142
+ const signature = await wallet.signMessage(deleteMessage);
143
+
144
+ callback?.('Deleting vault...');
145
+ const response = await fetch(`${EMBLEM_API_2}/v2/delete`, {
146
+ method: 'POST',
147
+ headers: {
148
+ 'Content-Type': 'application/json',
149
+ service: 'evmetadata',
150
+ },
151
+ body: JSON.stringify({
152
+ tokenId,
153
+ signature,
154
+ chainId: chainId.toString(),
155
+ }),
156
+ });
157
+
158
+ if (!response.ok) {
159
+ const errorData = await response.json().catch(() => ({}));
160
+ throw new Error(errorData.message || 'Failed to delete vault');
161
+ }
162
+
163
+ callback?.('Vault deleted successfully');
164
+ return true;
165
+ }
166
+
167
+ async function requestRemoteMintSignature(
168
+ ctx: SdkContext,
169
+ tokenId: string,
170
+ signature: string,
171
+ chainId: number
172
+ ): Promise<RemoteMintSignature> {
173
+ const url = `${ctx.baseUrl}/mint-curated`;
174
+ const remoteMintResponse = await fetchData(
175
+ url,
176
+ ctx.apiKey,
177
+ 'POST',
178
+ {
179
+ method: 'buyWithSignedPrice',
180
+ tokenId,
181
+ signature,
182
+ chainId: chainId.toString(),
183
+ }
184
+ );
185
+
186
+ if (remoteMintResponse.error) {
187
+ throw new Error(remoteMintResponse.error);
188
+ }
189
+
190
+ return remoteMintResponse as RemoteMintSignature;
191
+ }
192
+
193
+ async function submitMintTransaction(
194
+ wallet: EvmSigner,
195
+ remoteMintSig: RemoteMintSignature,
196
+ chainId: number,
197
+ callback?: ProgressCallback
198
+ ): Promise<string> {
199
+ const { ethers } = await import('ethers');
200
+
201
+ const handlerAddress = getHandlerContractAddress(chainId);
202
+ const priceBigInt = parseBigIntValue(remoteMintSig._price);
203
+
204
+ const iface = new ethers.utils.Interface([
205
+ 'function buyWithSignedPrice(address _nftAddress, address _payment, uint256 _price, address _to, uint256 _tokenId, uint256 _nonce, bytes _signature, bytes serialNumber, uint256 _amount) payable'
206
+ ]);
207
+
208
+ const data = iface.encodeFunctionData('buyWithSignedPrice', [
209
+ remoteMintSig._nftAddress,
210
+ ZERO_ADDRESS,
211
+ priceBigInt,
212
+ remoteMintSig._to,
213
+ parseBigIntValue(remoteMintSig._tokenId),
214
+ parseBigIntValue(remoteMintSig._nonce),
215
+ remoteMintSig._signature,
216
+ remoteMintSig.serialNumber,
217
+ BigInt(1),
218
+ ]);
219
+
220
+ const tx = await wallet.sendTransaction({
221
+ to: handlerAddress,
222
+ data,
223
+ value: priceBigInt,
224
+ });
225
+
226
+ callback?.('Waiting for confirmation...', { txHash: tx.hash });
227
+ await tx.wait();
228
+
229
+ return tx.hash;
230
+ }
231
+
232
+ async function performOnChainUnvault(
233
+ ctx: SdkContext,
234
+ wallet: EvmSigner,
235
+ tokenId: string,
236
+ claimIdentifier: string,
237
+ nftAddress: string | undefined,
238
+ chainId: number,
239
+ callback?: ProgressCallback
240
+ ): Promise<void> {
241
+ callback?.('Signing unvault request...');
242
+ // Sign with tokenId to match server expectation (server verifies "Unvault: " + req.body.tokenId)
243
+ const unvaultMessage = buildUnvaultMessage(tokenId);
244
+ const unvaultSignature = await wallet.signMessage(unvaultMessage);
245
+
246
+ callback?.('Requesting remote unvault signature...');
247
+ const remoteUnvaultSig = await requestRemoteUnvaultSignature(ctx, tokenId, unvaultSignature, chainId);
248
+
249
+ callback?.('Submitting on-chain unvault transaction...');
250
+ await submitUnvaultTransaction(wallet, remoteUnvaultSig, nftAddress, chainId, callback);
251
+
252
+ callback?.('On-chain unvault complete, retrieving keys...');
253
+ }
254
+
255
+ /**
256
+ * Perform legacy claim by calling the handler contract's claim function
257
+ * This is for non-V2 vaults that don't use signed price unvaulting
258
+ */
259
+ async function performLegacyClaim(
260
+ wallet: EvmSigner,
261
+ targetContractAddress: string,
262
+ tokenId: string,
263
+ chainId: number,
264
+ callback?: ProgressCallback
265
+ ): Promise<void> {
266
+ const { ethers } = await import('ethers');
267
+
268
+ // Handler contract ABI for claim function
269
+ const HANDLER_CLAIM_ABI = [
270
+ 'function claim(address _nftAddress, uint256 _tokenId) external'
271
+ ];
272
+
273
+ const handlerAddress = getHandlerContractAddress(chainId);
274
+ const iface = new ethers.utils.Interface(HANDLER_CLAIM_ABI);
275
+
276
+ const data = iface.encodeFunctionData('claim', [
277
+ targetContractAddress,
278
+ BigInt(tokenId),
279
+ ]);
280
+
281
+ callback?.('Submitting claim transaction...');
282
+ const tx = await wallet.sendTransaction({
283
+ to: handlerAddress,
284
+ data,
285
+ });
286
+
287
+ callback?.('Waiting for claim confirmation...', { txHash: tx.hash });
288
+ await tx.wait();
289
+
290
+ callback?.('On-chain claim complete!');
291
+ }
292
+
293
+ async function requestRemoteUnvaultSignature(
294
+ ctx: SdkContext,
295
+ tokenId: string,
296
+ signature: string,
297
+ chainId: number
298
+ ): Promise<RemoteUnvaultSignature> {
299
+ const response = await fetch(`${ctx.baseUrl}/unvault-curated`, {
300
+ method: 'POST',
301
+ headers: { 'Content-Type': 'application/json' },
302
+ body: JSON.stringify({
303
+ method: 'unvaultWithSignedPrice',
304
+ tokenId,
305
+ signature,
306
+ chainId: chainId.toString(),
307
+ }),
308
+ });
309
+
310
+ const remoteUnvaultSig = await response.json() as RemoteUnvaultSignature;
311
+
312
+ if (!remoteUnvaultSig?.success) {
313
+ throw new Error(
314
+ remoteUnvaultSig?.msg || remoteUnvaultSig?.err || 'Failed to get remote unvault signature'
315
+ );
316
+ }
317
+
318
+ return remoteUnvaultSig;
319
+ }
320
+
321
+ async function submitUnvaultTransaction(
322
+ wallet: EvmSigner,
323
+ remoteUnvaultSig: RemoteUnvaultSignature,
324
+ nftAddress: string | undefined,
325
+ chainId: number,
326
+ callback?: ProgressCallback
327
+ ): Promise<string> {
328
+ const { ethers } = await import('ethers');
329
+
330
+ const unvaultingAddress = getUnvaultingContractAddress(chainId);
331
+ const nftAddressToUse = nftAddress || remoteUnvaultSig._nftAddress;
332
+ const tokenId = parseBigIntValue(remoteUnvaultSig._tokenId);
333
+ const nonce = parseBigIntValue(remoteUnvaultSig._nonce);
334
+ const price = parseBigIntValue(remoteUnvaultSig._price);
335
+ const timestamp = parseBigIntValue(remoteUnvaultSig._timestamp);
336
+
337
+ const iface = new ethers.utils.Interface([
338
+ 'function unvaultWithSignedPrice(address _nftAddress, uint256 _tokenId, uint256 _nonce, address _payment, uint256 _price, bytes _signature, uint256 _timestamp) payable'
339
+ ]);
340
+
341
+ const data = iface.encodeFunctionData('unvaultWithSignedPrice', [
342
+ nftAddressToUse,
343
+ tokenId,
344
+ nonce,
345
+ ZERO_ADDRESS,
346
+ price,
347
+ remoteUnvaultSig._signature,
348
+ timestamp,
349
+ ]);
350
+
351
+ const tx = await wallet.sendTransaction({
352
+ to: unvaultingAddress,
353
+ data,
354
+ value: price,
355
+ });
356
+
357
+ callback?.('Waiting for unvault confirmation...', { txHash: tx.hash });
358
+ await tx.wait();
359
+
360
+ return tx.hash;
361
+ }
362
+
363
+ async function requestClaimToken(
364
+ tokenId: string,
365
+ signature: string,
366
+ chainId: number
367
+ ): Promise<{ token: string }> {
368
+ const response = await fetch(`${TORUS_SIGNER_API}/sign`, {
369
+ method: 'POST',
370
+ headers: {
371
+ 'Content-Type': 'application/json',
372
+ chainid: chainId.toString(),
373
+ },
374
+ body: JSON.stringify({ signature, tokenId }),
375
+ });
376
+
377
+ const jwt = await response.json();
378
+
379
+ if (!jwt || jwt.success === false) {
380
+ throw new Error(
381
+ jwt?.debug ? `Claim failed: ${JSON.stringify(jwt.debug)}` : 'Failed to get claim token'
382
+ );
383
+ }
384
+
385
+ return jwt;
386
+ }
package/src/index.ts CHANGED
@@ -1,8 +1,29 @@
1
1
  import { BigNumber } from '@ethersproject/bignumber'
2
- import { Collection, CuratedCollectionsResponse, MetaData, Ownership, Vault } from './types';
3
- import { COIN_TO_NETWORK, NFT_DATA, checkContentType, decryptKeys, evaluateFacts, fetchData, generateTemplate, genericGuard, getHandlerContract, getLegacyContract, getQuoteContractObject, getSatsConnectAddress, getTorusKeys, metadataAllProjects, metadataObj2Arr, pad, signPSBT, templateGuard } from './utils';
4
- import { getAddress, BitcoinNetworkType, AddressPurpose, signTransaction } from "sats-connect";
2
+ import type {
3
+ Collection,
4
+ CuratedCollectionsResponse,
5
+ MetaData,
6
+ Ownership,
7
+ Vault,
8
+ ProgressCallback,
9
+ MintResult,
10
+ ClaimResult,
11
+ EmblemVaultClient,
12
+ SdkContext,
13
+ } from './types';
14
+ import { NFT_DATA, checkContentType, decryptKeys, fetchData, generateTemplate, genericGuard, getHandlerContract, getLegacyContract, getQuoteContractObject, getSatsConnectAddress, getTorusKeys, metadataAllProjects, metadataObj2Arr, signPSBT, templateGuard } from './utils';
5
15
  import { generateTaprootAddressFromMnemonic, getPsbtTxnSize } from './derive';
16
+ import {
17
+ ETHEREUM_MAINNET_CHAIN_ID,
18
+ } from './constants';
19
+ import {
20
+ getChainConfig,
21
+ isV2Vault,
22
+ requiresOnChainUnvault,
23
+ getClaimIdentifier,
24
+ } from './vault-utils';
25
+ import { performMintEvm, performClaimEvm, deleteVaultEvm } from './evm-operations';
26
+
6
27
  const SDK_VERSION = '__SDK_VERSION__';
7
28
 
8
29
  class EmblemVaultSDK {
@@ -76,7 +97,7 @@ class EmblemVaultSDK {
76
97
  item[key] = template[key];
77
98
  });
78
99
  // Return a new object that combines the properties of the item and the template
79
- // return { ...item, ...template };
100
+ return { ...item, ...template };
80
101
  return item;
81
102
  });
82
103
  return data
@@ -94,7 +115,14 @@ class EmblemVaultSDK {
94
115
  let url = `${this.baseUrl}/create-curated`;
95
116
  if (callback) { callback(`creating Vault for user`, template.toAddress)}
96
117
  let vaultCreationResponse = await fetchData(url, this.apiKey, 'POST', template);
97
- if (callback) { callback(`created Vault tokenId`, vaultCreationResponse.data.tokenId)}
118
+
119
+ if (vaultCreationResponse?.err) {
120
+ if (callback) callback(`error creating Vault: ${vaultCreationResponse.msg}`)
121
+ return vaultCreationResponse
122
+ }
123
+
124
+ const { tokenId } = vaultCreationResponse.data
125
+ if (callback) { callback(`created Vault ${tokenId}`)}
98
126
  return vaultCreationResponse.data
99
127
  }
100
128
 
@@ -480,6 +508,66 @@ class EmblemVaultSDK {
480
508
  return results;
481
509
  }
482
510
 
511
+ // ========================================================================
512
+ // Remote Signer Methods (EmblemVaultClient) - Multi-Chain Support
513
+ // ========================================================================
514
+
515
+ private getSdkContext(): SdkContext {
516
+ return {
517
+ apiKey: this.apiKey,
518
+ baseUrl: this.baseUrl,
519
+ v3Url: this.v3Url,
520
+ sigUrl: this.sigUrl,
521
+ fetchMetadata: this.fetchMetadata.bind(this),
522
+ requestRemoteKey: this.requestRemoteKey.bind(this),
523
+ decryptVaultKeys: this.decryptVaultKeys.bind(this),
524
+ };
525
+ }
526
+
527
+ async performMintChainWithClient(
528
+ client: EmblemVaultClient,
529
+ tokenId: string,
530
+ chainId: number | 'solana' = ETHEREUM_MAINNET_CHAIN_ID,
531
+ callback?: ProgressCallback
532
+ ): Promise<MintResult> {
533
+ genericGuard(tokenId, "string", "tokenId");
534
+ getChainConfig(chainId);
535
+ return performMintEvm(this.getSdkContext(), client, tokenId, chainId as number, callback);
536
+ }
537
+
538
+ async performClaimChainWithClient(
539
+ client: EmblemVaultClient,
540
+ tokenId: string,
541
+ chainId: number | 'solana' = ETHEREUM_MAINNET_CHAIN_ID,
542
+ callback?: ProgressCallback
543
+ ): Promise<ClaimResult> {
544
+ genericGuard(tokenId, "string", "tokenId");
545
+ getChainConfig(chainId);
546
+
547
+ callback?.('Fetching vault metadata...');
548
+ const metadata = await this.fetchMetadata(tokenId, callback);
549
+ const claimIdentifier = getClaimIdentifier(metadata);
550
+
551
+ // Check if this is a V2 vault by checking the deployment type (matches VaultActions.vue logic)
552
+ // metadata[chainId]?.type?.endsWith('V2') indicates a diamond/V2 contract
553
+ const deploymentInfo = (metadata as Record<string, unknown>)?.[chainId as number] as { type?: string } | undefined;
554
+ const vaultIsV2 = Boolean(deploymentInfo?.type?.endsWith?.('V2'));
555
+ const needsOnChainUnvault = requiresOnChainUnvault(metadata) && vaultIsV2;
556
+
557
+ return performClaimEvm(this.getSdkContext(), client, tokenId, chainId as number, metadata, claimIdentifier, vaultIsV2, needsOnChainUnvault, callback);
558
+ }
559
+
560
+ async deleteVaultWithClient(
561
+ client: EmblemVaultClient,
562
+ tokenId: string,
563
+ chainId: number | 'solana' = ETHEREUM_MAINNET_CHAIN_ID,
564
+ callback?: ProgressCallback
565
+ ): Promise<boolean> {
566
+ genericGuard(tokenId, "string", "tokenId");
567
+ getChainConfig(chainId);
568
+ return deleteVaultEvm(client, tokenId, chainId as number, callback);
569
+ }
570
+
483
571
  // BTC
484
572
 
485
573
  async sweepVaultUsingPhrase(phrase: string, satsPerByte: number = 20, broadcast: boolean = false) {
@@ -0,0 +1,16 @@
1
+ export function buildMintMessage(tokenId: string): string {
2
+ return `Curated Minting: ${tokenId}`;
3
+ }
4
+
5
+ export function buildClaimMessage(identifier: string, isV2Vault: boolean): string {
6
+ const prefix = isV2Vault ? 'Unvault' : 'Claim';
7
+ return `${prefix}: ${identifier}`;
8
+ }
9
+
10
+ export function buildUnvaultMessage(identifier: string): string {
11
+ return `Unvault: ${identifier}`;
12
+ }
13
+
14
+ export function buildDeleteMessage(tokenId: string): string {
15
+ return `Delete: ${tokenId}`;
16
+ }