bstest001 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/circuits/transaction2.wasm +0 -0
- package/circuits/transaction2.zkey +0 -0
- package/dist/balance.d.ts +7 -0
- package/dist/balance.js +46 -0
- package/dist/deposit.d.ts +8 -0
- package/dist/deposit.js +136 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/utils/EtherPool.abi.json +798 -0
- package/dist/utils/constants.d.ts +8 -0
- package/dist/utils/constants.js +8 -0
- package/dist/utils/encryption.d.ts +8 -0
- package/dist/utils/encryption.js +34 -0
- package/dist/utils/keypair.d.ts +9 -0
- package/dist/utils/keypair.js +19 -0
- package/dist/utils/logger.d.ts +9 -0
- package/dist/utils/logger.js +35 -0
- package/dist/utils/prover.d.ts +9 -0
- package/dist/utils/prover.js +63 -0
- package/dist/utils/utils.d.ts +82 -0
- package/dist/utils/utils.js +202 -0
- package/dist/utils/utxo.d.ts +20 -0
- package/dist/utils/utxo.js +55 -0
- package/dist/withdraw.d.ts +7 -0
- package/dist/withdraw.js +123 -0
- package/package.json +30 -0
- package/src/balance.ts +55 -0
- package/src/deposit.ts +157 -0
- package/src/index.ts +5 -0
- package/src/utils/EtherPool.abi.json +798 -0
- package/src/utils/constants.ts +10 -0
- package/src/utils/encryption.ts +40 -0
- package/src/utils/keypair.ts +24 -0
- package/src/utils/logger.ts +42 -0
- package/src/utils/prover.ts +82 -0
- package/src/utils/utils.ts +295 -0
- package/src/utils/utxo.ts +74 -0
- package/src/withdraw.ts +153 -0
- package/tsconfig.json +29 -0
package/README.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# base SDK
|
|
2
|
+
|
|
3
|
+
## test
|
|
4
|
+
add to .env:
|
|
5
|
+
```
|
|
6
|
+
PRIVATE_KEY=[your private key]
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Check balance:
|
|
10
|
+
```bash
|
|
11
|
+
bun example/test.ts balance
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Deposit:
|
|
15
|
+
```bash
|
|
16
|
+
bun example/test.ts deposit
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Withdraw:
|
|
20
|
+
```bash
|
|
21
|
+
bun example/test.ts withdraw
|
|
22
|
+
```
|
|
Binary file
|
|
Binary file
|
package/dist/balance.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { BigNumber, ethers } from 'ethers';
|
|
2
|
+
import EtherPoolAbi from './utils/EtherPool.abi.json' with { type: 'json' };
|
|
3
|
+
import { BASE_SEPOLIA_RPC, CONTRACT_ADDRESS } from './utils/constants.js';
|
|
4
|
+
import { deriveKeys } from './utils/encryption.js';
|
|
5
|
+
import { logger } from './utils/logger';
|
|
6
|
+
import { findUnspentUtxos, toFixedHex } from './utils/utils.js';
|
|
7
|
+
export async function getBalance({ provider: rawProvider, signature, address }) {
|
|
8
|
+
const provider = rawProvider?.request
|
|
9
|
+
? new ethers.providers.Web3Provider(rawProvider)
|
|
10
|
+
: rawProvider;
|
|
11
|
+
// Use a dedicated JSON-RPC provider for contract reads so they always
|
|
12
|
+
// target the correct chain, regardless of which chain the wallet is on.
|
|
13
|
+
const readProvider = new ethers.providers.JsonRpcProvider(BASE_SEPOLIA_RPC);
|
|
14
|
+
const etherPoolAddress = CONTRACT_ADDRESS;
|
|
15
|
+
if (!etherPoolAddress) {
|
|
16
|
+
throw new Error('Missing CONTRACT_ADDRESS in environment');
|
|
17
|
+
}
|
|
18
|
+
const contractAddress = ethers.utils.getAddress(etherPoolAddress);
|
|
19
|
+
logger.debug(`Address: ${address}`);
|
|
20
|
+
logger.debug('Signing in to derive keys...');
|
|
21
|
+
const { encryptionKey, keypair } = deriveKeys(signature);
|
|
22
|
+
logger.debug(`UTXO pubkey: ${toFixedHex(keypair.pubkey)}`);
|
|
23
|
+
const etherPool = new ethers.Contract(contractAddress, EtherPoolAbi, readProvider);
|
|
24
|
+
const poolBalance = await readProvider.getBalance(etherPool.address);
|
|
25
|
+
logger.debug(`EtherPool: ${etherPool.address}`);
|
|
26
|
+
logger.debug(`Pool on-chain balance: ${ethers.utils.formatEther(poolBalance)} ETH`);
|
|
27
|
+
// Scan on-chain events and decrypt to find our UTXOs
|
|
28
|
+
logger.debug('Scanning on-chain events...');
|
|
29
|
+
const unspent = await findUnspentUtxos({
|
|
30
|
+
etherPool,
|
|
31
|
+
encryptionKey,
|
|
32
|
+
keypair
|
|
33
|
+
});
|
|
34
|
+
logger.debug(`Unspent UTXOs: ${unspent.length}`);
|
|
35
|
+
let total = BigNumber.from(0);
|
|
36
|
+
for (let i = 0; i < unspent.length; i++) {
|
|
37
|
+
const utxo = unspent[i];
|
|
38
|
+
logger.debug(` #${i}: ${ethers.utils.formatEther(utxo.amount)} ETH (index: ${utxo.index})`);
|
|
39
|
+
total = total.add(utxo.amount);
|
|
40
|
+
}
|
|
41
|
+
let balance = ethers.utils.formatEther(total);
|
|
42
|
+
logger.debug(`\nTotal unspent: ${ethers.utils.formatEther(total)} ETH`);
|
|
43
|
+
return {
|
|
44
|
+
balance
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function deposit({ provider: rawProvider, depositAmountInput, keyBasePath, signature, address, txSender }: {
|
|
2
|
+
provider: any;
|
|
3
|
+
depositAmountInput: number;
|
|
4
|
+
keyBasePath: string;
|
|
5
|
+
signature: string;
|
|
6
|
+
address: string;
|
|
7
|
+
txSender: any;
|
|
8
|
+
}): Promise<any>;
|
package/dist/deposit.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { BigNumber, ethers } from 'ethers';
|
|
2
|
+
import EtherPoolAbi from './utils/EtherPool.abi.json' with { type: 'json' };
|
|
3
|
+
import { BASE_SEPOLIA_RPC, CONTRACT_ADDRESS, INDEXER_URL } from './utils/constants.js';
|
|
4
|
+
import { deriveKeys } from './utils/encryption.js';
|
|
5
|
+
import { logger } from './utils/logger';
|
|
6
|
+
import { findUnspentUtxos, prepareTransaction, toFixedHex } from './utils/utils.js';
|
|
7
|
+
import { Utxo } from './utils/utxo.js';
|
|
8
|
+
export async function deposit({ provider: rawProvider, depositAmountInput, keyBasePath, signature, address, txSender }) {
|
|
9
|
+
const provider = rawProvider?.request
|
|
10
|
+
? new ethers.providers.Web3Provider(rawProvider)
|
|
11
|
+
: rawProvider;
|
|
12
|
+
const readProvider = new ethers.providers.JsonRpcProvider(BASE_SEPOLIA_RPC);
|
|
13
|
+
const etherPoolAddress = CONTRACT_ADDRESS;
|
|
14
|
+
if (!etherPoolAddress) {
|
|
15
|
+
throw new Error('Missing CONTRACT_ADDRESS in environment');
|
|
16
|
+
}
|
|
17
|
+
const contractAddress = ethers.utils.getAddress(etherPoolAddress);
|
|
18
|
+
logger.debug(`Depositor: ${address}`);
|
|
19
|
+
logger.info('Signing in to derive keys...');
|
|
20
|
+
const { encryptionKey, keypair } = deriveKeys(signature);
|
|
21
|
+
logger.debug(`UTXO pubkey: ${toFixedHex(keypair.pubkey)}`);
|
|
22
|
+
const etherPool = new ethers.Contract(contractAddress, EtherPoolAbi, readProvider);
|
|
23
|
+
const poolBalance = await readProvider.getBalance(etherPool.address);
|
|
24
|
+
logger.debug(`EtherPool: ${etherPool.address}`);
|
|
25
|
+
logger.debug(`Pool balance: ${ethers.utils.formatEther(poolBalance)} ETH`);
|
|
26
|
+
const depositAmount = ethers.utils.parseEther(depositAmountInput.toString());
|
|
27
|
+
const maxDeposit = await etherPool.maximumDepositAmount();
|
|
28
|
+
if (depositAmount.gt(maxDeposit)) {
|
|
29
|
+
throw new Error(`Deposit amount ${depositAmountInput} ETH exceeds pool limit of ${ethers.utils.formatEther(maxDeposit)} ETH`);
|
|
30
|
+
}
|
|
31
|
+
// post address to /screen_address of indexer to check if it's blacklisted
|
|
32
|
+
logger.debug(`screening address ${address}`);
|
|
33
|
+
let res = await fetch(INDEXER_URL + '/screen_address', {
|
|
34
|
+
method: 'POST',
|
|
35
|
+
headers: {
|
|
36
|
+
'Content-Type': 'application/json',
|
|
37
|
+
},
|
|
38
|
+
body: JSON.stringify({ address }),
|
|
39
|
+
});
|
|
40
|
+
let resJson = await res.json();
|
|
41
|
+
if (resJson.isRisk) {
|
|
42
|
+
throw new Error('Your wallet address is risky. Service rejected.');
|
|
43
|
+
}
|
|
44
|
+
logger.debug('Address screening passed');
|
|
45
|
+
// Scan on-chain events to find unspent UTXOs
|
|
46
|
+
logger.debug('Scanning on-chain events for unspent UTXOs...');
|
|
47
|
+
const unspent = await findUnspentUtxos({
|
|
48
|
+
etherPool,
|
|
49
|
+
encryptionKey,
|
|
50
|
+
keypair
|
|
51
|
+
});
|
|
52
|
+
logger.debug(`Unspent UTXOs found: ${unspent.length}`);
|
|
53
|
+
let inputs = [];
|
|
54
|
+
let inputSum = BigNumber.from(0);
|
|
55
|
+
if (unspent.length >= 2) {
|
|
56
|
+
inputs = [unspent[0], unspent[1]];
|
|
57
|
+
inputSum = inputs[0].amount.add(inputs[1].amount);
|
|
58
|
+
logger.debug(`Using 2 existing UTXOs as inputs (${ethers.utils.formatEther(inputSum)} ETH)`);
|
|
59
|
+
}
|
|
60
|
+
else if (unspent.length === 1) {
|
|
61
|
+
inputs = [unspent[0]];
|
|
62
|
+
inputSum = inputs[0].amount;
|
|
63
|
+
logger.debug(`Using 1 existing UTXO as input (${ethers.utils.formatEther(inputSum)} ETH)`);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
logger.debug('No existing UTXOs, creating fresh deposit');
|
|
67
|
+
}
|
|
68
|
+
const outputAmount = inputSum.add(depositAmount);
|
|
69
|
+
const outputUtxo = new Utxo({ amount: outputAmount, keypair });
|
|
70
|
+
logger.debug(`Depositing ${depositAmountInput} ETH (new output: ${ethers.utils.formatEther(outputAmount)} ETH)`);
|
|
71
|
+
const { args, extData } = await prepareTransaction({
|
|
72
|
+
inputs,
|
|
73
|
+
outputs: [outputUtxo],
|
|
74
|
+
encryptionKey,
|
|
75
|
+
keyBasePath,
|
|
76
|
+
});
|
|
77
|
+
// Build the transaction (Populate)
|
|
78
|
+
logger.info('Building transaction...');
|
|
79
|
+
const partialTx = await etherPool.populateTransaction.transact(args, extData, {
|
|
80
|
+
value: depositAmount,
|
|
81
|
+
gasLimit: 3000000,
|
|
82
|
+
});
|
|
83
|
+
const [network, nonce, feeData] = await Promise.all([
|
|
84
|
+
readProvider.getNetwork(),
|
|
85
|
+
readProvider.getTransactionCount(address, 'pending'),
|
|
86
|
+
readProvider.getFeeData(),
|
|
87
|
+
]);
|
|
88
|
+
const unsignedTx = {
|
|
89
|
+
...partialTx,
|
|
90
|
+
nonce,
|
|
91
|
+
chainId: network.chainId,
|
|
92
|
+
};
|
|
93
|
+
if (feeData.gasPrice) {
|
|
94
|
+
unsignedTx.gasPrice = feeData.gasPrice;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
throw new Error('Failed to fetch network fee data for transaction signing');
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
let tx = await txSender(unsignedTx);
|
|
101
|
+
logger.info(`Transaction sent!`);
|
|
102
|
+
logger.debug('veryfying transaction on indexer...', extData.encryptedOutput1);
|
|
103
|
+
let retryTimes = 0;
|
|
104
|
+
let itv = 2;
|
|
105
|
+
// const encryptedOutputStr = Buffer.from(extData.encryptedOutput1).toString('hex')
|
|
106
|
+
let start = Date.now();
|
|
107
|
+
while (true) {
|
|
108
|
+
logger.debug('Confirming transaction..');
|
|
109
|
+
logger.debug(`retryTimes: ${retryTimes}`);
|
|
110
|
+
await new Promise(resolve => setTimeout(resolve, itv * 1000));
|
|
111
|
+
logger.debug('Fetching updated onchain state...');
|
|
112
|
+
// post to /check_encrypted_output with body encryptedOutput: extData.encryptedOutput1
|
|
113
|
+
let res = await fetch(INDEXER_URL + '/check_encrypted_output', {
|
|
114
|
+
method: 'POST',
|
|
115
|
+
headers: {
|
|
116
|
+
'Content-Type': 'application/json',
|
|
117
|
+
},
|
|
118
|
+
body: JSON.stringify({ encryptedOutput: extData.encryptedOutput1 }),
|
|
119
|
+
});
|
|
120
|
+
let resJson = await res.json();
|
|
121
|
+
if (resJson.exists) {
|
|
122
|
+
logger.debug(`Top up successfully in ${((Date.now() - start) / 1000).toFixed(2)} seconds!`);
|
|
123
|
+
// break while true loop
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
if (retryTimes >= 10) {
|
|
127
|
+
throw new Error('Refresh the page to see latest balance.');
|
|
128
|
+
}
|
|
129
|
+
retryTimes++;
|
|
130
|
+
}
|
|
131
|
+
return tx;
|
|
132
|
+
}
|
|
133
|
+
catch (e) {
|
|
134
|
+
logger.error('Transaction failed:', e);
|
|
135
|
+
}
|
|
136
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED