@flatcash/bearerswap 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,142 @@
1
+ # @flatcash/bearerswap
2
+
3
+ **Private token transfers on Ethereum.** Send any ERC-20 token without revealing sender-recipient links on-chain.
4
+
5
+ BearerSwap uses a commit-reveal pattern with a privacy relayer that adds timing randomization, breaking the correlation between deposit and withdrawal.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @flatcash/bearerswap ethers
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```typescript
16
+ import { BearerSwap } from '@flatcash/bearerswap';
17
+
18
+ // Initialize with your private key (sender)
19
+ const bs = new BearerSwap({
20
+ privateKey: process.env.PRIVATE_KEY,
21
+ rpcUrl: 'https://eth.drpc.org',
22
+ });
23
+
24
+ // 1. Commit tokens (locks them in the contract)
25
+ const { secret, nonce, txHash } = await bs.commit(
26
+ '0x853d955aCEf822Db058eb8505911ED77F175b99e', // FLAT token
27
+ '100.0', // amount
28
+ '0xRecipientAddress...' // recipient
29
+ );
30
+
31
+ console.log(`Committed! TX: ${txHash}`);
32
+ console.log(`Share these with recipient: secret=${secret}, nonce=${nonce}`);
33
+
34
+ // 2. Deliver (recipient or anyone calls this)
35
+ const delivery = await bs.deliver(secret, recipientAddress, nonce);
36
+ console.log(`Delivery queued! ETA: ${delivery.estimatedDeliveryMinutes} min`);
37
+ ```
38
+
39
+ ## How It Works
40
+
41
+ ```
42
+ Sender Contract Relayer Recipient
43
+ | | | |
44
+ |-- commit(hash, token) -->| | |
45
+ | (locks tokens + ETH) | | |
46
+ | | | |
47
+ |--- share secret+nonce ---|------------------------|------> (off-chain) --->|
48
+ | | | |
49
+ | | |<-- deliver(s,r,n) -----|
50
+ | | | |
51
+ | | (random 2-45 min) | |
52
+ | | | |
53
+ | |<--- reveal(s,r,n) -----| |
54
+ | |--- tokens + ETH -------|----------------------->|
55
+ ```
56
+
57
+ **Privacy guarantees:**
58
+ - On-chain, the commit contains only a hash — no recipient info
59
+ - The relayer adds a random delay (2–45 min, exponential distribution)
60
+ - The recipient receives tokens + a small ETH stipend for gas
61
+ - No link between sender and recipient is visible on-chain
62
+
63
+ ## API Reference
64
+
65
+ ### `new BearerSwap(config)`
66
+
67
+ | Option | Type | Default | Description |
68
+ |--------|------|---------|-------------|
69
+ | `relayerUrl` | string | `https://flat.cash` | Relayer API URL |
70
+ | `rpcUrl` | string | `https://eth.drpc.org` | Ethereum RPC endpoint |
71
+ | `privateKey` | string | — | Sender's private key |
72
+ | `provider` | ethers.Provider | — | Custom provider |
73
+ | `signer` | ethers.Signer | — | Custom signer |
74
+
75
+ ### `bs.commit(token, amount, recipient, decimals?)`
76
+
77
+ Locks tokens in the BearerSwap contract. Returns `{ secret, nonce, commitHash, txHash }`.
78
+
79
+ ### `bs.deliver(secret, recipient, nonce)`
80
+
81
+ Queues the reveal via the relayer. Returns `{ success, estimatedDeliveryMinutes, flatAmount }`.
82
+
83
+ ### `bs.status()`
84
+
85
+ Returns relayer health: balance, queue size, availability.
86
+
87
+ ### `bs.resolve(identifier)`
88
+
89
+ Resolves a FlatID username or ENS name to an Ethereum address.
90
+
91
+ ### `BearerSwap.computeHash(secret, recipient, nonce)`
92
+
93
+ Static helper to compute the commit hash for verification.
94
+
95
+ ## Use Cases
96
+
97
+ ### AI Agent Payments
98
+ ```typescript
99
+ // Your autonomous agent pays for services privately
100
+ const bs = new BearerSwap({ privateKey: AGENT_WALLET_KEY });
101
+ const { secret, nonce } = await bs.commit(FLAT_TOKEN, '10.0', serviceProvider);
102
+ // Agent shares secret with service provider via API
103
+ await fetch(serviceProviderUrl, { body: JSON.stringify({ secret, nonce }) });
104
+ ```
105
+
106
+ ### Private Payroll
107
+ ```typescript
108
+ // Pay employees without revealing individual salaries on-chain
109
+ for (const employee of employees) {
110
+ const { secret, nonce } = await bs.commit(FLAT_TOKEN, employee.salary, employee.address);
111
+ await sendEncryptedMessage(employee.email, { secret, nonce });
112
+ }
113
+ ```
114
+
115
+ ### Tipping / Donations
116
+ ```typescript
117
+ // Anonymous tips to content creators
118
+ const { secret, nonce } = await bs.commit(FLAT_TOKEN, '5.0', creatorAddress);
119
+ // Share via any private channel
120
+ ```
121
+
122
+ ## Supported Tokens
123
+
124
+ Any ERC-20 token on Ethereum mainnet. Primary tokens:
125
+ - **FLAT** (`0x853d955aCEf822Db058eb8505911ED77F175b99e`) — CPI-pegged stablecoin
126
+ - **SAVE** — Locked FLAT with yield
127
+
128
+ ## Contract
129
+
130
+ - **BearerSwap V3:** `0x5de315Dab49012c5bbeC41d7a3B25c6829a3e566`
131
+ - **Network:** Ethereum Mainnet
132
+ - **Verified on Etherscan:** [View Contract](https://etherscan.io/address/0x5de315Dab49012c5bbeC41d7a3B25c6829a3e566)
133
+
134
+ ## Fees
135
+
136
+ - **Protocol fee:** 0 (no fees extracted)
137
+ - **Gas:** Sender pays commit gas + ETH stipend (~0.0004 ETH)
138
+ - **Relayer:** Free — operated by the FLAT Protocol
139
+
140
+ ## License
141
+
142
+ MIT — Flat Protocol team
@@ -0,0 +1,147 @@
1
+ import { ethers } from 'ethers';
2
+
3
+ /**
4
+ * @flatcash/bearerswap — Private token transfers on Ethereum
5
+ *
6
+ * BearerSwap lets you send ERC-20 tokens privately using a commit-reveal
7
+ * pattern with a relayer that adds timing randomization for privacy.
8
+ *
9
+ * Usage:
10
+ * import { BearerSwap } from '@flatcash/bearerswap';
11
+ * const bs = new BearerSwap({ relayerUrl: 'https://flat.cash' });
12
+ * const { secret, nonce, txHash } = await bs.commit(token, amount, recipient);
13
+ * // Share secret + nonce + recipient with the receiver (off-chain)
14
+ * const delivery = await bs.deliver(secret, recipient, nonce);
15
+ */
16
+
17
+ interface BearerSwapConfig {
18
+ /** Relayer API base URL (default: https://flat.cash) */
19
+ relayerUrl?: string;
20
+ /** Ethereum RPC URL for on-chain operations */
21
+ rpcUrl?: string;
22
+ /** Private key for signing commit transactions (sender) */
23
+ privateKey?: string;
24
+ /** Ethers provider (alternative to rpcUrl) */
25
+ provider?: ethers.Provider;
26
+ /** Ethers signer (alternative to privateKey + provider) */
27
+ signer?: ethers.Signer;
28
+ }
29
+ interface CommitResult {
30
+ /** The secret (bytes32) — share with recipient off-chain */
31
+ secret: string;
32
+ /** The nonce (bytes32) — share with recipient off-chain */
33
+ nonce: string;
34
+ /** The commit hash stored on-chain */
35
+ commitHash: string;
36
+ /** Transaction hash of the commit */
37
+ txHash: string;
38
+ /** Amount committed (human-readable) */
39
+ amount: string;
40
+ /** Token address */
41
+ token: string;
42
+ /** Recipient address */
43
+ recipient: string;
44
+ }
45
+ interface DeliverResult {
46
+ /** Whether the delivery was queued successfully */
47
+ success: boolean;
48
+ /** Current status */
49
+ status: "queued" | "already_settled";
50
+ /** Estimated delivery time in minutes (privacy delay) */
51
+ estimatedDeliveryMinutes: number;
52
+ /** Amount being delivered (human-readable) */
53
+ flatAmount: string;
54
+ /** Recipient address */
55
+ recipient: string;
56
+ /** Commit hash */
57
+ hash: string;
58
+ }
59
+ interface RelayerStatus {
60
+ /** BearerSwap contract address */
61
+ contract: string;
62
+ /** Contract version */
63
+ version: string;
64
+ /** Number of reveals pending in queue */
65
+ pendingInQueue: number;
66
+ /** ETH stipend sent with each reveal */
67
+ recipientStipend: string;
68
+ /** Relayer wallet address */
69
+ relayerAddress?: string;
70
+ /** Relayer ETH balance */
71
+ relayerBalanceEth?: string;
72
+ /** Whether the contract is paused */
73
+ contractPaused?: boolean;
74
+ /** Whether the relayer is available */
75
+ available?: boolean;
76
+ }
77
+ interface ResolveResult {
78
+ /** Resolved Ethereum address */
79
+ address: string;
80
+ /** Type of identifier resolved */
81
+ type: "address" | "ens" | "flatid";
82
+ /** Display name (username or ENS) */
83
+ displayName: string | null;
84
+ }
85
+ declare const BEARERSWAP_V3_ADDRESS = "0x5de315Dab49012c5bbeC41d7a3B25c6829a3e566";
86
+ declare const BEARERSWAP_V3_ABI: string[];
87
+ declare class BearerSwap {
88
+ private relayerUrl;
89
+ private provider;
90
+ private signer;
91
+ constructor(config?: BearerSwapConfig);
92
+ /** Contract address */
93
+ get contractAddress(): string;
94
+ /**
95
+ * Commit tokens on-chain for private transfer.
96
+ *
97
+ * This locks tokens in the BearerSwap contract. The returned secret and
98
+ * nonce must be shared with the recipient off-chain (e.g., via encrypted
99
+ * message, QR code, or any private channel).
100
+ *
101
+ * @param token - ERC-20 token address
102
+ * @param amount - Amount to send (human-readable, e.g., "100.0")
103
+ * @param recipient - Recipient Ethereum address
104
+ * @param decimals - Token decimals (default: 18)
105
+ */
106
+ commit(token: string, amount: string, recipient: string, decimals?: number): Promise<CommitResult>;
107
+ /**
108
+ * Deliver a committed transfer to the recipient via the relayer.
109
+ *
110
+ * The relayer adds a random privacy delay (2–45 min) before executing
111
+ * the on-chain reveal, breaking timing correlation between commit and reveal.
112
+ *
113
+ * @param secret - The secret from the commit step
114
+ * @param recipient - The recipient address
115
+ * @param nonce - The nonce from the commit step
116
+ */
117
+ deliver(secret: string, recipient: string, nonce: string): Promise<DeliverResult>;
118
+ /**
119
+ * Check relayer status (balance, queue size, availability).
120
+ */
121
+ status(): Promise<RelayerStatus>;
122
+ /**
123
+ * Resolve a FlatID username or ENS name to an Ethereum address.
124
+ *
125
+ * @param identifier - FlatID username, ENS name, or Ethereum address
126
+ */
127
+ resolve(identifier: string): Promise<ResolveResult>;
128
+ /**
129
+ * Check the status of a specific commitment on-chain.
130
+ *
131
+ * @param commitHash - The commit hash (bytes32)
132
+ */
133
+ getCommitment(commitHash: string): Promise<{
134
+ sender: string;
135
+ token: string;
136
+ amount: bigint;
137
+ timestamp: bigint;
138
+ settled: boolean;
139
+ }>;
140
+ /**
141
+ * Compute the commit hash from secret, recipient, and nonce.
142
+ * Useful for verifying parameters before delivery.
143
+ */
144
+ static computeHash(secret: string, recipient: string, nonce: string): string;
145
+ }
146
+
147
+ export { BEARERSWAP_V3_ABI, BEARERSWAP_V3_ADDRESS, BearerSwap, type BearerSwapConfig, type CommitResult, type DeliverResult, type RelayerStatus, type ResolveResult, BearerSwap as default };
@@ -0,0 +1,147 @@
1
+ import { ethers } from 'ethers';
2
+
3
+ /**
4
+ * @flatcash/bearerswap — Private token transfers on Ethereum
5
+ *
6
+ * BearerSwap lets you send ERC-20 tokens privately using a commit-reveal
7
+ * pattern with a relayer that adds timing randomization for privacy.
8
+ *
9
+ * Usage:
10
+ * import { BearerSwap } from '@flatcash/bearerswap';
11
+ * const bs = new BearerSwap({ relayerUrl: 'https://flat.cash' });
12
+ * const { secret, nonce, txHash } = await bs.commit(token, amount, recipient);
13
+ * // Share secret + nonce + recipient with the receiver (off-chain)
14
+ * const delivery = await bs.deliver(secret, recipient, nonce);
15
+ */
16
+
17
+ interface BearerSwapConfig {
18
+ /** Relayer API base URL (default: https://flat.cash) */
19
+ relayerUrl?: string;
20
+ /** Ethereum RPC URL for on-chain operations */
21
+ rpcUrl?: string;
22
+ /** Private key for signing commit transactions (sender) */
23
+ privateKey?: string;
24
+ /** Ethers provider (alternative to rpcUrl) */
25
+ provider?: ethers.Provider;
26
+ /** Ethers signer (alternative to privateKey + provider) */
27
+ signer?: ethers.Signer;
28
+ }
29
+ interface CommitResult {
30
+ /** The secret (bytes32) — share with recipient off-chain */
31
+ secret: string;
32
+ /** The nonce (bytes32) — share with recipient off-chain */
33
+ nonce: string;
34
+ /** The commit hash stored on-chain */
35
+ commitHash: string;
36
+ /** Transaction hash of the commit */
37
+ txHash: string;
38
+ /** Amount committed (human-readable) */
39
+ amount: string;
40
+ /** Token address */
41
+ token: string;
42
+ /** Recipient address */
43
+ recipient: string;
44
+ }
45
+ interface DeliverResult {
46
+ /** Whether the delivery was queued successfully */
47
+ success: boolean;
48
+ /** Current status */
49
+ status: "queued" | "already_settled";
50
+ /** Estimated delivery time in minutes (privacy delay) */
51
+ estimatedDeliveryMinutes: number;
52
+ /** Amount being delivered (human-readable) */
53
+ flatAmount: string;
54
+ /** Recipient address */
55
+ recipient: string;
56
+ /** Commit hash */
57
+ hash: string;
58
+ }
59
+ interface RelayerStatus {
60
+ /** BearerSwap contract address */
61
+ contract: string;
62
+ /** Contract version */
63
+ version: string;
64
+ /** Number of reveals pending in queue */
65
+ pendingInQueue: number;
66
+ /** ETH stipend sent with each reveal */
67
+ recipientStipend: string;
68
+ /** Relayer wallet address */
69
+ relayerAddress?: string;
70
+ /** Relayer ETH balance */
71
+ relayerBalanceEth?: string;
72
+ /** Whether the contract is paused */
73
+ contractPaused?: boolean;
74
+ /** Whether the relayer is available */
75
+ available?: boolean;
76
+ }
77
+ interface ResolveResult {
78
+ /** Resolved Ethereum address */
79
+ address: string;
80
+ /** Type of identifier resolved */
81
+ type: "address" | "ens" | "flatid";
82
+ /** Display name (username or ENS) */
83
+ displayName: string | null;
84
+ }
85
+ declare const BEARERSWAP_V3_ADDRESS = "0x5de315Dab49012c5bbeC41d7a3B25c6829a3e566";
86
+ declare const BEARERSWAP_V3_ABI: string[];
87
+ declare class BearerSwap {
88
+ private relayerUrl;
89
+ private provider;
90
+ private signer;
91
+ constructor(config?: BearerSwapConfig);
92
+ /** Contract address */
93
+ get contractAddress(): string;
94
+ /**
95
+ * Commit tokens on-chain for private transfer.
96
+ *
97
+ * This locks tokens in the BearerSwap contract. The returned secret and
98
+ * nonce must be shared with the recipient off-chain (e.g., via encrypted
99
+ * message, QR code, or any private channel).
100
+ *
101
+ * @param token - ERC-20 token address
102
+ * @param amount - Amount to send (human-readable, e.g., "100.0")
103
+ * @param recipient - Recipient Ethereum address
104
+ * @param decimals - Token decimals (default: 18)
105
+ */
106
+ commit(token: string, amount: string, recipient: string, decimals?: number): Promise<CommitResult>;
107
+ /**
108
+ * Deliver a committed transfer to the recipient via the relayer.
109
+ *
110
+ * The relayer adds a random privacy delay (2–45 min) before executing
111
+ * the on-chain reveal, breaking timing correlation between commit and reveal.
112
+ *
113
+ * @param secret - The secret from the commit step
114
+ * @param recipient - The recipient address
115
+ * @param nonce - The nonce from the commit step
116
+ */
117
+ deliver(secret: string, recipient: string, nonce: string): Promise<DeliverResult>;
118
+ /**
119
+ * Check relayer status (balance, queue size, availability).
120
+ */
121
+ status(): Promise<RelayerStatus>;
122
+ /**
123
+ * Resolve a FlatID username or ENS name to an Ethereum address.
124
+ *
125
+ * @param identifier - FlatID username, ENS name, or Ethereum address
126
+ */
127
+ resolve(identifier: string): Promise<ResolveResult>;
128
+ /**
129
+ * Check the status of a specific commitment on-chain.
130
+ *
131
+ * @param commitHash - The commit hash (bytes32)
132
+ */
133
+ getCommitment(commitHash: string): Promise<{
134
+ sender: string;
135
+ token: string;
136
+ amount: bigint;
137
+ timestamp: bigint;
138
+ settled: boolean;
139
+ }>;
140
+ /**
141
+ * Compute the commit hash from secret, recipient, and nonce.
142
+ * Useful for verifying parameters before delivery.
143
+ */
144
+ static computeHash(secret: string, recipient: string, nonce: string): string;
145
+ }
146
+
147
+ export { BEARERSWAP_V3_ABI, BEARERSWAP_V3_ADDRESS, BearerSwap, type BearerSwapConfig, type CommitResult, type DeliverResult, type RelayerStatus, type ResolveResult, BearerSwap as default };
package/dist/index.js ADDED
@@ -0,0 +1,218 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ BEARERSWAP_V3_ABI: () => BEARERSWAP_V3_ABI,
24
+ BEARERSWAP_V3_ADDRESS: () => BEARERSWAP_V3_ADDRESS,
25
+ BearerSwap: () => BearerSwap,
26
+ default: () => index_default
27
+ });
28
+ module.exports = __toCommonJS(index_exports);
29
+ var import_ethers = require("ethers");
30
+ var BEARERSWAP_V3_ADDRESS = "0x5de315Dab49012c5bbeC41d7a3B25c6829a3e566";
31
+ var BEARERSWAP_V3_ABI = [
32
+ "function commit(bytes32 hash, address token, uint256 amount) external payable",
33
+ "function reveal(bytes32 secret, address recipient, bytes32 nonce) external",
34
+ "function commitments(bytes32 hash) view returns (address sender, address token, uint256 amount, uint256 timestamp, bool settled)",
35
+ "function paused() view returns (bool)",
36
+ "function pendingCount() view returns (uint256)",
37
+ "function getRecommendedETH() view returns (uint256)",
38
+ "function getMinETH() pure returns (uint256)",
39
+ "function verifyPreimage(bytes32 secret, address recipient, bytes32 nonce) view returns (bytes32)"
40
+ ];
41
+ var ERC20_ABI = [
42
+ "function approve(address spender, uint256 amount) external returns (bool)",
43
+ "function allowance(address owner, address spender) view returns (uint256)",
44
+ "function balanceOf(address account) view returns (uint256)",
45
+ "function decimals() view returns (uint8)"
46
+ ];
47
+ var BearerSwap = class {
48
+ constructor(config = {}) {
49
+ this.provider = null;
50
+ this.signer = null;
51
+ this.relayerUrl = (config.relayerUrl || "https://flat.cash").replace(
52
+ /\/$/,
53
+ ""
54
+ );
55
+ if (config.signer) {
56
+ this.signer = config.signer;
57
+ this.provider = config.signer.provider || null;
58
+ } else if (config.privateKey) {
59
+ const provider = config.provider || new import_ethers.ethers.JsonRpcProvider(config.rpcUrl || "https://eth.drpc.org");
60
+ this.provider = provider;
61
+ this.signer = new import_ethers.ethers.Wallet(config.privateKey, provider);
62
+ } else if (config.provider) {
63
+ this.provider = config.provider;
64
+ }
65
+ }
66
+ /** Contract address */
67
+ get contractAddress() {
68
+ return BEARERSWAP_V3_ADDRESS;
69
+ }
70
+ /**
71
+ * Commit tokens on-chain for private transfer.
72
+ *
73
+ * This locks tokens in the BearerSwap contract. The returned secret and
74
+ * nonce must be shared with the recipient off-chain (e.g., via encrypted
75
+ * message, QR code, or any private channel).
76
+ *
77
+ * @param token - ERC-20 token address
78
+ * @param amount - Amount to send (human-readable, e.g., "100.0")
79
+ * @param recipient - Recipient Ethereum address
80
+ * @param decimals - Token decimals (default: 18)
81
+ */
82
+ async commit(token, amount, recipient, decimals = 18) {
83
+ if (!this.signer) {
84
+ throw new Error(
85
+ "Signer required for commit. Provide privateKey or signer in config."
86
+ );
87
+ }
88
+ const secret = import_ethers.ethers.hexlify(import_ethers.ethers.randomBytes(32));
89
+ const nonce = import_ethers.ethers.hexlify(import_ethers.ethers.randomBytes(32));
90
+ const commitHash = import_ethers.ethers.solidityPackedKeccak256(
91
+ ["bytes32", "address", "bytes32"],
92
+ [secret, recipient, nonce]
93
+ );
94
+ const amountWei = import_ethers.ethers.parseUnits(amount, decimals);
95
+ const tokenContract = new import_ethers.ethers.Contract(token, ERC20_ABI, this.signer);
96
+ const signerAddress = await this.signer.getAddress();
97
+ const currentAllowance = await tokenContract.allowance(
98
+ signerAddress,
99
+ BEARERSWAP_V3_ADDRESS
100
+ );
101
+ if (currentAllowance < amountWei) {
102
+ const approveTx = await tokenContract.approve(
103
+ BEARERSWAP_V3_ADDRESS,
104
+ amountWei
105
+ );
106
+ await approveTx.wait();
107
+ }
108
+ const contract = new import_ethers.ethers.Contract(
109
+ BEARERSWAP_V3_ADDRESS,
110
+ BEARERSWAP_V3_ABI,
111
+ this.signer
112
+ );
113
+ const recommendedETH = await contract.getRecommendedETH();
114
+ const tx = await contract.commit(commitHash, token, amountWei, {
115
+ value: recommendedETH,
116
+ gasLimit: 15e4
117
+ });
118
+ const receipt = await tx.wait();
119
+ return {
120
+ secret,
121
+ nonce,
122
+ commitHash,
123
+ txHash: receipt.hash,
124
+ amount,
125
+ token,
126
+ recipient
127
+ };
128
+ }
129
+ /**
130
+ * Deliver a committed transfer to the recipient via the relayer.
131
+ *
132
+ * The relayer adds a random privacy delay (2–45 min) before executing
133
+ * the on-chain reveal, breaking timing correlation between commit and reveal.
134
+ *
135
+ * @param secret - The secret from the commit step
136
+ * @param recipient - The recipient address
137
+ * @param nonce - The nonce from the commit step
138
+ */
139
+ async deliver(secret, recipient, nonce) {
140
+ const response = await fetch(`${this.relayerUrl}/api/bearer/deliver`, {
141
+ method: "POST",
142
+ headers: { "Content-Type": "application/json" },
143
+ body: JSON.stringify({ secret, recipient, nonce })
144
+ });
145
+ if (!response.ok) {
146
+ const error = await response.json().catch(() => ({ error: "Unknown error" }));
147
+ throw new Error(
148
+ `Delivery failed (${response.status}): ${error.error || error.details || "Unknown error"}`
149
+ );
150
+ }
151
+ return response.json();
152
+ }
153
+ /**
154
+ * Check relayer status (balance, queue size, availability).
155
+ */
156
+ async status() {
157
+ const response = await fetch(`${this.relayerUrl}/api/bearer/status`);
158
+ if (!response.ok) {
159
+ throw new Error(`Status check failed (${response.status})`);
160
+ }
161
+ return response.json();
162
+ }
163
+ /**
164
+ * Resolve a FlatID username or ENS name to an Ethereum address.
165
+ *
166
+ * @param identifier - FlatID username, ENS name, or Ethereum address
167
+ */
168
+ async resolve(identifier) {
169
+ const response = await fetch(
170
+ `${this.relayerUrl}/api/bearer/resolve/${encodeURIComponent(identifier)}`
171
+ );
172
+ if (!response.ok) {
173
+ const error = await response.json().catch(() => ({ error: "Not found" }));
174
+ throw new Error(
175
+ `Resolve failed (${response.status}): ${error.error || "Not found"}`
176
+ );
177
+ }
178
+ return response.json();
179
+ }
180
+ /**
181
+ * Check the status of a specific commitment on-chain.
182
+ *
183
+ * @param commitHash - The commit hash (bytes32)
184
+ */
185
+ async getCommitment(commitHash) {
186
+ const provider = this.provider || new import_ethers.ethers.JsonRpcProvider("https://eth.drpc.org");
187
+ const contract = new import_ethers.ethers.Contract(
188
+ BEARERSWAP_V3_ADDRESS,
189
+ BEARERSWAP_V3_ABI,
190
+ provider
191
+ );
192
+ const result = await contract.commitments(commitHash);
193
+ return {
194
+ sender: result.sender,
195
+ token: result.token,
196
+ amount: result.amount,
197
+ timestamp: result.timestamp,
198
+ settled: result.settled
199
+ };
200
+ }
201
+ /**
202
+ * Compute the commit hash from secret, recipient, and nonce.
203
+ * Useful for verifying parameters before delivery.
204
+ */
205
+ static computeHash(secret, recipient, nonce) {
206
+ return import_ethers.ethers.solidityPackedKeccak256(
207
+ ["bytes32", "address", "bytes32"],
208
+ [secret, recipient, nonce]
209
+ );
210
+ }
211
+ };
212
+ var index_default = BearerSwap;
213
+ // Annotate the CommonJS export names for ESM import in node:
214
+ 0 && (module.exports = {
215
+ BEARERSWAP_V3_ABI,
216
+ BEARERSWAP_V3_ADDRESS,
217
+ BearerSwap
218
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,191 @@
1
+ // src/index.ts
2
+ import { ethers } from "ethers";
3
+ var BEARERSWAP_V3_ADDRESS = "0x5de315Dab49012c5bbeC41d7a3B25c6829a3e566";
4
+ var BEARERSWAP_V3_ABI = [
5
+ "function commit(bytes32 hash, address token, uint256 amount) external payable",
6
+ "function reveal(bytes32 secret, address recipient, bytes32 nonce) external",
7
+ "function commitments(bytes32 hash) view returns (address sender, address token, uint256 amount, uint256 timestamp, bool settled)",
8
+ "function paused() view returns (bool)",
9
+ "function pendingCount() view returns (uint256)",
10
+ "function getRecommendedETH() view returns (uint256)",
11
+ "function getMinETH() pure returns (uint256)",
12
+ "function verifyPreimage(bytes32 secret, address recipient, bytes32 nonce) view returns (bytes32)"
13
+ ];
14
+ var ERC20_ABI = [
15
+ "function approve(address spender, uint256 amount) external returns (bool)",
16
+ "function allowance(address owner, address spender) view returns (uint256)",
17
+ "function balanceOf(address account) view returns (uint256)",
18
+ "function decimals() view returns (uint8)"
19
+ ];
20
+ var BearerSwap = class {
21
+ constructor(config = {}) {
22
+ this.provider = null;
23
+ this.signer = null;
24
+ this.relayerUrl = (config.relayerUrl || "https://flat.cash").replace(
25
+ /\/$/,
26
+ ""
27
+ );
28
+ if (config.signer) {
29
+ this.signer = config.signer;
30
+ this.provider = config.signer.provider || null;
31
+ } else if (config.privateKey) {
32
+ const provider = config.provider || new ethers.JsonRpcProvider(config.rpcUrl || "https://eth.drpc.org");
33
+ this.provider = provider;
34
+ this.signer = new ethers.Wallet(config.privateKey, provider);
35
+ } else if (config.provider) {
36
+ this.provider = config.provider;
37
+ }
38
+ }
39
+ /** Contract address */
40
+ get contractAddress() {
41
+ return BEARERSWAP_V3_ADDRESS;
42
+ }
43
+ /**
44
+ * Commit tokens on-chain for private transfer.
45
+ *
46
+ * This locks tokens in the BearerSwap contract. The returned secret and
47
+ * nonce must be shared with the recipient off-chain (e.g., via encrypted
48
+ * message, QR code, or any private channel).
49
+ *
50
+ * @param token - ERC-20 token address
51
+ * @param amount - Amount to send (human-readable, e.g., "100.0")
52
+ * @param recipient - Recipient Ethereum address
53
+ * @param decimals - Token decimals (default: 18)
54
+ */
55
+ async commit(token, amount, recipient, decimals = 18) {
56
+ if (!this.signer) {
57
+ throw new Error(
58
+ "Signer required for commit. Provide privateKey or signer in config."
59
+ );
60
+ }
61
+ const secret = ethers.hexlify(ethers.randomBytes(32));
62
+ const nonce = ethers.hexlify(ethers.randomBytes(32));
63
+ const commitHash = ethers.solidityPackedKeccak256(
64
+ ["bytes32", "address", "bytes32"],
65
+ [secret, recipient, nonce]
66
+ );
67
+ const amountWei = ethers.parseUnits(amount, decimals);
68
+ const tokenContract = new ethers.Contract(token, ERC20_ABI, this.signer);
69
+ const signerAddress = await this.signer.getAddress();
70
+ const currentAllowance = await tokenContract.allowance(
71
+ signerAddress,
72
+ BEARERSWAP_V3_ADDRESS
73
+ );
74
+ if (currentAllowance < amountWei) {
75
+ const approveTx = await tokenContract.approve(
76
+ BEARERSWAP_V3_ADDRESS,
77
+ amountWei
78
+ );
79
+ await approveTx.wait();
80
+ }
81
+ const contract = new ethers.Contract(
82
+ BEARERSWAP_V3_ADDRESS,
83
+ BEARERSWAP_V3_ABI,
84
+ this.signer
85
+ );
86
+ const recommendedETH = await contract.getRecommendedETH();
87
+ const tx = await contract.commit(commitHash, token, amountWei, {
88
+ value: recommendedETH,
89
+ gasLimit: 15e4
90
+ });
91
+ const receipt = await tx.wait();
92
+ return {
93
+ secret,
94
+ nonce,
95
+ commitHash,
96
+ txHash: receipt.hash,
97
+ amount,
98
+ token,
99
+ recipient
100
+ };
101
+ }
102
+ /**
103
+ * Deliver a committed transfer to the recipient via the relayer.
104
+ *
105
+ * The relayer adds a random privacy delay (2–45 min) before executing
106
+ * the on-chain reveal, breaking timing correlation between commit and reveal.
107
+ *
108
+ * @param secret - The secret from the commit step
109
+ * @param recipient - The recipient address
110
+ * @param nonce - The nonce from the commit step
111
+ */
112
+ async deliver(secret, recipient, nonce) {
113
+ const response = await fetch(`${this.relayerUrl}/api/bearer/deliver`, {
114
+ method: "POST",
115
+ headers: { "Content-Type": "application/json" },
116
+ body: JSON.stringify({ secret, recipient, nonce })
117
+ });
118
+ if (!response.ok) {
119
+ const error = await response.json().catch(() => ({ error: "Unknown error" }));
120
+ throw new Error(
121
+ `Delivery failed (${response.status}): ${error.error || error.details || "Unknown error"}`
122
+ );
123
+ }
124
+ return response.json();
125
+ }
126
+ /**
127
+ * Check relayer status (balance, queue size, availability).
128
+ */
129
+ async status() {
130
+ const response = await fetch(`${this.relayerUrl}/api/bearer/status`);
131
+ if (!response.ok) {
132
+ throw new Error(`Status check failed (${response.status})`);
133
+ }
134
+ return response.json();
135
+ }
136
+ /**
137
+ * Resolve a FlatID username or ENS name to an Ethereum address.
138
+ *
139
+ * @param identifier - FlatID username, ENS name, or Ethereum address
140
+ */
141
+ async resolve(identifier) {
142
+ const response = await fetch(
143
+ `${this.relayerUrl}/api/bearer/resolve/${encodeURIComponent(identifier)}`
144
+ );
145
+ if (!response.ok) {
146
+ const error = await response.json().catch(() => ({ error: "Not found" }));
147
+ throw new Error(
148
+ `Resolve failed (${response.status}): ${error.error || "Not found"}`
149
+ );
150
+ }
151
+ return response.json();
152
+ }
153
+ /**
154
+ * Check the status of a specific commitment on-chain.
155
+ *
156
+ * @param commitHash - The commit hash (bytes32)
157
+ */
158
+ async getCommitment(commitHash) {
159
+ const provider = this.provider || new ethers.JsonRpcProvider("https://eth.drpc.org");
160
+ const contract = new ethers.Contract(
161
+ BEARERSWAP_V3_ADDRESS,
162
+ BEARERSWAP_V3_ABI,
163
+ provider
164
+ );
165
+ const result = await contract.commitments(commitHash);
166
+ return {
167
+ sender: result.sender,
168
+ token: result.token,
169
+ amount: result.amount,
170
+ timestamp: result.timestamp,
171
+ settled: result.settled
172
+ };
173
+ }
174
+ /**
175
+ * Compute the commit hash from secret, recipient, and nonce.
176
+ * Useful for verifying parameters before delivery.
177
+ */
178
+ static computeHash(secret, recipient, nonce) {
179
+ return ethers.solidityPackedKeccak256(
180
+ ["bytes32", "address", "bytes32"],
181
+ [secret, recipient, nonce]
182
+ );
183
+ }
184
+ };
185
+ var index_default = BearerSwap;
186
+ export {
187
+ BEARERSWAP_V3_ABI,
188
+ BEARERSWAP_V3_ADDRESS,
189
+ BearerSwap,
190
+ index_default as default
191
+ };
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@flatcash/bearerswap",
3
+ "version": "1.0.0",
4
+ "description": "BearerSwap SDK — Private token transfers on Ethereum. Send any ERC-20 token privately with zero-knowledge commit-reveal.",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.mjs",
11
+ "require": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": ["dist", "README.md"],
16
+ "keywords": ["ethereum", "privacy", "erc20", "token-transfer", "bearerswap", "flat", "save", "commit-reveal", "private-transfer"],
17
+ "license": "MIT",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/AuditTester1/bearerswap-sdk"
21
+ },
22
+ "homepage": "https://flat.cash/developers",
23
+ "peerDependencies": {
24
+ "ethers": "^6.0.0"
25
+ },
26
+ "devDependencies": {
27
+ "ethers": "^6.13.0",
28
+ "tsup": "^8.0.0",
29
+ "typescript": "^5.5.0"
30
+ },
31
+ "scripts": {
32
+ "build": "tsup src/index.ts --format cjs,esm --dts",
33
+ "prepublishOnly": "npm run build"
34
+ }
35
+ }