Rename variables and update package name

This commit is contained in:
Prathamesh Musale 2024-07-17 14:10:46 +05:30
parent f06792a946
commit e271982345
5 changed files with 54 additions and 17 deletions

View File

@ -11,4 +11,4 @@ RUN yarn && yarn build
EXPOSE 3000 EXPOSE 3000
# Run the app # Run the app
CMD ["yarn", "start-faucet"] CMD ["node", "dist/index.js"]

View File

@ -11,7 +11,7 @@
* Run the faucet: * Run the faucet:
```bash ```bash
yarn start-faucet yarn start
# Expected output: # Expected output:
# Config: # Config:
@ -19,3 +19,14 @@
# Faucet server running on port <port> # Faucet server running on port <port>
# Using DB directory '/path/to/faucet/data/db' # Using DB directory '/path/to/faucet/data/db'
``` ```
* Example request:
```bash
curl -X POST http://localhost:3000/faucet \
-H "Content-Type: application/json" \
-d '{"address": "laconic1cndafgkspae7es7g2j52hmxxukwsy84v6h07w5"}'
# Expected output:
# {"success":true,"txHash":"40405D3CCA8122482C36083762561908E2595A4B765B7457C3995525991D18CE"}
```

View File

@ -3,10 +3,11 @@
chainId = "laconic_9000-1" chainId = "laconic_9000-1"
denom = "photon" denom = "photon"
prefix = "laconic" prefix = "laconic"
gasPrice = "0.01"
faucetKey = "" faucetKey = ""
[server] [server]
port = 3000 port = 3000
transferAmount = 1000000 transferAmount = 1000000
dailyLimit = 3000000 periodTransferLimit = 3000000
dbDir = "db" dbDir = "db"

View File

@ -1,5 +1,5 @@
{ {
"name": "laconic-testnet-faucet", "name": "laconic-faucet",
"version": "0.1.0", "version": "0.1.0",
"main": "dist/index.js", "main": "dist/index.js",
"license": "UNLICENSED", "license": "UNLICENSED",
@ -20,6 +20,7 @@
"typescript": "^5.5.3" "typescript": "^5.5.3"
}, },
"dependencies": { "dependencies": {
"@cosmjs/encoding": "^0.32.4",
"@cosmjs/proto-signing": "^0.32.4", "@cosmjs/proto-signing": "^0.32.4",
"@cosmjs/stargate": "^0.32.4", "@cosmjs/stargate": "^0.32.4",
"@keyv/sqlite": "^3.6.7", "@keyv/sqlite": "^3.6.7",
@ -30,6 +31,6 @@
"scripts": { "scripts": {
"lint": "eslint .", "lint": "eslint .",
"build": "yarn tsc", "build": "yarn tsc",
"start-faucet": "node dist/index.js" "start": "node dist/index.js"
} }
} }

View File

