@fairblock/stabletrust 2.0.14 → 2.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -5
- package/package.json +1 -1
- package/src/backend.js +2 -0
- package/src/constants.js +27 -15
- package/src/index.d.ts +4 -1
- package/src/index.js +10 -1
- package/src/predicate-contract.js +126 -0
- package/src/predicate-fee-aware-clients.js +31 -0
package/README.md
CHANGED
|
@@ -63,13 +63,23 @@ The following contract addresses are available for confidential transfers on tes
|
|
|
63
63
|
|
|
64
64
|
| Network(Testnet) | Chain ID | Contract Address |
|
|
65
65
|
| :--------------- | :------- | :------------------------------------------- |
|
|
66
|
-
| Stable | 2201 | `
|
|
67
|
-
| Arc | 5042002 | `
|
|
68
|
-
| Base | 84532 | `
|
|
69
|
-
| Ethereum | 11155111 | `
|
|
70
|
-
| Arbitrum | 421614 | `
|
|
66
|
+
| Stable | 2201 | `0x0b6791C168ffBF52e82F5E862929Dbf505c3A46E` |
|
|
67
|
+
| Arc | 5042002 | `0xA90621B79d49c8E3A5eeEBcaaa839E2f886240C5` |
|
|
68
|
+
| Base | 84532 | `0xb6cdAE7ccfEE03e351694c63436D5c5c073aEF84` |
|
|
69
|
+
| Ethereum | 11155111 | `0x5A061604A1d94f4fa9939544707f6B200d6bB5cf` |
|
|
70
|
+
| Arbitrum | 421614 | `0x147C6D8cA1a4784Ed76d98b0E3CcA41C38a49A5f` |
|
|
71
71
|
| Tempo | 42431 | `0xE559fB936C69c46E216bf61B07C16bF1a6d444aa` |
|
|
72
72
|
|
|
73
|
+
## Available Confidential Contract Addresses (Mainnet)
|
|
74
|
+
|
|
75
|
+
The following contract addresses are **live mainnet** deployments:
|
|
76
|
+
|
|
77
|
+
| Network(Mainnet) | Chain ID | Contract Address |
|
|
78
|
+
| :--------------- | :------- | :------------------------------------------- |
|
|
79
|
+
| Arbitrum One | 42161 | `0xCAA6384D5Ac8b9111D482dd676BB890f2b6e9513` |
|
|
80
|
+
| Base | 8453 | `0xF90a80eef61e934CF20E5B4fa48FBe9F5fB58aED` |
|
|
81
|
+
| Ethereum | 1 | `0xa9661635cc97756190973Ef281d4529693EcAcD0` |
|
|
82
|
+
|
|
73
83
|
---
|
|
74
84
|
|
|
75
85
|
## ConfidentialTransferClient
|
package/package.json
CHANGED
package/src/backend.js
CHANGED
package/src/constants.js
CHANGED
|
@@ -2,15 +2,25 @@
|
|
|
2
2
|
* Contract ABIs and Constants
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
|
|
5
|
+
export const PREDICATE_ATTESTATION_SIGNATURE =
|
|
6
|
+
"(string,uint256,address,bytes)";
|
|
7
|
+
const PREDICATE_ATTESTATION_ABI =
|
|
8
|
+
"(string uuid,uint256 expiration,address attester,bytes signature) attestation";
|
|
9
|
+
|
|
10
|
+
export const CREATE_CONFIDENTIAL_ACCOUNT_SIGNATURE =
|
|
11
|
+
`createConfidentialAccount(bytes,${PREDICATE_ATTESTATION_SIGNATURE})`;
|
|
12
|
+
export const DEPOSIT_SIGNATURE =
|
|
13
|
+
`deposit(address,uint256,${PREDICATE_ATTESTATION_SIGNATURE})`;
|
|
7
14
|
const GET_ACCOUNT_CORE_SIGNATURE = "getAccountCore(address)";
|
|
8
15
|
const GET_AVAILABLE_SIGNATURE = "getAvailable(address,address)";
|
|
9
16
|
const GET_PENDING_SIGNATURE = "getPending(address,address)";
|
|
10
|
-
const APPLY_PENDING_SIGNATURE =
|
|
17
|
+
export const APPLY_PENDING_SIGNATURE =
|
|
18
|
+
`applyPending(${PREDICATE_ATTESTATION_SIGNATURE})`;
|
|
11
19
|
|
|
12
|
-
export const TRANSFER_CONFIDENTIAL_SIGNATURE =
|
|
13
|
-
|
|
20
|
+
export const TRANSFER_CONFIDENTIAL_SIGNATURE =
|
|
21
|
+
`transferConfidential(address,address,bytes,bool,${PREDICATE_ATTESTATION_SIGNATURE})`;
|
|
22
|
+
export const WITHDRAW_CONFIDENTIAL_SIGNATURE =
|
|
23
|
+
`withdraw(address,uint256,bytes,bool,${PREDICATE_ATTESTATION_SIGNATURE})`;
|
|
14
24
|
export const FEE_TOKEN_SIGNATURE = "feeToken()";
|
|
15
25
|
export const FEE_ACCOUNT_SIGNATURE = "feeAccount()";
|
|
16
26
|
export const NON_ANONYMOUS_TRANSFER_FEE_SIGNATURE = "nonAnonymousTransferFee()";
|
|
@@ -21,14 +31,14 @@ export const ANONYMOUS_INLINE_TRANSFER_FEE_SIGNATURE = "anonymousInlineTransferF
|
|
|
21
31
|
export const ANONYMOUS_WITHDRAW_FEE_PPM_SIGNATURE = "anonymousWithdrawFeePpm()";
|
|
22
32
|
|
|
23
33
|
export const CONTRACT_ABI = [
|
|
24
|
-
`function
|
|
25
|
-
`function
|
|
34
|
+
`function createConfidentialAccount(bytes elgamalPubkey,${PREDICATE_ATTESTATION_ABI}) external`,
|
|
35
|
+
`function deposit(address token,uint256 plainAmount,${PREDICATE_ATTESTATION_ABI}) external`,
|
|
26
36
|
`function ${GET_ACCOUNT_CORE_SIGNATURE} external view returns ((bool exists, bool finalized, bool pendingAction, uint256 txId, bytes elgamalPubkey, uint64 pendingCreditCounter))`,
|
|
27
37
|
`function ${GET_AVAILABLE_SIGNATURE} external view returns (bytes c1, bytes c2)`,
|
|
28
38
|
`function ${GET_PENDING_SIGNATURE} external view returns (bytes c1, bytes c2)`,
|
|
29
|
-
`function
|
|
30
|
-
`function
|
|
31
|
-
`function ${
|
|
39
|
+
`function transferConfidential(address recipient,address token,bytes proof,bool offchainZKP,${PREDICATE_ATTESTATION_ABI}) external payable`,
|
|
40
|
+
`function withdraw(address token,uint256 plainAmount,bytes proof,bool offchainZKP,${PREDICATE_ATTESTATION_ABI}) external payable`,
|
|
41
|
+
`function applyPending(${PREDICATE_ATTESTATION_ABI}) external`,
|
|
32
42
|
`function ${FEE_TOKEN_SIGNATURE} external view returns (address)`,
|
|
33
43
|
`function ${FEE_ACCOUNT_SIGNATURE} external view returns (address)`,
|
|
34
44
|
`function ${NON_ANONYMOUS_TRANSFER_FEE_SIGNATURE} external view returns (uint256)`,
|
|
@@ -63,13 +73,15 @@ export const ERC20_ABI = [
|
|
|
63
73
|
export const TEMPO_FEE_TOKEN_ADDRESS =
|
|
64
74
|
"0x20c0000000000000000000000000000000000000";
|
|
65
75
|
export const STABLETRUST_CONTRACTS_BY_CHAIN_ID = Object.freeze({
|
|
66
|
-
2201: "
|
|
67
|
-
5042002: "
|
|
68
|
-
84532: "
|
|
69
|
-
11155111: "
|
|
70
|
-
421614: "
|
|
76
|
+
2201: "0x0b6791C168ffBF52e82F5E862929Dbf505c3A46E", //Stable
|
|
77
|
+
5042002: "0xA90621B79d49c8E3A5eeEBcaaa839E2f886240C5", //Arc
|
|
78
|
+
84532: "0xb6cdAE7ccfEE03e351694c63436D5c5c073aEF84", //Base
|
|
79
|
+
11155111: "0x5A061604A1d94f4fa9939544707f6B200d6bB5cf", //Ethereum
|
|
80
|
+
421614: "0x147C6D8cA1a4784Ed76d98b0E3CcA41C38a49A5f", //Arbitrum Sepolia
|
|
71
81
|
42431: "0xE559fB936C69c46E216bf61B07C16bF1a6d444aa", //Tempo
|
|
72
82
|
42161: "0xCAA6384D5Ac8b9111D482dd676BB890f2b6e9513", //Arbitrum One (mainnet)
|
|
83
|
+
8453: "0xF90a80eef61e934CF20E5B4fa48FBe9F5fB58aED", //Base (mainnet)
|
|
84
|
+
1: "0xa9661635cc97756190973Ef281d4529693EcAcD0", //Ethereum (mainnet)
|
|
73
85
|
});
|
|
74
86
|
|
|
75
87
|
export function getStabletrustContractAddress(chainId) {
|
package/src/index.d.ts
CHANGED
package/src/index.js
CHANGED
|
@@ -3,7 +3,7 @@ export {
|
|
|
3
3
|
ControlledConfidentialTransferClient,
|
|
4
4
|
AnonymousTransferClient,
|
|
5
5
|
WITHDRAW_FEE_PPM_DENOMINATOR,
|
|
6
|
-
} from "./fee-aware-clients.js";
|
|
6
|
+
} from "./predicate-fee-aware-clients.js";
|
|
7
7
|
export { deriveKeys, decryptCiphertext, combineCiphertext } from "./crypto.js";
|
|
8
8
|
export {
|
|
9
9
|
encodeTransferProof,
|
|
@@ -14,7 +14,11 @@ export {
|
|
|
14
14
|
export {
|
|
15
15
|
CONTRACT_ABI,
|
|
16
16
|
ERC20_ABI,
|
|
17
|
+
PREDICATE_ATTESTATION_SIGNATURE,
|
|
18
|
+
CREATE_CONFIDENTIAL_ACCOUNT_SIGNATURE,
|
|
19
|
+
DEPOSIT_SIGNATURE,
|
|
17
20
|
TRANSFER_CONFIDENTIAL_SIGNATURE,
|
|
21
|
+
APPLY_PENDING_SIGNATURE,
|
|
18
22
|
WITHDRAW_CONFIDENTIAL_SIGNATURE,
|
|
19
23
|
FEE_TOKEN_SIGNATURE,
|
|
20
24
|
FEE_ACCOUNT_SIGNATURE,
|
|
@@ -27,4 +31,9 @@ export {
|
|
|
27
31
|
STABLETRUST_CONTRACTS_BY_CHAIN_ID,
|
|
28
32
|
getStabletrustContractAddress,
|
|
29
33
|
} from "./constants.js";
|
|
34
|
+
export {
|
|
35
|
+
emptyPredicateAttestation,
|
|
36
|
+
injectPredicateAttestation,
|
|
37
|
+
isPredicateAttestation,
|
|
38
|
+
} from "./predicate-contract.js";
|
|
30
39
|
// Note: initializeWasm is now internal - WASM auto-initializes on first client use
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { ethers } from "ethers";
|
|
2
|
+
|
|
3
|
+
const PREDICATE_BUSINESS_ARG_COUNTS = Object.freeze({
|
|
4
|
+
createConfidentialAccount: 1,
|
|
5
|
+
deposit: 2,
|
|
6
|
+
transferConfidential: 4,
|
|
7
|
+
applyPending: 0,
|
|
8
|
+
withdraw: 4,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const METHOD_HELPERS = [
|
|
12
|
+
"estimateGas",
|
|
13
|
+
"populateTransaction",
|
|
14
|
+
"send",
|
|
15
|
+
"staticCall",
|
|
16
|
+
"staticCallResult",
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const PREDICATE_WRAPPED = Symbol("stabletrust.predicateWrappedContract");
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Empty Predicate attestation used while on-chain Predicate enforcement is off.
|
|
23
|
+
* A fresh array is returned for each call so callers/ethers never share mutable
|
|
24
|
+
* tuple state between transactions.
|
|
25
|
+
*/
|
|
26
|
+
export function emptyPredicateAttestation() {
|
|
27
|
+
return ["", 0n, ethers.ZeroAddress, "0x"];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function isPredicateAttestation(value) {
|
|
31
|
+
if (Array.isArray(value)) return value.length === 4;
|
|
32
|
+
if (!value || typeof value !== "object") return false;
|
|
33
|
+
return (
|
|
34
|
+
"uuid" in value &&
|
|
35
|
+
"expiration" in value &&
|
|
36
|
+
"attester" in value &&
|
|
37
|
+
"signature" in value
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Convert the pre-Predicate SDK call shape into the upgraded Diamond call shape.
|
|
43
|
+
* Existing SDK methods may optionally append an ethers transaction-overrides
|
|
44
|
+
* object, so the attestation must be inserted immediately before overrides.
|
|
45
|
+
*
|
|
46
|
+
* Calls that already contain an explicit attestation are left unchanged. This
|
|
47
|
+
* makes the wrapped contract usable directly by applications that obtain a real
|
|
48
|
+
* Predicate attestation later.
|
|
49
|
+
*/
|
|
50
|
+
export function injectPredicateAttestation(methodName, args) {
|
|
51
|
+
const businessArgCount = PREDICATE_BUSINESS_ARG_COUNTS[methodName];
|
|
52
|
+
if (businessArgCount === undefined) return args;
|
|
53
|
+
|
|
54
|
+
if (args.length === businessArgCount) {
|
|
55
|
+
return [...args, emptyPredicateAttestation()];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (args.length === businessArgCount + 1) {
|
|
59
|
+
if (isPredicateAttestation(args[businessArgCount])) {
|
|
60
|
+
return args;
|
|
61
|
+
}
|
|
62
|
+
return [
|
|
63
|
+
...args.slice(0, businessArgCount),
|
|
64
|
+
emptyPredicateAttestation(),
|
|
65
|
+
args[businessArgCount],
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (
|
|
70
|
+
args.length === businessArgCount + 2 &&
|
|
71
|
+
isPredicateAttestation(args[businessArgCount])
|
|
72
|
+
) {
|
|
73
|
+
return args;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Let ethers surface its normal argument-count/type error for malformed calls.
|
|
77
|
+
return args;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function wrapPredicateMethod(methodName, method) {
|
|
81
|
+
const wrapped = (...args) =>
|
|
82
|
+
method(...injectPredicateAttestation(methodName, args));
|
|
83
|
+
|
|
84
|
+
for (const helperName of METHOD_HELPERS) {
|
|
85
|
+
const helper = method?.[helperName];
|
|
86
|
+
if (typeof helper === "function") {
|
|
87
|
+
wrapped[helperName] = (...args) =>
|
|
88
|
+
helper(...injectPredicateAttestation(methodName, args));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return wrapped;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Wrap an ethers Contract so the SDK's existing high-level methods keep their
|
|
97
|
+
* public API while targeting the upgraded Attestation-bearing selectors.
|
|
98
|
+
*
|
|
99
|
+
* `connect()` is wrapped recursively because every state-changing SDK path uses
|
|
100
|
+
* `this.contract.connect(wallet)` before invoking the contract.
|
|
101
|
+
*/
|
|
102
|
+
export function wrapPredicateContract(contract) {
|
|
103
|
+
if (!contract || contract[PREDICATE_WRAPPED]) return contract;
|
|
104
|
+
|
|
105
|
+
return new Proxy(contract, {
|
|
106
|
+
get(target, prop) {
|
|
107
|
+
if (prop === PREDICATE_WRAPPED) return true;
|
|
108
|
+
|
|
109
|
+
if (prop === "connect") {
|
|
110
|
+
return (runner) => wrapPredicateContract(target.connect(runner));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (
|
|
114
|
+
typeof prop === "string" &&
|
|
115
|
+
Object.prototype.hasOwnProperty.call(PREDICATE_BUSINESS_ARG_COUNTS, prop)
|
|
116
|
+
) {
|
|
117
|
+
const method = target[prop];
|
|
118
|
+
if (typeof method === "function") {
|
|
119
|
+
return wrapPredicateMethod(prop, method);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return Reflect.get(target, prop, target);
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ConfidentialTransferClient as FeeAwareConfidentialTransferClient,
|
|
3
|
+
ControlledConfidentialTransferClient as FeeAwareControlledConfidentialTransferClient,
|
|
4
|
+
AnonymousTransferClient,
|
|
5
|
+
WITHDRAW_FEE_PPM_DENOMINATOR,
|
|
6
|
+
} from "./fee-aware-clients.js";
|
|
7
|
+
import { wrapPredicateContract } from "./predicate-contract.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Public non-anonymous clients target the upgraded ConfidentialMirror ABI.
|
|
11
|
+
* Existing SDK methods still call the pre-Predicate argument shape internally;
|
|
12
|
+
* the wrapped ethers Contract inserts an empty attestation while enforcement is
|
|
13
|
+
* disabled, without changing the high-level SDK API.
|
|
14
|
+
*/
|
|
15
|
+
export class ConfidentialTransferClient extends FeeAwareConfidentialTransferClient {
|
|
16
|
+
constructor(...args) {
|
|
17
|
+
super(...args);
|
|
18
|
+
this.contract = wrapPredicateContract(this.contract);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class ControlledConfidentialTransferClient extends FeeAwareControlledConfidentialTransferClient {
|
|
23
|
+
constructor(...args) {
|
|
24
|
+
super(...args);
|
|
25
|
+
this.contract = wrapPredicateContract(this.contract);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Anonymous flows are intentionally not Predicate-gated and must remain
|
|
30
|
+
// byte-for-byte/API compatible with the existing anonymous client behavior.
|
|
31
|
+
export { AnonymousTransferClient, WITHDRAW_FEE_PPM_DENOMINATOR };
|