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 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
@@ -0,0 +1,7 @@
1
+ export declare function getBalance({ provider: rawProvider, signature, address }: {
2
+ provider: any;
3
+ signature: string;
4
+ address: string;
5
+ }): Promise<{
6
+ balance: string;
7
+ }>;
@@ -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>;
@@ -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
+ }
@@ -0,0 +1,4 @@
1
+ export { getBalance } from './balance.js';
2
+ export { deposit } from './deposit.js';
3
+ export { setLogger } from './utils/logger.js';
4
+ export { withdraw } from './withdraw.js';
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { getBalance } from './balance.js';
2
+ export { deposit } from './deposit.js';
3
+ export { setLogger } from './utils/logger.js';
4
+ export { withdraw } from './withdraw.js';