@ -7,10 +7,12 @@ import cors from 'cors';
import { DirectSecp256k1Wallet } from '@cosmjs/proto-signing'; import { DirectSecp256k1Wallet } from '@cosmjs/proto-signing';
import { GasPrice, SigningStargateClient } from '@cosmjs/stargate'; import { GasPrice, SigningStargateClient } from '@cosmjs/stargate';
import { fromBech32 } from '@cosmjs/encoding';
import KeyvSqlite from '@keyv/sqlite'; import KeyvSqlite from '@keyv/sqlite';
const CONFIG_PATH = 'environments/local.toml'; const CONFIG_PATH = 'environments/local.toml';
const FAUCET_DATA_FILE = 'faucet_data.sqlite'; const FAUCET_DATA_FILE = 'faucet_data.sqlite';
const FAUCET_DATA_TTL = 86400000; // 24 hrs
interface Config { interface Config {
upstream: { upstream: {
@ -18,12 +20,13 @@ interface Config {
chainId: string chainId: string
denom: string denom: string
prefix: string prefix: string
gasPrice: string
faucetKey: string faucetKey: string
}, },
server: { server: {
port: number port: number
transferAmount: string transferAmount: string
dailyLimit: string periodTransferLimit: string
dbDir: string dbDir: string
} }
} }
@ -34,35 +37,39 @@ async function main (): Promise<void> {
const config: Config = toml.parse(configFile); const config: Config = toml.parse(configFile);
console.log('Config: ', JSON.stringify(config, null, 2)); console.log('Config: ', JSON.stringify(config, null, 2));
const keyv = await initKVStore(config.server.dbDir); const faucetDataStore = await initKVStore(config.server.dbDir);
const app = express(); const app = express();
app.use(express.json()); app.use(express.json());
app.use(cors()); app.use(cors());
app.post('/faucet', async (req, res) => { app.post('/faucet', async (req, res) => {
const { address } = req.body; const { address: accountAddress } = req.body;
if (!address) { if (!accountAddress) {
return res.status(400).json({ error: 'Address is required' }); return res.status(400).json({ error: 'address is required' });
}
if (!isValidAddress(accountAddress, config.upstream.prefix)) {
return res.status(400).json({ error: 'invalid address' });
} }
// Check rate limit // Check rate limit
const now = Date.now(); const now = Date.now();
const today = new Date(now).toISOString().split('T')[0]; const today = new Date(now).toISOString().split('T')[0];
const key = `${address}:${today}`; const faucetStoreKey = `${accountAddress}:${today}`;
const currentAmount = await keyv.get(key) || '0'; const amountSentToAddress = await faucetDataStore.get(faucetStoreKey) || '0';
if (BigInt(currentAmount) + BigInt(config.server.transferAmount) > BigInt(config.server.dailyLimit)) { if (BigInt(amountSentToAddress) + BigInt(config.server.transferAmount) > BigInt(config.server.periodTransferLimit)) {
return res.status(429).json({ error: 'Limit exceeded' }); return res.status(429).json({ error: 'Limit exceeded' });
} }
try { try {
const txHash = await sendTokens(config, address, String(config.server.transferAmount)); const txHash = await sendTokens(config, accountAddress, String(config.server.transferAmount));
console.log(`Sent tokens to address: ${address}, txHash: ${txHash}`); console.log(`Sent tokens to address: ${accountAddress}, txHash: ${txHash}`);
// Update rate limit // Update rate limit
await keyv.set(key, (BigInt(currentAmount) + BigInt(config.server.transferAmount)).toString(), 86400000); // 24 hours TTL await faucetDataStore.set(faucetStoreKey, (BigInt(amountSentToAddress) + BigInt(config.server.transferAmount)).toString(), FAUCET_DATA_TTL);
res.json({ success: true, txHash }); res.json({ success: true, txHash });
} catch (error) { } catch (error) {
@ -112,7 +119,11 @@ async function sendTokens (config: Config, recipientAddress: string, amount: str
); );
const [faucetAccount] = await wallet.getAccounts(); const [faucetAccount] = await wallet.getAccounts();
const client = await SigningStargateClient.connectWithSigner(config.upstream.rpcEndpoint, wallet, { gasPrice: GasPrice.fromString(`0.01${config.upstream.denom}`) }); const client = await SigningStargateClient.connectWithSigner(
config.upstream.rpcEndpoint,
wallet,
{ gasPrice: GasPrice.fromString(`${config.upstream.gasPrice}${config.upstream.denom}`) }
);
const result = await client.sendTokens( const result = await client.sendTokens(
faucetAccount.address, faucetAccount.address,
@ -125,6 +136,19 @@ async function sendTokens (config: Config, recipientAddress: string, amount: str
return result.transactionHash; return result.transactionHash;
} }
export function isValidAddress (address: string, requiredPrefix: string): boolean {
try {
const { prefix, data } = fromBech32(address);
if (prefix !== requiredPrefix) {
return false;
}
return data.length === 20;
} catch {
return false;
}
}
main().catch(err => { main().catch(err => {
console.log(err); console.log(err);
}); });