opacity-issuer-core 0.2.1 → 0.2.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/dist/index.cjs +785 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +254 -1
- package/dist/index.d.ts +254 -1
- package/dist/index.js +773 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -8641,6 +8641,777 @@ async function transferSandboxUser(publicClient, params) {
|
|
|
8641
8641
|
active2.delete(key);
|
|
8642
8642
|
}
|
|
8643
8643
|
}
|
|
8644
|
+
var sandboxWalletLinkAbi = [
|
|
8645
|
+
{
|
|
8646
|
+
type: "function",
|
|
8647
|
+
name: "sandboxWalletLinkingVersion",
|
|
8648
|
+
stateMutability: "pure",
|
|
8649
|
+
inputs: [],
|
|
8650
|
+
outputs: [{ type: "uint256" }]
|
|
8651
|
+
},
|
|
8652
|
+
{
|
|
8653
|
+
type: "function",
|
|
8654
|
+
name: "sandboxWalletLinkUsed",
|
|
8655
|
+
stateMutability: "view",
|
|
8656
|
+
inputs: [{ name: "digest", type: "bytes32" }],
|
|
8657
|
+
outputs: [{ type: "bool" }]
|
|
8658
|
+
},
|
|
8659
|
+
{
|
|
8660
|
+
type: "function",
|
|
8661
|
+
name: "sandboxLinkWallet",
|
|
8662
|
+
stateMutability: "nonpayable",
|
|
8663
|
+
inputs: [
|
|
8664
|
+
{ name: "newWallet", type: "address" },
|
|
8665
|
+
{ name: "nonce", type: "bytes32" },
|
|
8666
|
+
{ name: "deadline", type: "uint64" },
|
|
8667
|
+
{ name: "newWalletSignature", type: "bytes" }
|
|
8668
|
+
],
|
|
8669
|
+
outputs: []
|
|
8670
|
+
},
|
|
8671
|
+
{
|
|
8672
|
+
type: "event",
|
|
8673
|
+
name: "SandboxWalletLinked",
|
|
8674
|
+
anonymous: false,
|
|
8675
|
+
inputs: [
|
|
8676
|
+
{ name: "existingWallet", type: "address", indexed: true },
|
|
8677
|
+
{ name: "newWallet", type: "address", indexed: true },
|
|
8678
|
+
{ name: "userId", type: "bytes32", indexed: true },
|
|
8679
|
+
{ name: "nonce", type: "bytes32", indexed: false },
|
|
8680
|
+
{ name: "deadline", type: "uint64", indexed: false }
|
|
8681
|
+
]
|
|
8682
|
+
}
|
|
8683
|
+
];
|
|
8684
|
+
var sandboxWalletLinkTypes = {
|
|
8685
|
+
SandboxWalletLink: [
|
|
8686
|
+
{ name: "existingWallet", type: "address" },
|
|
8687
|
+
{ name: "newWallet", type: "address" },
|
|
8688
|
+
{ name: "userId", type: "bytes32" },
|
|
8689
|
+
{ name: "nonce", type: "bytes32" },
|
|
8690
|
+
{ name: "deadline", type: "uint64" }
|
|
8691
|
+
]
|
|
8692
|
+
};
|
|
8693
|
+
var SandboxWalletLinkError = class extends Error {
|
|
8694
|
+
constructor(code, message, progress) {
|
|
8695
|
+
super(message);
|
|
8696
|
+
this.code = code;
|
|
8697
|
+
this.progress = progress;
|
|
8698
|
+
this.name = "SandboxWalletLinkError";
|
|
8699
|
+
}
|
|
8700
|
+
code;
|
|
8701
|
+
progress;
|
|
8702
|
+
};
|
|
8703
|
+
function walletLinkData(value, label, keys) {
|
|
8704
|
+
if (!value || typeof value !== "object" || ![Object.prototype, null].includes(Object.getPrototypeOf(value)))
|
|
8705
|
+
invalid(`${label} must be a plain object.`);
|
|
8706
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
8707
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
8708
|
+
if (typeof key !== "string" || !keys.includes(key) || !descriptor.enumerable || !Object.hasOwn(descriptor, "value"))
|
|
8709
|
+
invalid(`${label} must contain only recognized enumerable data fields.`);
|
|
8710
|
+
}
|
|
8711
|
+
}
|
|
8712
|
+
var fields = [
|
|
8713
|
+
"chainId",
|
|
8714
|
+
"registryAddress",
|
|
8715
|
+
"existingWallet",
|
|
8716
|
+
"newWallet",
|
|
8717
|
+
"nonce",
|
|
8718
|
+
"deadline",
|
|
8719
|
+
"checkedAssets"
|
|
8720
|
+
];
|
|
8721
|
+
function validateSandboxWalletLinkParams(input) {
|
|
8722
|
+
walletLinkData(input, "Wallet link", fields);
|
|
8723
|
+
if (!Array.isArray(input.checkedAssets) || input.checkedAssets.length === 0)
|
|
8724
|
+
invalid("checkedAssets must include every relevant fund token.");
|
|
8725
|
+
for (const key of Reflect.ownKeys(input.checkedAssets)) {
|
|
8726
|
+
if (key === "length") continue;
|
|
8727
|
+
const descriptor = Object.getOwnPropertyDescriptor(input.checkedAssets, key);
|
|
8728
|
+
if (typeof key !== "string" || !/^(0|[1-9][0-9]*)$/.test(key) || Number(key) >= input.checkedAssets.length || !descriptor.enumerable || !Object.hasOwn(descriptor, "value"))
|
|
8729
|
+
invalid("checkedAssets must contain data entries only.");
|
|
8730
|
+
}
|
|
8731
|
+
if (Object.keys(input.checkedAssets).length !== input.checkedAssets.length)
|
|
8732
|
+
invalid("checkedAssets must not contain missing entries.");
|
|
8733
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8734
|
+
const checkedAssets = input.checkedAssets.map((asset) => {
|
|
8735
|
+
walletLinkData(asset, "Checked asset", ["token", "tokenId"]);
|
|
8736
|
+
const token = issuerAddress(asset.token, "token");
|
|
8737
|
+
const tokenId = issuerUint(asset.tokenId, "tokenId");
|
|
8738
|
+
const key = `${token.toLowerCase()}:${tokenId}`;
|
|
8739
|
+
if (seen.has(key)) invalid("checkedAssets must not contain duplicates.");
|
|
8740
|
+
seen.add(key);
|
|
8741
|
+
return Object.freeze({ token, tokenId });
|
|
8742
|
+
});
|
|
8743
|
+
const result = {
|
|
8744
|
+
checkedAssets: Object.freeze(checkedAssets),
|
|
8745
|
+
chainId: issuerChainId(input.chainId),
|
|
8746
|
+
registryAddress: issuerAddress(input.registryAddress, "registryAddress"),
|
|
8747
|
+
existingWallet: issuerAddress(input.existingWallet, "existingWallet"),
|
|
8748
|
+
newWallet: issuerAddress(input.newWallet, "newWallet"),
|
|
8749
|
+
nonce: issuerBytes(input.nonce, "nonce", 32),
|
|
8750
|
+
deadline: issuerUint(input.deadline, "deadline")
|
|
8751
|
+
};
|
|
8752
|
+
if (result.deadline === 0n || result.deadline >= 1n << 64n)
|
|
8753
|
+
invalid("deadline must be a positive uint64 timestamp.");
|
|
8754
|
+
if (sameIssuerAddress(result.existingWallet, result.newWallet))
|
|
8755
|
+
invalid("Choose a different wallet to link.");
|
|
8756
|
+
return Object.freeze(result);
|
|
8757
|
+
}
|
|
8758
|
+
function validateSandboxWalletLinkIntent(input) {
|
|
8759
|
+
walletLinkData(input, "Wallet link intent", [...fields, "userId"]);
|
|
8760
|
+
const { userId, ...params } = input;
|
|
8761
|
+
const id = issuerBytes(userId, "userId", 32);
|
|
8762
|
+
if (id.toLowerCase() === viem.zeroHash) invalid("The existing wallet must have a user identity.");
|
|
8763
|
+
return Object.freeze({ ...validateSandboxWalletLinkParams(params), userId: id });
|
|
8764
|
+
}
|
|
8765
|
+
function buildSandboxWalletLinkTypedData(input) {
|
|
8766
|
+
const { chainId: chainId4, registryAddress, existingWallet, newWallet, userId, nonce, deadline } = validateSandboxWalletLinkIntent(input);
|
|
8767
|
+
const message = { existingWallet, newWallet, userId, nonce, deadline };
|
|
8768
|
+
return {
|
|
8769
|
+
domain: {
|
|
8770
|
+
name: "AllowlistRegistry",
|
|
8771
|
+
version: "1",
|
|
8772
|
+
chainId: chainId4,
|
|
8773
|
+
verifyingContract: registryAddress
|
|
8774
|
+
},
|
|
8775
|
+
types: sandboxWalletLinkTypes,
|
|
8776
|
+
primaryType: "SandboxWalletLink",
|
|
8777
|
+
message
|
|
8778
|
+
};
|
|
8779
|
+
}
|
|
8780
|
+
function buildSandboxWalletLinkTransaction(input, signature) {
|
|
8781
|
+
const intent = validateSandboxWalletLinkIntent(input);
|
|
8782
|
+
return {
|
|
8783
|
+
from: intent.existingWallet,
|
|
8784
|
+
to: intent.registryAddress,
|
|
8785
|
+
chainId: intent.chainId,
|
|
8786
|
+
value: 0n,
|
|
8787
|
+
data: viem.encodeFunctionData({
|
|
8788
|
+
abi: sandboxWalletLinkAbi,
|
|
8789
|
+
functionName: "sandboxLinkWallet",
|
|
8790
|
+
args: [intent.newWallet, intent.nonce, intent.deadline, issuerBytes(signature, "signature")]
|
|
8791
|
+
})
|
|
8792
|
+
};
|
|
8793
|
+
}
|
|
8794
|
+
function walletLinkWaitOptions(value = {}) {
|
|
8795
|
+
walletLinkData(value, "wait", ["confirmations", "timeout", "pollingInterval"]);
|
|
8796
|
+
for (const n of Object.values(value))
|
|
8797
|
+
if (n !== void 0 && (!Number.isSafeInteger(n) || n <= 0))
|
|
8798
|
+
invalid("Wait options must be positive safe integers.");
|
|
8799
|
+
return { ...value };
|
|
8800
|
+
}
|
|
8801
|
+
async function checkChain3(client, chainId4) {
|
|
8802
|
+
if (client.chain && client.chain.id !== chainId4 || await client.getChainId() !== chainId4)
|
|
8803
|
+
invalid("The wallet, RPC and requested chains must match.");
|
|
8804
|
+
}
|
|
8805
|
+
async function checkWallet(wallet, chainId4, expected) {
|
|
8806
|
+
if (!wallet) invalid("Wallet linking requires a wallet client.");
|
|
8807
|
+
await checkChain3(wallet, chainId4);
|
|
8808
|
+
const selected = wallet.account?.type === "local" ? wallet.account.address : (await wallet.getAddresses())[0];
|
|
8809
|
+
if (!selected || !sameIssuerAddress(selected, expected) || wallet.account && !sameIssuerAddress(wallet.account.address, selected))
|
|
8810
|
+
invalid("The selected wallet changed. Review the link with the expected wallet.");
|
|
8811
|
+
return wallet;
|
|
8812
|
+
}
|
|
8813
|
+
function absentCapability(error) {
|
|
8814
|
+
if (!(error instanceof viem.BaseError)) return false;
|
|
8815
|
+
return !!error.walk(
|
|
8816
|
+
(cause) => cause instanceof viem.ContractFunctionRevertedError || cause instanceof viem.ContractFunctionZeroDataError
|
|
8817
|
+
);
|
|
8818
|
+
}
|
|
8819
|
+
function rejected(error) {
|
|
8820
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8821
|
+
for (let e = error; e && typeof e === "object" && !seen.has(e); e = e.cause) {
|
|
8822
|
+
seen.add(e);
|
|
8823
|
+
if (e.code === 4001) return true;
|
|
8824
|
+
}
|
|
8825
|
+
return false;
|
|
8826
|
+
}
|
|
8827
|
+
var pending = /* @__PURE__ */ new Map();
|
|
8828
|
+
var keyFor = (i) => `${i.chainId}:${i.existingWallet.toLowerCase()}`;
|
|
8829
|
+
var sameIntent = (a, b) => viem.hashTypedData(buildSandboxWalletLinkTypedData(a)) === viem.hashTypedData(buildSandboxWalletLinkTypedData(b));
|
|
8830
|
+
function createSandboxWalletLinksNamespace(options) {
|
|
8831
|
+
async function clientFor(chainId4) {
|
|
8832
|
+
if (options.chainId !== void 0 && options.chainId !== chainId4)
|
|
8833
|
+
invalid("Configured and requested wallet linking chains must match.");
|
|
8834
|
+
await checkChain3(options.publicClient, chainId4);
|
|
8835
|
+
return options.publicClient;
|
|
8836
|
+
}
|
|
8837
|
+
async function prepareWalletLink(input) {
|
|
8838
|
+
const params = validateSandboxWalletLinkParams(input);
|
|
8839
|
+
const client = await clientFor(params.chainId);
|
|
8840
|
+
const block = await client.getBlock();
|
|
8841
|
+
const blockNumber = block.number;
|
|
8842
|
+
const context = { address: params.registryAddress, blockNumber };
|
|
8843
|
+
let supported = false;
|
|
8844
|
+
try {
|
|
8845
|
+
supported = await client.readContract({
|
|
8846
|
+
...context,
|
|
8847
|
+
abi: sandboxWalletLinkAbi,
|
|
8848
|
+
functionName: "sandboxWalletLinkingVersion"
|
|
8849
|
+
}) === 1n;
|
|
8850
|
+
} catch (error) {
|
|
8851
|
+
if (!absentCapability(error)) throw error;
|
|
8852
|
+
}
|
|
8853
|
+
const [paused, allowed, userId, targetUserId, targetStatus, targetIssuer, sourceExpiry] = await Promise.all([
|
|
8854
|
+
client.readContract({ ...context, abi: issuerRegistryAbi, functionName: "paused" }),
|
|
8855
|
+
client.readContract({
|
|
8856
|
+
...context,
|
|
8857
|
+
abi: issuerRegistryAbi,
|
|
8858
|
+
functionName: "isAllowed",
|
|
8859
|
+
args: [params.existingWallet]
|
|
8860
|
+
}),
|
|
8861
|
+
client.readContract({
|
|
8862
|
+
...context,
|
|
8863
|
+
abi: issuerRegistryAbi,
|
|
8864
|
+
functionName: "getUserId",
|
|
8865
|
+
args: [params.existingWallet]
|
|
8866
|
+
}),
|
|
8867
|
+
client.readContract({
|
|
8868
|
+
...context,
|
|
8869
|
+
abi: issuerRegistryAbi,
|
|
8870
|
+
functionName: "getUserId",
|
|
8871
|
+
args: [params.newWallet]
|
|
8872
|
+
}),
|
|
8873
|
+
client.readContract({
|
|
8874
|
+
...context,
|
|
8875
|
+
abi: issuerRegistryAbi,
|
|
8876
|
+
functionName: "getEntryStatus",
|
|
8877
|
+
args: [params.newWallet]
|
|
8878
|
+
}),
|
|
8879
|
+
client.readContract({
|
|
8880
|
+
...context,
|
|
8881
|
+
abi: issuerRegistryAbi,
|
|
8882
|
+
functionName: "isAuthorizedIssuer",
|
|
8883
|
+
args: [params.newWallet]
|
|
8884
|
+
}),
|
|
8885
|
+
client.readContract({
|
|
8886
|
+
...context,
|
|
8887
|
+
abi: issuerRegistryAbi,
|
|
8888
|
+
functionName: "getEntryExpiry",
|
|
8889
|
+
args: [params.existingWallet]
|
|
8890
|
+
})
|
|
8891
|
+
]);
|
|
8892
|
+
const intent = { ...params, userId };
|
|
8893
|
+
const blockers = [];
|
|
8894
|
+
if (!supported) blockers.push("unsupported-wallet-linking");
|
|
8895
|
+
if (paused) blockers.push("registry-paused");
|
|
8896
|
+
if (!allowed) blockers.push("source-not-approved");
|
|
8897
|
+
if (userId === viem.zeroHash) blockers.push("source-identity-missing");
|
|
8898
|
+
if (targetUserId !== viem.zeroHash) blockers.push("target-already-linked");
|
|
8899
|
+
if (targetStatus !== 0) blockers.push("target-not-fresh");
|
|
8900
|
+
if (targetIssuer) blockers.push("target-is-issuer");
|
|
8901
|
+
for (const asset of params.checkedAssets) {
|
|
8902
|
+
const registry = await client.readContract({
|
|
8903
|
+
address: asset.token,
|
|
8904
|
+
blockNumber,
|
|
8905
|
+
abi: issuerTokenAbi,
|
|
8906
|
+
functionName: "allowlistRegistry"
|
|
8907
|
+
});
|
|
8908
|
+
if (!sameIssuerAddress(registry, params.registryAddress))
|
|
8909
|
+
invalid("A checked fund token uses a different registry.");
|
|
8910
|
+
const balance = await client.readContract({
|
|
8911
|
+
address: asset.token,
|
|
8912
|
+
blockNumber,
|
|
8913
|
+
abi: issuerTokenAbi,
|
|
8914
|
+
functionName: "balanceOf",
|
|
8915
|
+
args: [params.newWallet, asset.tokenId]
|
|
8916
|
+
});
|
|
8917
|
+
if (balance !== 0n && !blockers.includes("target-holds-assets"))
|
|
8918
|
+
blockers.push("target-holds-assets");
|
|
8919
|
+
}
|
|
8920
|
+
if (params.deadline < block.timestamp) blockers.push("consent-expired");
|
|
8921
|
+
if (supported && userId !== viem.zeroHash && await client.readContract({
|
|
8922
|
+
...context,
|
|
8923
|
+
abi: sandboxWalletLinkAbi,
|
|
8924
|
+
functionName: "sandboxWalletLinkUsed",
|
|
8925
|
+
args: [viem.hashTypedData(buildSandboxWalletLinkTypedData(intent))]
|
|
8926
|
+
}))
|
|
8927
|
+
blockers.push("consent-used");
|
|
8928
|
+
await clientFor(params.chainId);
|
|
8929
|
+
return {
|
|
8930
|
+
intent: Object.freeze(intent),
|
|
8931
|
+
blockNumber,
|
|
8932
|
+
sourceExpiry,
|
|
8933
|
+
blockers,
|
|
8934
|
+
ready: blockers.length === 0
|
|
8935
|
+
};
|
|
8936
|
+
}
|
|
8937
|
+
async function fresh(input) {
|
|
8938
|
+
const intent = validateSandboxWalletLinkIntent(input);
|
|
8939
|
+
const { userId: _id, ...params } = intent;
|
|
8940
|
+
const prepared = await prepareWalletLink(params);
|
|
8941
|
+
if (prepared.blockers.length)
|
|
8942
|
+
throw new SandboxWalletLinkError(
|
|
8943
|
+
"blocked",
|
|
8944
|
+
`Wallet linking is blocked: ${prepared.blockers.join(", ")}.`
|
|
8945
|
+
);
|
|
8946
|
+
if (!sameIntent(intent, prepared.intent))
|
|
8947
|
+
throw new SandboxWalletLinkError(
|
|
8948
|
+
"stale-intent",
|
|
8949
|
+
"The existing wallet identity changed. Prepare and review a new link."
|
|
8950
|
+
);
|
|
8951
|
+
return prepared;
|
|
8952
|
+
}
|
|
8953
|
+
async function signWalletLink(input, newWalletClient) {
|
|
8954
|
+
const intent = validateSandboxWalletLinkIntent(input);
|
|
8955
|
+
await fresh(intent);
|
|
8956
|
+
const wallet = await checkWallet(newWalletClient, intent.chainId, intent.newWallet);
|
|
8957
|
+
let signature;
|
|
8958
|
+
try {
|
|
8959
|
+
signature = await wallet.signTypedData({
|
|
8960
|
+
...buildSandboxWalletLinkTypedData(intent),
|
|
8961
|
+
account: wallet.account ?? intent.newWallet
|
|
8962
|
+
});
|
|
8963
|
+
} catch (error) {
|
|
8964
|
+
throw new SandboxWalletLinkError(
|
|
8965
|
+
rejected(error) ? "rejected" : "blocked",
|
|
8966
|
+
"Wallet consent was not signed. No transaction was sent."
|
|
8967
|
+
);
|
|
8968
|
+
}
|
|
8969
|
+
await checkWallet(wallet, intent.chainId, intent.newWallet);
|
|
8970
|
+
return issuerBytes(signature, "signature");
|
|
8971
|
+
}
|
|
8972
|
+
async function preflightWalletLink(input, signature) {
|
|
8973
|
+
const intent = validateSandboxWalletLinkIntent(input);
|
|
8974
|
+
const transaction = buildSandboxWalletLinkTransaction(intent, signature);
|
|
8975
|
+
const prepared = await fresh(intent);
|
|
8976
|
+
const client = await clientFor(intent.chainId);
|
|
8977
|
+
try {
|
|
8978
|
+
await client.call({
|
|
8979
|
+
account: transaction.from,
|
|
8980
|
+
to: transaction.to,
|
|
8981
|
+
data: transaction.data,
|
|
8982
|
+
value: 0n
|
|
8983
|
+
});
|
|
8984
|
+
} catch (error) {
|
|
8985
|
+
const reverted = error instanceof viem.BaseError && !!error.walk(
|
|
8986
|
+
(cause) => cause instanceof viem.ContractFunctionRevertedError || cause instanceof viem.ExecutionRevertedError
|
|
8987
|
+
);
|
|
8988
|
+
throw new SandboxWalletLinkError(
|
|
8989
|
+
reverted ? "blocked" : "check-unavailable",
|
|
8990
|
+
reverted ? "This wallet link was rejected. Check the consent and current wallet eligibility." : "The connection could not check this wallet link. Try the check again before sending."
|
|
8991
|
+
);
|
|
8992
|
+
}
|
|
8993
|
+
let gas;
|
|
8994
|
+
try {
|
|
8995
|
+
const [estimatedGas, gasPrice, nativeBalance] = await Promise.all([
|
|
8996
|
+
client.estimateGas({
|
|
8997
|
+
account: transaction.from,
|
|
8998
|
+
to: transaction.to,
|
|
8999
|
+
data: transaction.data,
|
|
9000
|
+
value: 0n
|
|
9001
|
+
}),
|
|
9002
|
+
client.getGasPrice(),
|
|
9003
|
+
client.getBalance({ address: intent.existingWallet })
|
|
9004
|
+
]);
|
|
9005
|
+
const estimatedCost = estimatedGas * gasPrice;
|
|
9006
|
+
gas = { estimatedGas, gasPrice, estimatedCost, nativeBalance };
|
|
9007
|
+
if (nativeBalance < estimatedCost || nativeBalance === 0n)
|
|
9008
|
+
throw new SandboxWalletLinkError(
|
|
9009
|
+
"insufficient-gas",
|
|
9010
|
+
"The existing wallet needs more test ETH to link this wallet."
|
|
9011
|
+
);
|
|
9012
|
+
} catch (error) {
|
|
9013
|
+
if (error instanceof SandboxWalletLinkError) throw error;
|
|
9014
|
+
throw new SandboxWalletLinkError(
|
|
9015
|
+
"check-unavailable",
|
|
9016
|
+
"The connection could not estimate the network fee. Check again before sending."
|
|
9017
|
+
);
|
|
9018
|
+
}
|
|
9019
|
+
await clientFor(intent.chainId);
|
|
9020
|
+
return { ...prepared, gas };
|
|
9021
|
+
}
|
|
9022
|
+
async function sendWalletLink(input) {
|
|
9023
|
+
walletLinkData(input, "Send wallet link", ["intent", "signature", "persist"]);
|
|
9024
|
+
const intent = validateSandboxWalletLinkIntent(input.intent);
|
|
9025
|
+
const signature = issuerBytes(input.signature, "signature");
|
|
9026
|
+
const persist = input.persist;
|
|
9027
|
+
if (typeof persist !== "function")
|
|
9028
|
+
invalid("persist must save wallet linking progress before sending.");
|
|
9029
|
+
const key = keyFor(intent);
|
|
9030
|
+
if (pending.has(key))
|
|
9031
|
+
throw new SandboxWalletLinkError(
|
|
9032
|
+
"send-in-progress",
|
|
9033
|
+
"Check the existing wallet link before starting another.",
|
|
9034
|
+
structuredClone(pending.get(key))
|
|
9035
|
+
);
|
|
9036
|
+
const progress = { kind: "wallet-link", intent, stage: "prepared" };
|
|
9037
|
+
pending.set(key, structuredClone(progress));
|
|
9038
|
+
let attempted = false;
|
|
9039
|
+
let persistence = false;
|
|
9040
|
+
const save = async () => {
|
|
9041
|
+
pending.set(key, structuredClone(progress));
|
|
9042
|
+
persistence = true;
|
|
9043
|
+
await persist(structuredClone(progress));
|
|
9044
|
+
persistence = false;
|
|
9045
|
+
};
|
|
9046
|
+
try {
|
|
9047
|
+
await save();
|
|
9048
|
+
await preflightWalletLink(intent, signature);
|
|
9049
|
+
await checkWallet(options.walletClient, intent.chainId, intent.existingWallet);
|
|
9050
|
+
progress.senderNonce = await (await clientFor(intent.chainId)).getTransactionCount({ address: intent.existingWallet, blockTag: "pending" });
|
|
9051
|
+
if (!Number.isSafeInteger(progress.senderNonce) || progress.senderNonce < 0)
|
|
9052
|
+
invalid("The RPC returned an invalid transaction nonce.");
|
|
9053
|
+
progress.stage = "sending";
|
|
9054
|
+
await save();
|
|
9055
|
+
await preflightWalletLink(intent, signature);
|
|
9056
|
+
const wallet = await checkWallet(options.walletClient, intent.chainId, intent.existingWallet);
|
|
9057
|
+
const client = await clientFor(intent.chainId);
|
|
9058
|
+
if (await client.getTransactionCount({
|
|
9059
|
+
address: intent.existingWallet,
|
|
9060
|
+
blockTag: "pending"
|
|
9061
|
+
}) !== progress.senderNonce)
|
|
9062
|
+
throw new SandboxWalletLinkError(
|
|
9063
|
+
"stale-intent",
|
|
9064
|
+
"The existing wallet has another pending transaction. Check it before reviewing a new link."
|
|
9065
|
+
);
|
|
9066
|
+
const tx = buildSandboxWalletLinkTransaction(intent, signature);
|
|
9067
|
+
attempted = true;
|
|
9068
|
+
const hash = await wallet.sendTransaction({
|
|
9069
|
+
account: wallet.account ?? intent.existingWallet,
|
|
9070
|
+
chain: wallet.chain ?? viem.defineChain({
|
|
9071
|
+
id: intent.chainId,
|
|
9072
|
+
name: `Sandbox ${intent.chainId}`,
|
|
9073
|
+
nativeCurrency: { name: "Native", symbol: "NATIVE", decimals: 18 },
|
|
9074
|
+
rpcUrls: { default: { http: [] } }
|
|
9075
|
+
}),
|
|
9076
|
+
to: tx.to,
|
|
9077
|
+
data: tx.data,
|
|
9078
|
+
value: 0n,
|
|
9079
|
+
nonce: progress.senderNonce
|
|
9080
|
+
});
|
|
9081
|
+
progress.hash = issuerBytes(hash, "transaction hash", 32);
|
|
9082
|
+
progress.stage = "submitted";
|
|
9083
|
+
await save();
|
|
9084
|
+
return structuredClone(progress);
|
|
9085
|
+
} catch (error) {
|
|
9086
|
+
if (!attempted || !progress.hash && !persistence && rejected(error)) {
|
|
9087
|
+
pending.delete(key);
|
|
9088
|
+
progress.stage = "rejected";
|
|
9089
|
+
try {
|
|
9090
|
+
await persist(structuredClone(progress));
|
|
9091
|
+
} catch {
|
|
9092
|
+
}
|
|
9093
|
+
if (error instanceof SandboxWalletLinkError)
|
|
9094
|
+
throw new SandboxWalletLinkError(error.code, error.message, structuredClone(progress));
|
|
9095
|
+
throw new SandboxWalletLinkError(
|
|
9096
|
+
persistence ? "persistence-failed" : "rejected",
|
|
9097
|
+
persistence ? "Wallet link progress could not be saved. No transaction was sent." : "Wallet linking stopped before a transaction was submitted.",
|
|
9098
|
+
structuredClone(progress)
|
|
9099
|
+
);
|
|
9100
|
+
}
|
|
9101
|
+
pending.set(key, structuredClone(progress));
|
|
9102
|
+
throw new SandboxWalletLinkError(
|
|
9103
|
+
"uncertain",
|
|
9104
|
+
"Check the existing transaction before trying another wallet link.",
|
|
9105
|
+
structuredClone(progress)
|
|
9106
|
+
);
|
|
9107
|
+
}
|
|
9108
|
+
}
|
|
9109
|
+
async function waitForWalletLink(input, wait = {}) {
|
|
9110
|
+
walletLinkData(input, "Wallet link submission", [
|
|
9111
|
+
"kind",
|
|
9112
|
+
"intent",
|
|
9113
|
+
"stage",
|
|
9114
|
+
"hash",
|
|
9115
|
+
"senderNonce",
|
|
9116
|
+
"result"
|
|
9117
|
+
]);
|
|
9118
|
+
if (input.kind !== "wallet-link" || !["submitted", "complete"].includes(input.stage))
|
|
9119
|
+
invalid("Expected a submitted wallet link.");
|
|
9120
|
+
const intent = validateSandboxWalletLinkIntent(input.intent);
|
|
9121
|
+
const hash = issuerBytes(input.hash, "hash", 32);
|
|
9122
|
+
const senderNonce = input.senderNonce;
|
|
9123
|
+
if (!Number.isSafeInteger(senderNonce) || senderNonce < 0)
|
|
9124
|
+
invalid("senderNonce must be a nonnegative safe integer.");
|
|
9125
|
+
const client = await clientFor(intent.chainId);
|
|
9126
|
+
const waitOptions3 = walletLinkWaitOptions(wait);
|
|
9127
|
+
let replacementReason;
|
|
9128
|
+
const receipt = structuredClone(
|
|
9129
|
+
await client.waitForTransactionReceipt({
|
|
9130
|
+
hash,
|
|
9131
|
+
...waitOptions3,
|
|
9132
|
+
onReplaced: ({ reason }) => {
|
|
9133
|
+
replacementReason = reason;
|
|
9134
|
+
}
|
|
9135
|
+
})
|
|
9136
|
+
);
|
|
9137
|
+
await clientFor(intent.chainId);
|
|
9138
|
+
const base = { submittedHash: hash, hash: receipt.transactionHash, receipt };
|
|
9139
|
+
let exactTransaction = false;
|
|
9140
|
+
let result = { ...base, status: "unverified" };
|
|
9141
|
+
if (replacementReason || receipt.transactionHash.toLowerCase() !== hash.toLowerCase())
|
|
9142
|
+
result = { ...base, status: "replaced", ...replacementReason ? { replacementReason } : {} };
|
|
9143
|
+
else if (receipt.status === "reverted") result = { ...base, status: "reverted" };
|
|
9144
|
+
else if (receipt.status === "success") {
|
|
9145
|
+
try {
|
|
9146
|
+
const tx = await client.getTransaction({ hash });
|
|
9147
|
+
await clientFor(intent.chainId);
|
|
9148
|
+
const decoded = viem.decodeFunctionData({ abi: sandboxWalletLinkAbi, data: tx.input });
|
|
9149
|
+
const matches = sameIssuerAddress(receipt.from, intent.existingWallet) && receipt.to !== null && sameIssuerAddress(receipt.to, intent.registryAddress) && tx.blockHash === receipt.blockHash && tx.blockNumber === receipt.blockNumber && tx.hash.toLowerCase() === hash.toLowerCase() && tx.chainId === intent.chainId && sameIssuerAddress(tx.from, intent.existingWallet) && tx.to !== null && sameIssuerAddress(tx.to, intent.registryAddress) && tx.value === 0n && (senderNonce === void 0 || tx.nonce === senderNonce) && decoded.functionName === "sandboxLinkWallet" && sameIssuerAddress(decoded.args[0], intent.newWallet) && decoded.args[1].toLowerCase() === intent.nonce.toLowerCase() && decoded.args[2] === intent.deadline;
|
|
9150
|
+
exactTransaction = matches;
|
|
9151
|
+
if (matches)
|
|
9152
|
+
for (const log of receipt.logs) {
|
|
9153
|
+
if (!sameIssuerAddress(log.address, intent.registryAddress) || log.removed || log.blockHash !== receipt.blockHash || log.blockNumber !== receipt.blockNumber || log.transactionHash?.toLowerCase() !== hash.toLowerCase())
|
|
9154
|
+
continue;
|
|
9155
|
+
try {
|
|
9156
|
+
const { args } = viem.decodeEventLog({
|
|
9157
|
+
abi: sandboxWalletLinkAbi,
|
|
9158
|
+
eventName: "SandboxWalletLinked",
|
|
9159
|
+
data: log.data,
|
|
9160
|
+
topics: log.topics,
|
|
9161
|
+
strict: true
|
|
9162
|
+
});
|
|
9163
|
+
if (sameIssuerAddress(args.existingWallet, intent.existingWallet) && sameIssuerAddress(args.newWallet, intent.newWallet) && args.userId.toLowerCase() === intent.userId.toLowerCase() && args.nonce.toLowerCase() === intent.nonce.toLowerCase() && args.deadline === intent.deadline)
|
|
9164
|
+
result = { ...base, status: "confirmed" };
|
|
9165
|
+
} catch {
|
|
9166
|
+
}
|
|
9167
|
+
}
|
|
9168
|
+
} catch {
|
|
9169
|
+
}
|
|
9170
|
+
}
|
|
9171
|
+
const current = pending.get(keyFor(intent));
|
|
9172
|
+
if (current?.hash === void 0 && current?.stage === "sending" && result.status === "reverted") {
|
|
9173
|
+
try {
|
|
9174
|
+
const tx = await client.getTransaction({ hash });
|
|
9175
|
+
await clientFor(intent.chainId);
|
|
9176
|
+
const decoded = viem.decodeFunctionData({ abi: sandboxWalletLinkAbi, data: tx.input });
|
|
9177
|
+
exactTransaction = tx.hash.toLowerCase() === hash.toLowerCase() && tx.chainId === intent.chainId && sameIssuerAddress(tx.from, intent.existingWallet) && tx.to !== null && sameIssuerAddress(tx.to, intent.registryAddress) && tx.value === 0n && tx.nonce === senderNonce && tx.blockHash === receipt.blockHash && tx.blockNumber === receipt.blockNumber && decoded.functionName === "sandboxLinkWallet" && sameIssuerAddress(decoded.args[0], intent.newWallet) && decoded.args[1].toLowerCase() === intent.nonce.toLowerCase() && decoded.args[2] === intent.deadline;
|
|
9178
|
+
} catch {
|
|
9179
|
+
}
|
|
9180
|
+
}
|
|
9181
|
+
if (current && pending.get(keyFor(intent)) === current && sameIntent(current.intent, intent) && (current.hash?.toLowerCase() === hash.toLowerCase() || current.hash === void 0 && current.stage === "sending" && current.senderNonce === senderNonce && exactTransaction) && (result.status === "confirmed" || result.status === "reverted" || result.status === "replaced"))
|
|
9182
|
+
pending.delete(keyFor(intent));
|
|
9183
|
+
return result;
|
|
9184
|
+
}
|
|
9185
|
+
return {
|
|
9186
|
+
prepareWalletLink,
|
|
9187
|
+
signWalletLink,
|
|
9188
|
+
preflightWalletLink,
|
|
9189
|
+
sendWalletLink,
|
|
9190
|
+
waitForWalletLink
|
|
9191
|
+
};
|
|
9192
|
+
}
|
|
9193
|
+
var SandboxLinkedWalletCreationError = class extends Error {
|
|
9194
|
+
constructor(progress) {
|
|
9195
|
+
super(
|
|
9196
|
+
"Wallet creation stopped. Recover the saved wallet and check its pending link before another attempt."
|
|
9197
|
+
);
|
|
9198
|
+
this.progress = progress;
|
|
9199
|
+
this.name = "SandboxLinkedWalletCreationError";
|
|
9200
|
+
Object.defineProperty(this, "progress", { enumerable: false });
|
|
9201
|
+
}
|
|
9202
|
+
progress;
|
|
9203
|
+
};
|
|
9204
|
+
async function createSandboxLinkedWallet(publicClient, input) {
|
|
9205
|
+
walletLinkData(input, "Create linked wallet", [
|
|
9206
|
+
"chainId",
|
|
9207
|
+
"registryAddress",
|
|
9208
|
+
"existingWallet",
|
|
9209
|
+
"checkedAssets",
|
|
9210
|
+
"sourceWalletClient",
|
|
9211
|
+
"persist",
|
|
9212
|
+
"privateKey",
|
|
9213
|
+
"nonce",
|
|
9214
|
+
"deadline",
|
|
9215
|
+
"wait"
|
|
9216
|
+
]);
|
|
9217
|
+
const chainId4 = issuerChainId(input.chainId);
|
|
9218
|
+
const registryAddress = issuerAddress(input.registryAddress, "registryAddress");
|
|
9219
|
+
const existingWallet = issuerAddress(input.existingWallet, "existingWallet");
|
|
9220
|
+
const persist = input.persist;
|
|
9221
|
+
if (typeof persist !== "function") invalid("persist must save the new wallet before sending.");
|
|
9222
|
+
if (!input.sourceWalletClient || typeof input.sourceWalletClient.sendTransaction !== "function")
|
|
9223
|
+
invalid("sourceWalletClient is required.");
|
|
9224
|
+
const sourceWalletClient = input.sourceWalletClient;
|
|
9225
|
+
const privateKey = input.privateKey === void 0 ? accounts.generatePrivateKey() : issuerBytes(input.privateKey, "privateKey", 32);
|
|
9226
|
+
let account;
|
|
9227
|
+
try {
|
|
9228
|
+
account = accounts.privateKeyToAccount(privateKey);
|
|
9229
|
+
} catch {
|
|
9230
|
+
invalid("privateKey must be a valid test-wallet private key.");
|
|
9231
|
+
}
|
|
9232
|
+
const nonce = input.nonce === void 0 ? accounts.generatePrivateKey() : issuerBytes(input.nonce, "nonce", 32);
|
|
9233
|
+
const wait = walletLinkWaitOptions(input.wait);
|
|
9234
|
+
const provisional = validateSandboxWalletLinkParams({
|
|
9235
|
+
chainId: chainId4,
|
|
9236
|
+
registryAddress,
|
|
9237
|
+
existingWallet,
|
|
9238
|
+
newWallet: account.address,
|
|
9239
|
+
checkedAssets: input.checkedAssets,
|
|
9240
|
+
nonce,
|
|
9241
|
+
deadline: input.deadline ?? 1n
|
|
9242
|
+
});
|
|
9243
|
+
const explicitDeadline = input.deadline;
|
|
9244
|
+
const links = createSandboxWalletLinksNamespace({
|
|
9245
|
+
publicClient,
|
|
9246
|
+
walletClient: sourceWalletClient,
|
|
9247
|
+
chainId: chainId4
|
|
9248
|
+
});
|
|
9249
|
+
const deadline = explicitDeadline ?? (await publicClient.getBlock()).timestamp + 900n;
|
|
9250
|
+
const prepared = await links.prepareWalletLink({ ...provisional, deadline });
|
|
9251
|
+
if (!prepared.ready)
|
|
9252
|
+
throw new SandboxWalletLinkError(
|
|
9253
|
+
"blocked",
|
|
9254
|
+
`Wallet linking is blocked: ${prepared.blockers.join(", ")}.`
|
|
9255
|
+
);
|
|
9256
|
+
const state = {
|
|
9257
|
+
kind: "linked-wallet",
|
|
9258
|
+
wallet: account.address,
|
|
9259
|
+
existingWallet,
|
|
9260
|
+
privateKey,
|
|
9261
|
+
chainId: chainId4,
|
|
9262
|
+
registryAddress,
|
|
9263
|
+
userId: prepared.intent.userId,
|
|
9264
|
+
stage: "created",
|
|
9265
|
+
link: { kind: "wallet-link", intent: prepared.intent, stage: "prepared" }
|
|
9266
|
+
};
|
|
9267
|
+
const targetWallet = viem.createWalletClient({
|
|
9268
|
+
account,
|
|
9269
|
+
transport: viem.custom({
|
|
9270
|
+
request: async ({ method }) => {
|
|
9271
|
+
if (method === "eth_chainId") return `0x${chainId4.toString(16)}`;
|
|
9272
|
+
throw new Error("Generated wallet transport supports only local signing.");
|
|
9273
|
+
}
|
|
9274
|
+
})
|
|
9275
|
+
});
|
|
9276
|
+
const save = () => persist(structuredClone(state));
|
|
9277
|
+
try {
|
|
9278
|
+
await save();
|
|
9279
|
+
const signature = await links.signWalletLink(prepared.intent, targetWallet);
|
|
9280
|
+
state.stage = "linking";
|
|
9281
|
+
const submission = await links.sendWalletLink({
|
|
9282
|
+
intent: prepared.intent,
|
|
9283
|
+
signature,
|
|
9284
|
+
persist: async (link) => {
|
|
9285
|
+
state.link = structuredClone(link);
|
|
9286
|
+
await save();
|
|
9287
|
+
}
|
|
9288
|
+
});
|
|
9289
|
+
const result = await links.waitForWalletLink(submission, wait);
|
|
9290
|
+
state.link = {
|
|
9291
|
+
...submission,
|
|
9292
|
+
result,
|
|
9293
|
+
...result.status === "confirmed" ? { stage: "complete" } : {}
|
|
9294
|
+
};
|
|
9295
|
+
if (result.status !== "confirmed") {
|
|
9296
|
+
await save();
|
|
9297
|
+
throw new Error("Link is not confirmed.");
|
|
9298
|
+
}
|
|
9299
|
+
state.stage = "complete";
|
|
9300
|
+
await save();
|
|
9301
|
+
return structuredClone(state);
|
|
9302
|
+
} catch (error) {
|
|
9303
|
+
if (error instanceof SandboxWalletLinkError && error.progress)
|
|
9304
|
+
state.link = structuredClone(error.progress);
|
|
9305
|
+
throw new SandboxLinkedWalletCreationError(structuredClone(state));
|
|
9306
|
+
}
|
|
9307
|
+
}
|
|
9308
|
+
function savedData(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
9309
|
+
if (value === null || value === void 0 || ["string", "boolean", "bigint"].includes(typeof value))
|
|
9310
|
+
return;
|
|
9311
|
+
if (typeof value === "number" && Number.isFinite(value)) return;
|
|
9312
|
+
if (typeof value !== "object" || value === null || ancestors.has(value))
|
|
9313
|
+
invalid("Saved wallet must contain acyclic data.");
|
|
9314
|
+
if (!Array.isArray(value) && ![Object.prototype, null].includes(Object.getPrototypeOf(value)))
|
|
9315
|
+
invalid("Saved wallet must contain plain data.");
|
|
9316
|
+
ancestors.add(value);
|
|
9317
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
9318
|
+
if (Array.isArray(value) && key === "length") continue;
|
|
9319
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
9320
|
+
if (typeof key !== "string" || !descriptor.enumerable || !Object.hasOwn(descriptor, "value"))
|
|
9321
|
+
invalid("Saved wallet must contain enumerable data fields.");
|
|
9322
|
+
savedData(descriptor.value, ancestors);
|
|
9323
|
+
}
|
|
9324
|
+
ancestors.delete(value);
|
|
9325
|
+
}
|
|
9326
|
+
function validateSandboxLinkedWalletProgress(input) {
|
|
9327
|
+
savedData(input);
|
|
9328
|
+
walletLinkData(input, "Saved linked wallet", [
|
|
9329
|
+
"kind",
|
|
9330
|
+
"wallet",
|
|
9331
|
+
"existingWallet",
|
|
9332
|
+
"privateKey",
|
|
9333
|
+
"chainId",
|
|
9334
|
+
"registryAddress",
|
|
9335
|
+
"userId",
|
|
9336
|
+
"stage",
|
|
9337
|
+
"link"
|
|
9338
|
+
]);
|
|
9339
|
+
if (input.kind !== "linked-wallet" || !["created", "linking", "complete"].includes(input.stage))
|
|
9340
|
+
invalid("Invalid saved linked-wallet state.");
|
|
9341
|
+
walletLinkData(input.link, "Saved wallet link", [
|
|
9342
|
+
"kind",
|
|
9343
|
+
"intent",
|
|
9344
|
+
"stage",
|
|
9345
|
+
"hash",
|
|
9346
|
+
"senderNonce",
|
|
9347
|
+
"result"
|
|
9348
|
+
]);
|
|
9349
|
+
const intent = validateSandboxWalletLinkIntent(input.link.intent);
|
|
9350
|
+
if (input.link.kind !== "wallet-link" || !["prepared", "sending", "submitted", "rejected", "complete"].includes(input.link.stage))
|
|
9351
|
+
invalid("Invalid saved link journal.");
|
|
9352
|
+
if (input.link.hash !== void 0) issuerBytes(input.link.hash, "hash", 32);
|
|
9353
|
+
if (["submitted", "complete"].includes(input.link.stage) && input.link.hash === void 0)
|
|
9354
|
+
invalid("A submitted link requires its transaction hash.");
|
|
9355
|
+
if (input.link.senderNonce !== void 0 && (!Number.isSafeInteger(input.link.senderNonce) || input.link.senderNonce < 0))
|
|
9356
|
+
invalid("Invalid saved sender nonce.");
|
|
9357
|
+
if (["sending", "submitted", "complete"].includes(input.link.stage) && input.link.senderNonce === void 0)
|
|
9358
|
+
invalid("A pending link requires its sender nonce.");
|
|
9359
|
+
if (input.link.result !== void 0) {
|
|
9360
|
+
const result = input.link.result;
|
|
9361
|
+
walletLinkData(result, "Saved link result", [
|
|
9362
|
+
"status",
|
|
9363
|
+
"submittedHash",
|
|
9364
|
+
"hash",
|
|
9365
|
+
"receipt",
|
|
9366
|
+
"replacementReason"
|
|
9367
|
+
]);
|
|
9368
|
+
if (!["confirmed", "reverted", "unverified", "replaced"].includes(result.status) || result.submittedHash.toLowerCase() !== input.link.hash?.toLowerCase() || result.receipt.transactionHash.toLowerCase() !== result.hash.toLowerCase())
|
|
9369
|
+
invalid("Saved link result does not match its submission.");
|
|
9370
|
+
issuerBytes(result.hash, "result hash", 32);
|
|
9371
|
+
if (result.status === "confirmed" && (result.hash.toLowerCase() !== result.submittedHash.toLowerCase() || result.receipt.status !== "success"))
|
|
9372
|
+
invalid("Saved confirmed result is inconsistent.");
|
|
9373
|
+
}
|
|
9374
|
+
if (input.stage === "complete" && (input.link.stage !== "complete" || input.link.result?.status !== "confirmed"))
|
|
9375
|
+
invalid("Saved wallet completion requires a confirmed link.");
|
|
9376
|
+
if (input.link.stage === "complete" && input.link.result?.status !== "confirmed")
|
|
9377
|
+
invalid("Saved link completion requires confirmation.");
|
|
9378
|
+
if (issuerChainId(input.chainId) !== intent.chainId || !sameIssuerAddress(
|
|
9379
|
+
issuerAddress(input.registryAddress, "registryAddress"),
|
|
9380
|
+
intent.registryAddress
|
|
9381
|
+
) || !sameIssuerAddress(issuerAddress(input.wallet, "wallet"), intent.newWallet) || !sameIssuerAddress(
|
|
9382
|
+
issuerAddress(input.existingWallet, "existingWallet"),
|
|
9383
|
+
intent.existingWallet
|
|
9384
|
+
) || issuerBytes(input.userId, "userId", 32).toLowerCase() !== intent.userId.toLowerCase())
|
|
9385
|
+
invalid("Saved wallet and link identities do not match.");
|
|
9386
|
+
try {
|
|
9387
|
+
if (!sameIssuerAddress(
|
|
9388
|
+
accounts.privateKeyToAccount(issuerBytes(input.privateKey, "privateKey", 32)).address,
|
|
9389
|
+
intent.newWallet
|
|
9390
|
+
))
|
|
9391
|
+
invalid("Saved key and wallet do not match.");
|
|
9392
|
+
} catch {
|
|
9393
|
+
invalid("Saved key and wallet do not match.");
|
|
9394
|
+
}
|
|
9395
|
+
return structuredClone(input);
|
|
9396
|
+
}
|
|
9397
|
+
function restoreSandboxLinkedWallet(input, options) {
|
|
9398
|
+
const progress = validateSandboxLinkedWalletProgress(input);
|
|
9399
|
+
if (progress.stage !== "complete")
|
|
9400
|
+
invalid("Check the pending link before restoring this wallet for transactions.");
|
|
9401
|
+
return restoreSandboxUserWallet(
|
|
9402
|
+
{
|
|
9403
|
+
wallet: progress.wallet,
|
|
9404
|
+
privateKey: progress.privateKey,
|
|
9405
|
+
userId: progress.userId,
|
|
9406
|
+
chainId: progress.chainId,
|
|
9407
|
+
registryAddress: progress.registryAddress,
|
|
9408
|
+
stage: "complete",
|
|
9409
|
+
traits: [],
|
|
9410
|
+
submissions: []
|
|
9411
|
+
},
|
|
9412
|
+
options
|
|
9413
|
+
);
|
|
9414
|
+
}
|
|
8644
9415
|
|
|
8645
9416
|
Object.defineProperty(exports, "SANDBOX_CHAIN_ID", {
|
|
8646
9417
|
enumerable: true,
|
|
@@ -8830,8 +9601,10 @@ exports.OpacityPurchaseError = OpacityPurchaseError;
|
|
|
8830
9601
|
exports.OpacityTransferError = OpacityTransferError;
|
|
8831
9602
|
exports.SANDBOX_ISSUER_DEPLOYMENT = SANDBOX_ISSUER_DEPLOYMENT;
|
|
8832
9603
|
exports.SANDBOX_PURCHASE_DEPLOYMENT = SANDBOX_PURCHASE_DEPLOYMENT;
|
|
9604
|
+
exports.SandboxLinkedWalletCreationError = SandboxLinkedWalletCreationError;
|
|
8833
9605
|
exports.SandboxTransferError = SandboxTransferError;
|
|
8834
9606
|
exports.SandboxUserCreationError = SandboxUserCreationError;
|
|
9607
|
+
exports.SandboxWalletLinkError = SandboxWalletLinkError;
|
|
8835
9608
|
exports.buildAdapterOperation = buildAdapterOperation;
|
|
8836
9609
|
exports.buildConfigureVaultTransaction = buildConfigureVaultTransaction;
|
|
8837
9610
|
exports.buildForcedTransferTransaction = buildForcedTransferTransaction;
|
|
@@ -8856,6 +9629,8 @@ exports.buildPurchaseWriteRequest = buildPurchaseWriteRequest;
|
|
|
8856
9629
|
exports.buildRuleSetOperation = buildRuleSetOperation;
|
|
8857
9630
|
exports.buildSandboxRegistryOperation = buildSandboxRegistryOperation;
|
|
8858
9631
|
exports.buildSandboxVaultOperation = buildSandboxVaultOperation;
|
|
9632
|
+
exports.buildSandboxWalletLinkTransaction = buildSandboxWalletLinkTransaction;
|
|
9633
|
+
exports.buildSandboxWalletLinkTypedData = buildSandboxWalletLinkTypedData;
|
|
8859
9634
|
exports.buildSetIssuerAdminTransaction = buildSetIssuerAdminTransaction;
|
|
8860
9635
|
exports.buildSetUserTraitsTransactions = buildSetUserTraitsTransactions;
|
|
8861
9636
|
exports.buildSetWalletsTransaction = buildSetWalletsTransaction;
|
|
@@ -8869,7 +9644,9 @@ exports.createPolicyAttachment = createPolicyAttachment;
|
|
|
8869
9644
|
exports.createPolicyBatch = createPolicyBatch;
|
|
8870
9645
|
exports.createPolicyReplacementBatch = createPolicyReplacementBatch;
|
|
8871
9646
|
exports.createPurchasesNamespace = createPurchasesNamespace;
|
|
9647
|
+
exports.createSandboxLinkedWallet = createSandboxLinkedWallet;
|
|
8872
9648
|
exports.createSandboxUser = createSandboxUser;
|
|
9649
|
+
exports.createSandboxWalletLinksNamespace = createSandboxWalletLinksNamespace;
|
|
8873
9650
|
exports.createTransfersNamespace = createTransfersNamespace;
|
|
8874
9651
|
exports.encodeAllowedTransfereeConfig = encodeAllowedTransfereeConfig;
|
|
8875
9652
|
exports.encodeCeilingBalanceConfig = encodeCeilingBalanceConfig;
|
|
@@ -8907,11 +9684,19 @@ exports.purchasePaymentTokenAbi = purchasePaymentTokenAbi;
|
|
|
8907
9684
|
exports.purchaseRegistryAbi = purchaseRegistryAbi;
|
|
8908
9685
|
exports.purchaseSecurityTokenAbi = purchaseSecurityTokenAbi;
|
|
8909
9686
|
exports.resolveSandboxUserTraits = resolveSandboxUserTraits;
|
|
9687
|
+
exports.restoreSandboxLinkedWallet = restoreSandboxLinkedWallet;
|
|
8910
9688
|
exports.restoreSandboxUserWallet = restoreSandboxUserWallet;
|
|
8911
9689
|
exports.sandboxJurisdictionTraitId = sandboxJurisdictionTraitId;
|
|
8912
9690
|
exports.sandboxTraitId = sandboxTraitId;
|
|
9691
|
+
exports.sandboxWalletLinkAbi = sandboxWalletLinkAbi;
|
|
9692
|
+
exports.sandboxWalletLinkTypes = sandboxWalletLinkTypes;
|
|
8913
9693
|
exports.securityTokenVaultAbi = securityTokenVaultAbi;
|
|
8914
9694
|
exports.transferSandboxUser = transferSandboxUser;
|
|
9695
|
+
exports.validateSandboxLinkedWalletProgress = validateSandboxLinkedWalletProgress;
|
|
9696
|
+
exports.validateSandboxWalletLinkIntent = validateSandboxWalletLinkIntent;
|
|
9697
|
+
exports.validateSandboxWalletLinkParams = validateSandboxWalletLinkParams;
|
|
8915
9698
|
exports.waitForSandboxUserFunding = waitForSandboxUserFunding;
|
|
9699
|
+
exports.walletLinkData = walletLinkData;
|
|
9700
|
+
exports.walletLinkWaitOptions = walletLinkWaitOptions;
|
|
8916
9701
|
//# sourceMappingURL=index.cjs.map
|
|
8917
9702
|
//# sourceMappingURL=index.cjs.map
|