From 8c80fa4d55f856e7a4ad2b01f05dd357a6f5f049 Mon Sep 17 00:00:00 2001 From: Nayyir Jutha Date: Mon, 16 Sep 2024 17:18:58 -0400 Subject: [PATCH 1/6] [NayNay] File Restructure: Faucet - restructured faucet to match the new structure --- src/common/entropy-base.ts | 2 + src/faucet/command.ts | 0 .../helpers}/signer.ts | 2 +- .../index.ts => faucet/interaction.ts} | 14 +-- src/faucet/main.ts | 100 ++++++++++++++++++ src/faucet/types.ts | 0 .../constants.ts => faucet/utils.ts} | 0 src/flows/entropyFaucet/faucet.ts | 96 ----------------- tests/faucet.test.ts | 2 +- 9 files changed, 111 insertions(+), 105 deletions(-) create mode 100644 src/faucet/command.ts rename src/{flows/entropyFaucet => faucet/helpers}/signer.ts (100%) rename src/{flows/entropyFaucet/index.ts => faucet/interaction.ts} (82%) create mode 100644 src/faucet/main.ts create mode 100644 src/faucet/types.ts rename src/{flows/entropyFaucet/constants.ts => faucet/utils.ts} (100%) delete mode 100644 src/flows/entropyFaucet/faucet.ts diff --git a/src/common/entropy-base.ts b/src/common/entropy-base.ts index 1e14bf3b..f981f975 100644 --- a/src/common/entropy-base.ts +++ b/src/common/entropy-base.ts @@ -4,9 +4,11 @@ import { EntropyLogger } from "./logger"; export abstract class EntropyBase { protected logger: EntropyLogger protected entropy: Entropy + protected endpoint: string constructor (entropy: Entropy, endpoint: string, flowContext: string) { this.logger = new EntropyLogger(flowContext, endpoint) this.entropy = entropy + this.endpoint = endpoint } } \ No newline at end of file diff --git a/src/faucet/command.ts b/src/faucet/command.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/flows/entropyFaucet/signer.ts b/src/faucet/helpers/signer.ts similarity index 100% rename from src/flows/entropyFaucet/signer.ts rename to src/faucet/helpers/signer.ts index bb492291..d3a9140a 100644 --- a/src/flows/entropyFaucet/signer.ts +++ b/src/faucet/helpers/signer.ts @@ -2,8 +2,8 @@ import Entropy from "@entropyxyz/sdk"; import type { Signer, SignerResult } from "@polkadot/api/types"; import { Registry, SignerPayloadJSON } from "@polkadot/types/types"; import { u8aToHex } from "@polkadot/util"; -import { stripHexPrefix } from "../../common/utils"; import { blake2AsHex, decodeAddress, encodeAddress, signatureVerify } from "@polkadot/util-crypto"; +import { stripHexPrefix } from "../../common/utils"; let id = 0 export default class FaucetSigner implements Signer { diff --git a/src/flows/entropyFaucet/index.ts b/src/faucet/interaction.ts similarity index 82% rename from src/flows/entropyFaucet/index.ts rename to src/faucet/interaction.ts index e76b7f14..ed16e329 100644 --- a/src/flows/entropyFaucet/index.ts +++ b/src/faucet/interaction.ts @@ -1,9 +1,9 @@ import Entropy from "@entropyxyz/sdk" -import { getSelectedAccount, print } from "../../common/utils" -import { initializeEntropy } from "../../common/initializeEntropy" -import { EntropyLogger } from '../../common/logger' -import { getRandomFaucet, sendMoney } from "./faucet" -import { TESTNET_PROGRAM_HASH } from "./constants" +import { getSelectedAccount, print } from "../common/utils" +import { initializeEntropy } from "../common/initializeEntropy" +import { EntropyLogger } from '../common/logger' +import { TESTNET_PROGRAM_HASH } from "./utils" +import { EntropyFaucet } from "./main" let chosenVerifyingKeys = [] export async function entropyFaucet ({ accounts, selectedAccount: selectedAccountAddress }, options, logger: EntropyLogger) { @@ -20,12 +20,12 @@ export async function entropyFaucet ({ accounts, selectedAccount: selectedAccoun try { // @ts-ignore (see TODO on aliceAccount) entropy = await initializeEntropy({ keyMaterial: selectedAccount.data, endpoint }) - + const FaucetService = new EntropyFaucet(entropy, options.endpoint) if (!entropy.registrationManager.signer.pair) { throw new Error("Keys are undefined") } - ({ chosenVerifyingKey, faucetAddress, verifyingKeys } = await getRandomFaucet(entropy, chosenVerifyingKeys)) + ({ chosenVerifyingKey, faucetAddress, verifyingKeys } = await FaucetService.getRandomFaucet(chosenVerifyingKeys)) await sendMoney(entropy, options.endpoint, { amount, addressToSendTo: selectedAccountAddress, faucetAddress, chosenVerifyingKey, faucetProgramPointer: TESTNET_PROGRAM_HASH }) // reset chosen keys after successful transfer diff --git a/src/faucet/main.ts b/src/faucet/main.ts new file mode 100644 index 00000000..386b8484 --- /dev/null +++ b/src/faucet/main.ts @@ -0,0 +1,100 @@ +import Entropy from "@entropyxyz/sdk"; +import { EntropyBase } from "../common/entropy-base"; +import { blake2AsHex, encodeAddress } from "@polkadot/util-crypto"; +import { FAUCET_PROGRAM_MOD_KEY, TESTNET_PROGRAM_HASH } from "./utils"; +import { EntropyBalance } from "src/balance/main"; +import { viewPrograms } from "src/flows/programs/view"; +import FaucetSigner from "./helpers/signer"; + +const FLOW_CONTEXT = 'ENTROPY-FAUCET' + +export class EntropyFaucet extends EntropyBase { + constructor(entropy: Entropy, endpoint: string) { + super(entropy, endpoint, FLOW_CONTEXT) + } + + async faucetSignAndSend (call: any, amount: number, senderAddress: string, chosenVerifyingKey: any): Promise { + const api = this.entropy.substrate + const faucetSigner = new FaucetSigner(api.registry, this.entropy, amount, chosenVerifyingKey) + + const sig = await call.signAsync(senderAddress, { + signer: faucetSigner, + }); + return new Promise((resolve, reject) => { + sig.send(({ status, dispatchError }: any) => { + // status would still be set, but in the case of error we can shortcut + // to just check it (so an error would indicate InBlock or Finalized) + if (dispatchError) { + let msg: string + if (dispatchError.isModule) { + // for module errors, we have the section indexed, lookup + const decoded = api.registry.findMetaError(dispatchError.asModule); + // @ts-ignore + const { documentation, method, section } = decoded; + + msg = `${section}.${method}: ${documentation.join(' ')}` + } else { + // Other, CannotLookup, BadOrigin, no extra info + msg = dispatchError.toString() + } + return reject(Error(msg)) + } + if (status.isFinalized) resolve(status) + }) + }) + } + + async getRandomFaucet (previousVerifyingKeys: string[] = [], programModKey = FAUCET_PROGRAM_MOD_KEY) { + const modifiableKeys = await this.entropy.substrate.query.registry.modifiableKeys(programModKey) + const verifyingKeys = JSON.parse(JSON.stringify(modifiableKeys.toJSON())) + + // Choosing one of the 5 verifiying keys at random to be used as the faucet sender + if (verifyingKeys.length === previousVerifyingKeys.length) { + throw new Error('FaucetError: There are no more faucets to choose from') + } + let chosenVerifyingKey = verifyingKeys[Math.floor(Math.random() * verifyingKeys.length)] + if (previousVerifyingKeys.length && previousVerifyingKeys.includes(chosenVerifyingKey)) { + const filteredVerifyingKeys = verifyingKeys.filter((key: string) => !previousVerifyingKeys.includes(key)) + chosenVerifyingKey = filteredVerifyingKeys[Math.floor(Math.random() * filteredVerifyingKeys.length)] + } + const hashedKey = blake2AsHex(chosenVerifyingKey) + const faucetAddress = encodeAddress(hashedKey, 42).toString() + + return { chosenVerifyingKey, faucetAddress, verifyingKeys } + } + + async sendMoney ( + { + amount, + addressToSendTo, + faucetAddress, + chosenVerifyingKey, + faucetProgramPointer = TESTNET_PROGRAM_HASH + }: { + amount: string, + addressToSendTo: string, + faucetAddress: string, + chosenVerifyingKey: string, + faucetProgramPointer: string + } + ): Promise { + const BalanceService = new EntropyBalance(this.entropy, this.endpoint) + // check balance of faucet address + const balance = await BalanceService.getBalance(faucetAddress) + if (balance <= 0) throw new Error('FundsError: Faucet Account does not have funds') + // check verifying key for only one program matching the program hash + const programs = await viewPrograms(this.entropy, { verifyingKey: chosenVerifyingKey }) + if (programs.length) { + if (programs.length > 1) throw new Error('ProgramsError: Faucet Account has too many programs attached, expected less') + if (programs.length === 1 && programs[0].program_pointer !== faucetProgramPointer) { + throw new Error('ProgramsError: Faucet Account does not possess Faucet program') + } + } else { + throw new Error('ProgramsError: Faucet Account has no programs attached') + } + + const transfer = this.entropy.substrate.tx.balances.transferAllowDeath(addressToSendTo, BigInt(amount)); + const transferStatus = await this.faucetSignAndSend(transfer, parseInt(amount), faucetAddress, chosenVerifyingKey) + if (transferStatus.isFinalized) return transferStatus + } +} \ No newline at end of file diff --git a/src/faucet/types.ts b/src/faucet/types.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/flows/entropyFaucet/constants.ts b/src/faucet/utils.ts similarity index 100% rename from src/flows/entropyFaucet/constants.ts rename to src/faucet/utils.ts diff --git a/src/flows/entropyFaucet/faucet.ts b/src/flows/entropyFaucet/faucet.ts deleted file mode 100644 index 0a9c3044..00000000 --- a/src/flows/entropyFaucet/faucet.ts +++ /dev/null @@ -1,96 +0,0 @@ -// check verifying key has the balance and proper program hash - -import Entropy from "@entropyxyz/sdk"; -import { blake2AsHex, encodeAddress } from "@polkadot/util-crypto"; -import { viewPrograms } from "../programs/view"; -import FaucetSigner from "./signer"; -import { FAUCET_PROGRAM_MOD_KEY, TESTNET_PROGRAM_HASH } from "./constants"; -import { EntropyBalance } from "src/balance/main"; - -// only the faucet program should be on the key -async function faucetSignAndSend (call: any, entropy: Entropy, amount: number, senderAddress: string, chosenVerifyingKey: any): Promise { - const api = entropy.substrate - const faucetSigner = new FaucetSigner(api.registry, entropy, amount, chosenVerifyingKey) - - const sig = await call.signAsync(senderAddress, { - signer: faucetSigner, - }); - return new Promise((resolve, reject) => { - sig.send(({ status, dispatchError }: any) => { - // status would still be set, but in the case of error we can shortcut - // to just check it (so an error would indicate InBlock or Finalized) - if (dispatchError) { - let msg: string - if (dispatchError.isModule) { - // for module errors, we have the section indexed, lookup - const decoded = api.registry.findMetaError(dispatchError.asModule); - // @ts-ignore - const { documentation, method, section } = decoded; - - msg = `${section}.${method}: ${documentation.join(' ')}` - } else { - // Other, CannotLookup, BadOrigin, no extra info - msg = dispatchError.toString() - } - return reject(Error(msg)) - } - if (status.isFinalized) resolve(status) - }) - }) -} - -export async function getRandomFaucet (entropy: Entropy, previousVerifyingKeys: string[] = [], programModKey = FAUCET_PROGRAM_MOD_KEY) { - const modifiableKeys = await entropy.substrate.query.registry.modifiableKeys(programModKey) - const verifyingKeys = JSON.parse(JSON.stringify(modifiableKeys.toJSON())) - - // Choosing one of the 5 verifiying keys at random to be used as the faucet sender - if (verifyingKeys.length === previousVerifyingKeys.length) { - throw new Error('FaucetError: There are no more faucets to choose from') - } - let chosenVerifyingKey = verifyingKeys[Math.floor(Math.random() * verifyingKeys.length)] - if (previousVerifyingKeys.length && previousVerifyingKeys.includes(chosenVerifyingKey)) { - const filteredVerifyingKeys = verifyingKeys.filter((key: string) => !previousVerifyingKeys.includes(key)) - chosenVerifyingKey = filteredVerifyingKeys[Math.floor(Math.random() * filteredVerifyingKeys.length)] - } - const hashedKey = blake2AsHex(chosenVerifyingKey) - const faucetAddress = encodeAddress(hashedKey, 42).toString() - - return { chosenVerifyingKey, faucetAddress, verifyingKeys } -} - -export async function sendMoney ( - entropy: Entropy, - endpoint: string, - { - amount, - addressToSendTo, - faucetAddress, - chosenVerifyingKey, - faucetProgramPointer = TESTNET_PROGRAM_HASH - }: { - amount: string, - addressToSendTo: string, - faucetAddress: string, - chosenVerifyingKey: string, - faucetProgramPointer: string - } -): Promise { - const BalanceService = new EntropyBalance(entropy, endpoint) - // check balance of faucet address - const balance = await BalanceService.getBalance(faucetAddress) - if (balance <= 0) throw new Error('FundsError: Faucet Account does not have funds') - // check verifying key for only one program matching the program hash - const programs = await viewPrograms(entropy, { verifyingKey: chosenVerifyingKey }) - if (programs.length) { - if (programs.length > 1) throw new Error('ProgramsError: Faucet Account has too many programs attached, expected less') - if (programs.length === 1 && programs[0].program_pointer !== faucetProgramPointer) { - throw new Error('ProgramsError: Faucet Account does not possess Faucet program') - } - } else { - throw new Error('ProgramsError: Faucet Account has no programs attached') - } - - const transfer = entropy.substrate.tx.balances.transferAllowDeath(addressToSendTo, BigInt(amount)); - const transferStatus = await faucetSignAndSend(transfer, entropy, parseInt(amount), faucetAddress, chosenVerifyingKey ) - if (transferStatus.isFinalized) return transferStatus -} \ No newline at end of file diff --git a/tests/faucet.test.ts b/tests/faucet.test.ts index 517d0b72..33a35ca1 100644 --- a/tests/faucet.test.ts +++ b/tests/faucet.test.ts @@ -55,7 +55,7 @@ test('Faucet Tests', async t => { const { chosenVerifyingKey, faucetAddress } = await getRandomFaucet(entropy, [], entropy.keyring.accounts.registration.address) // adding funds to faucet address - await run('Transfer funds to faucet address', TransferService.transfer(faucetAddress, "100000000000000")) + await run('Transfer funds to faucet address', TransferService.transfer(faucetAddress, "1000")) const transferStatus = await sendMoney( naynayEntropy, From a3e0da1518f4cf3c23f0570db98819dee69d8acf Mon Sep 17 00:00:00 2001 From: Nayyir Jutha Date: Tue, 17 Sep 2024 14:55:14 -0400 Subject: [PATCH 2/6] completed restructure, working on tests --- src/faucet/command.ts | 0 src/faucet/interaction.ts | 19 ++++++------------- src/faucet/main.ts | 11 +++-------- src/faucet/types.ts | 7 +++++++ src/flows/index.ts | 1 - src/tui.ts | 18 +++++++++++++----- 6 files changed, 29 insertions(+), 27 deletions(-) delete mode 100644 src/faucet/command.ts diff --git a/src/faucet/command.ts b/src/faucet/command.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/faucet/interaction.ts b/src/faucet/interaction.ts index ed16e329..c931301c 100644 --- a/src/faucet/interaction.ts +++ b/src/faucet/interaction.ts @@ -1,33 +1,26 @@ import Entropy from "@entropyxyz/sdk" -import { getSelectedAccount, print } from "../common/utils" -import { initializeEntropy } from "../common/initializeEntropy" import { EntropyLogger } from '../common/logger' import { TESTNET_PROGRAM_HASH } from "./utils" import { EntropyFaucet } from "./main" +import { print } from "src/common/utils" let chosenVerifyingKeys = [] -export async function entropyFaucet ({ accounts, selectedAccount: selectedAccountAddress }, options, logger: EntropyLogger) { +export async function entropyFaucet (entropy: Entropy, options, logger: EntropyLogger) { const FLOW_CONTEXT = 'ENTROPY_FAUCET' let faucetAddress let chosenVerifyingKey - let entropy: Entropy let verifyingKeys: string[] = [] const amount = "10000000000" const { endpoint } = options - const selectedAccount = getSelectedAccount(accounts, selectedAccountAddress) - logger.log(`selectedAccount::`, FLOW_CONTEXT) - logger.log(selectedAccount, FLOW_CONTEXT) + const selectedAccountAddress = entropy.keyring.accounts.registration.address try { - // @ts-ignore (see TODO on aliceAccount) - entropy = await initializeEntropy({ keyMaterial: selectedAccount.data, endpoint }) - const FaucetService = new EntropyFaucet(entropy, options.endpoint) + const FaucetService = new EntropyFaucet(entropy, endpoint) if (!entropy.registrationManager.signer.pair) { throw new Error("Keys are undefined") } ({ chosenVerifyingKey, faucetAddress, verifyingKeys } = await FaucetService.getRandomFaucet(chosenVerifyingKeys)) - - await sendMoney(entropy, options.endpoint, { amount, addressToSendTo: selectedAccountAddress, faucetAddress, chosenVerifyingKey, faucetProgramPointer: TESTNET_PROGRAM_HASH }) + await FaucetService.sendMoney({ amount, addressToSendTo: selectedAccountAddress, faucetAddress, chosenVerifyingKey, faucetProgramPointer: TESTNET_PROGRAM_HASH }) // reset chosen keys after successful transfer chosenVerifyingKeys = [] print(`Account: ${selectedAccountAddress} has been successfully funded with ${parseInt(amount).toLocaleString('en-US')} BITS`) @@ -39,7 +32,7 @@ export async function entropyFaucet ({ accounts, selectedAccount: selectedAccoun return } else { // Check for non faucet errors (FaucetError) and retry faucet - await entropyFaucet({ accounts, selectedAccount: selectedAccountAddress }, options, logger) + await entropyFaucet(entropy, options, logger) } } } \ No newline at end of file diff --git a/src/faucet/main.ts b/src/faucet/main.ts index 386b8484..5c8a4a7a 100644 --- a/src/faucet/main.ts +++ b/src/faucet/main.ts @@ -5,11 +5,12 @@ import { FAUCET_PROGRAM_MOD_KEY, TESTNET_PROGRAM_HASH } from "./utils"; import { EntropyBalance } from "src/balance/main"; import { viewPrograms } from "src/flows/programs/view"; import FaucetSigner from "./helpers/signer"; +import { SendMoneyParams } from "./types"; const FLOW_CONTEXT = 'ENTROPY-FAUCET' export class EntropyFaucet extends EntropyBase { - constructor(entropy: Entropy, endpoint: string) { + constructor (entropy: Entropy, endpoint: string) { super(entropy, endpoint, FLOW_CONTEXT) } @@ -70,13 +71,7 @@ export class EntropyFaucet extends EntropyBase { faucetAddress, chosenVerifyingKey, faucetProgramPointer = TESTNET_PROGRAM_HASH - }: { - amount: string, - addressToSendTo: string, - faucetAddress: string, - chosenVerifyingKey: string, - faucetProgramPointer: string - } + }: SendMoneyParams ): Promise { const BalanceService = new EntropyBalance(this.entropy, this.endpoint) // check balance of faucet address diff --git a/src/faucet/types.ts b/src/faucet/types.ts index e69de29b..9e874085 100644 --- a/src/faucet/types.ts +++ b/src/faucet/types.ts @@ -0,0 +1,7 @@ +export interface SendMoneyParams { + amount: string + addressToSendTo: string + faucetAddress: string + chosenVerifyingKey: string + faucetProgramPointer: string +} \ No newline at end of file diff --git a/src/flows/index.ts b/src/flows/index.ts index 389e5483..a74388bf 100644 --- a/src/flows/index.ts +++ b/src/flows/index.ts @@ -1,4 +1,3 @@ -export { entropyFaucet } from './entropyFaucet' export { entropyRegister } from './register' export { userPrograms, devPrograms } from './programs' export { manageAccounts } from './manage-accounts' diff --git a/src/tui.ts b/src/tui.ts index 9dd100a0..aa241594 100644 --- a/src/tui.ts +++ b/src/tui.ts @@ -10,6 +10,7 @@ import { loadEntropy } from './common/utils-cli' import { entropySign } from './sign/interaction' import { entropyBalance } from './balance/interaction' import { entropyTransfer } from './transfer/interaction' +import { entropyFaucet } from './faucet/interaction' let hasConfigInit = false async function setupConfig () { @@ -49,14 +50,13 @@ export default function tui (entropy: Entropy, options: EntropyTuiOptions) { // TODO: design programs in TUI (merge deploy+user programs) 'Deploy Program': flows.devPrograms, 'User Programs': flows.userPrograms, - 'Entropy Faucet': flows.entropyFaucet, } - // const devChoices = { - // // 'Entropy Faucet': flows.entropyFaucet, - // } + const devChoices = { + 'Entropy Faucet': () => {}, + } - // if (options.dev) Object.assign(choices, devChoices) + if (options.dev) Object.assign(choices, devChoices) // assign exit so its last Object.assign(choices, { 'Exit': async () => {} }) @@ -118,6 +118,14 @@ async function main (entropy: Entropy, choices, options, logger: EntropyLogger) } break } + case 'Entropy Faucet': { + try { + await entropyFaucet(entropy, options, logger) + } catch (error) { + console.error('There was an issue with running the faucet', error); + } + break + } default: { const newConfigUpdates = await choices[answers.choice](storedConfig, options, logger) if (typeof newConfigUpdates === 'string' && newConfigUpdates === 'exit') { From b43e250d272d549e0db395b9c90f607d27e227d7 Mon Sep 17 00:00:00 2001 From: Nayyir Jutha Date: Tue, 17 Sep 2024 16:06:21 -0400 Subject: [PATCH 3/6] updated faucet tests --- tests/faucet.test.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/faucet.test.ts b/tests/faucet.test.ts index 33a35ca1..23fc5213 100644 --- a/tests/faucet.test.ts +++ b/tests/faucet.test.ts @@ -5,9 +5,9 @@ import { stripHexPrefix } from '../src/common/utils' import { readFileSync } from 'fs' import { EntropyBalance } from '../src/balance/main' import { EntropyTransfer } from '../src/transfer/main' -import { getRandomFaucet, sendMoney } from '../src/flows/entropyFaucet/faucet' import { register } from '../src/flows/register/register' -import { LOCAL_PROGRAM_HASH } from '../src/flows/entropyFaucet/constants' +import { EntropyFaucet } from '../src/faucet/main' +import { LOCAL_PROGRAM_HASH } from '../src/faucet/utils' test('Faucet Tests', async t => { const { run, entropy, endpoint } = await setupTest(t, { seed: charlieStashSeed }) @@ -15,6 +15,7 @@ test('Faucet Tests', async t => { const BalanceService = new EntropyBalance(entropy, endpoint) const TransferService = new EntropyTransfer(entropy, endpoint) + const FaucetService = new EntropyFaucet(naynayEntropy, endpoint) const faucetProgram = readFileSync('tests/programs/faucet_program.wasm') @@ -52,14 +53,12 @@ test('Faucet Tests', async t => { } )) - const { chosenVerifyingKey, faucetAddress } = await getRandomFaucet(entropy, [], entropy.keyring.accounts.registration.address) + const { chosenVerifyingKey, faucetAddress } = await FaucetService.getRandomFaucet([], entropy.keyring.accounts.registration.address) // adding funds to faucet address await run('Transfer funds to faucet address', TransferService.transfer(faucetAddress, "1000")) - const transferStatus = await sendMoney( - naynayEntropy, - endpoint, + const transferStatus = await FaucetService.sendMoney( { amount: "10000000000", addressToSendTo: naynayEntropy.keyring.accounts.registration.address, From 009f67a16b675f9decdcbfdf45c042cec529b8b2 Mon Sep 17 00:00:00 2001 From: Nayyir Jutha Date: Thu, 19 Sep 2024 13:35:14 -0400 Subject: [PATCH 4/6] updated recursion for faucet retry mechanism, reduce calls to the chain --- src/faucet/interaction.ts | 30 +++++++++++++++++------------- src/faucet/main.ts | 20 +++++++++++--------- tests/faucet.test.ts | 20 ++++++++++---------- 3 files changed, 38 insertions(+), 32 deletions(-) diff --git a/src/faucet/interaction.ts b/src/faucet/interaction.ts index c931301c..54c201d4 100644 --- a/src/faucet/interaction.ts +++ b/src/faucet/interaction.ts @@ -5,22 +5,26 @@ import { EntropyFaucet } from "./main" import { print } from "src/common/utils" let chosenVerifyingKeys = [] +const amount = "10000000000" +// context for logging file +const FLOW_CONTEXT = 'ENTROPY_FAUCET_INTERACTION' export async function entropyFaucet (entropy: Entropy, options, logger: EntropyLogger) { - const FLOW_CONTEXT = 'ENTROPY_FAUCET' - let faucetAddress - let chosenVerifyingKey - let verifyingKeys: string[] = [] - const amount = "10000000000" const { endpoint } = options + if (!entropy.registrationManager.signer.pair) { + throw new Error("Keys are undefined") + } + const faucetService = new EntropyFaucet(entropy, endpoint) + const verifyingKeys = await faucetService.getAllFaucetVerifyingKeys() + // @ts-expect-error + return sendMoneyFromRandomFaucet(entropy, options.endpoint, verifyingKeys, logger) +} + +async function sendMoneyFromRandomFaucet (entropy: Entropy, endpoint: string, verifyingKeys: string[], logger: EntropyLogger) { + const faucetService = new EntropyFaucet(entropy, endpoint) const selectedAccountAddress = entropy.keyring.accounts.registration.address + const { chosenVerifyingKey, faucetAddress } = faucetService.getRandomFaucet(chosenVerifyingKeys, verifyingKeys) try { - const FaucetService = new EntropyFaucet(entropy, endpoint) - if (!entropy.registrationManager.signer.pair) { - throw new Error("Keys are undefined") - } - - ({ chosenVerifyingKey, faucetAddress, verifyingKeys } = await FaucetService.getRandomFaucet(chosenVerifyingKeys)) - await FaucetService.sendMoney({ amount, addressToSendTo: selectedAccountAddress, faucetAddress, chosenVerifyingKey, faucetProgramPointer: TESTNET_PROGRAM_HASH }) + await faucetService.sendMoney({ amount, addressToSendTo: selectedAccountAddress, faucetAddress, chosenVerifyingKey, faucetProgramPointer: TESTNET_PROGRAM_HASH }) // reset chosen keys after successful transfer chosenVerifyingKeys = [] print(`Account: ${selectedAccountAddress} has been successfully funded with ${parseInt(amount).toLocaleString('en-US')} BITS`) @@ -32,7 +36,7 @@ export async function entropyFaucet (entropy: Entropy, options, logger: EntropyL return } else { // Check for non faucet errors (FaucetError) and retry faucet - await entropyFaucet(entropy, options, logger) + await sendMoneyFromRandomFaucet(entropy, endpoint, verifyingKeys, logger) } } } \ No newline at end of file diff --git a/src/faucet/main.ts b/src/faucet/main.ts index 5c8a4a7a..1b9ef4aa 100644 --- a/src/faucet/main.ts +++ b/src/faucet/main.ts @@ -45,23 +45,25 @@ export class EntropyFaucet extends EntropyBase { }) } - async getRandomFaucet (previousVerifyingKeys: string[] = [], programModKey = FAUCET_PROGRAM_MOD_KEY) { + async getAllFaucetVerifyingKeys (programModKey = FAUCET_PROGRAM_MOD_KEY) { const modifiableKeys = await this.entropy.substrate.query.registry.modifiableKeys(programModKey) - const verifyingKeys = JSON.parse(JSON.stringify(modifiableKeys.toJSON())) - + return modifiableKeys.toJSON() + } + + getRandomFaucet (previousVerifyingKeys: string[] = [], allVerifyingKeys: string[] = []) { // Choosing one of the 5 verifiying keys at random to be used as the faucet sender - if (verifyingKeys.length === previousVerifyingKeys.length) { + if (allVerifyingKeys.length === previousVerifyingKeys.length) { throw new Error('FaucetError: There are no more faucets to choose from') } - let chosenVerifyingKey = verifyingKeys[Math.floor(Math.random() * verifyingKeys.length)] + let chosenVerifyingKey = allVerifyingKeys[Math.floor(Math.random() * allVerifyingKeys.length)] if (previousVerifyingKeys.length && previousVerifyingKeys.includes(chosenVerifyingKey)) { - const filteredVerifyingKeys = verifyingKeys.filter((key: string) => !previousVerifyingKeys.includes(key)) + const filteredVerifyingKeys = allVerifyingKeys.filter((key: string) => !previousVerifyingKeys.includes(key)) chosenVerifyingKey = filteredVerifyingKeys[Math.floor(Math.random() * filteredVerifyingKeys.length)] } const hashedKey = blake2AsHex(chosenVerifyingKey) const faucetAddress = encodeAddress(hashedKey, 42).toString() - return { chosenVerifyingKey, faucetAddress, verifyingKeys } + return { chosenVerifyingKey, faucetAddress } } async sendMoney ( @@ -73,9 +75,9 @@ export class EntropyFaucet extends EntropyBase { faucetProgramPointer = TESTNET_PROGRAM_HASH }: SendMoneyParams ): Promise { - const BalanceService = new EntropyBalance(this.entropy, this.endpoint) + const balanceService = new EntropyBalance(this.entropy, this.endpoint) // check balance of faucet address - const balance = await BalanceService.getBalance(faucetAddress) + const balance = await balanceService.getBalance(faucetAddress) if (balance <= 0) throw new Error('FundsError: Faucet Account does not have funds') // check verifying key for only one program matching the program hash const programs = await viewPrograms(this.entropy, { verifyingKey: chosenVerifyingKey }) diff --git a/tests/faucet.test.ts b/tests/faucet.test.ts index 23fc5213..296210f7 100644 --- a/tests/faucet.test.ts +++ b/tests/faucet.test.ts @@ -1,5 +1,4 @@ import test from 'tape' -import * as util from "@polkadot/util" import { charlieStashSeed, setupTest } from './testing-utils' import { stripHexPrefix } from '../src/common/utils' import { readFileSync } from 'fs' @@ -13,9 +12,9 @@ test('Faucet Tests', async t => { const { run, entropy, endpoint } = await setupTest(t, { seed: charlieStashSeed }) const { entropy: naynayEntropy } = await setupTest(t) - const BalanceService = new EntropyBalance(entropy, endpoint) - const TransferService = new EntropyTransfer(entropy, endpoint) - const FaucetService = new EntropyFaucet(naynayEntropy, endpoint) + const balanceService = new EntropyBalance(entropy, endpoint) + const transferService = new EntropyTransfer(entropy, endpoint) + const faucetService = new EntropyFaucet(naynayEntropy, endpoint) const faucetProgram = readFileSync('tests/programs/faucet_program.wasm') @@ -42,7 +41,7 @@ test('Faucet Tests', async t => { // Confirm faucetPointer matches deployed program pointer t.equal(faucetProgramPointer, LOCAL_PROGRAM_HASH, 'Program pointer matches') - let naynayBalance = await BalanceService.getBalance(naynayEntropy.keyring.accounts.registration.address) + let naynayBalance = await balanceService.getBalance(naynayEntropy.keyring.accounts.registration.address) t.equal(naynayBalance, 0, 'Naynay is broke af') // register with faucet program await run('Register Faucet Program for charlie stash', register( @@ -52,13 +51,14 @@ test('Faucet Tests', async t => { programData: [{ program_pointer: faucetProgramPointer, program_config: userConfig }] } )) - - const { chosenVerifyingKey, faucetAddress } = await FaucetService.getRandomFaucet([], entropy.keyring.accounts.registration.address) + const verifyingKeys = await faucetService.getAllFaucetVerifyingKeys(entropy.keyring.accounts.registration.address) + // @ts-expect-error + const { chosenVerifyingKey, faucetAddress } = faucetService.getRandomFaucet([], verifyingKeys) // adding funds to faucet address - await run('Transfer funds to faucet address', TransferService.transfer(faucetAddress, "1000")) + await run('Transfer funds to faucet address', transferService.transfer(faucetAddress, "1000")) - const transferStatus = await FaucetService.sendMoney( + const transferStatus = await faucetService.sendMoney( { amount: "10000000000", addressToSendTo: naynayEntropy.keyring.accounts.registration.address, @@ -70,7 +70,7 @@ test('Faucet Tests', async t => { t.ok(transferStatus.isFinalized, 'Transfer is good') - naynayBalance = await BalanceService.getBalance(naynayEntropy.keyring.accounts.registration.address) + naynayBalance = await balanceService.getBalance(naynayEntropy.keyring.accounts.registration.address) t.ok(naynayBalance > 0, 'Naynay is drippin in faucet tokens') From 60996a07fe1c0f8567ab3af1bbde13f5c4aea55b Mon Sep 17 00:00:00 2001 From: Nayyir Jutha Date: Tue, 24 Sep 2024 13:07:21 -0400 Subject: [PATCH 5/6] documented some of the methods used for the faucet --- src/faucet/interaction.ts | 2 ++ src/faucet/main.ts | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/faucet/interaction.ts b/src/faucet/interaction.ts index 54c201d4..54cc647b 100644 --- a/src/faucet/interaction.ts +++ b/src/faucet/interaction.ts @@ -19,6 +19,8 @@ export async function entropyFaucet (entropy: Entropy, options, logger: EntropyL return sendMoneyFromRandomFaucet(entropy, options.endpoint, verifyingKeys, logger) } +// Method that takes in the initial list of verifying keys (to avoid multiple calls to the rpc) and recursively retries each faucet until +// a successful transfer is made async function sendMoneyFromRandomFaucet (entropy: Entropy, endpoint: string, verifyingKeys: string[], logger: EntropyLogger) { const faucetService = new EntropyFaucet(entropy, endpoint) const selectedAccountAddress = entropy.keyring.accounts.registration.address diff --git a/src/faucet/main.ts b/src/faucet/main.ts index 00d672ad..2933ce35 100644 --- a/src/faucet/main.ts +++ b/src/faucet/main.ts @@ -14,6 +14,8 @@ export class EntropyFaucet extends EntropyBase { super({ entropy, endpoint, flowContext: FLOW_CONTEXT }) } + // Method used to sign and send the transfer request (transfer request = call argument) using the custom signer + // created to overwrite how we sign the payload that is sent up chain async faucetSignAndSend (call: any, amount: number, senderAddress: string, chosenVerifyingKey: any): Promise { const api = this.entropy.substrate const faucetSigner = new FaucetSigner(api.registry, this.entropy, amount, chosenVerifyingKey) @@ -50,8 +52,9 @@ export class EntropyFaucet extends EntropyBase { return modifiableKeys.toJSON() } + // To handle overloading the individual faucet, multiple faucet accounts have been generated, and here is + // where we choose one of those faucet's at random getRandomFaucet (previousVerifyingKeys: string[] = [], allVerifyingKeys: string[] = []) { - // Choosing one of the 5 verifiying keys at random to be used as the faucet sender if (allVerifyingKeys.length === previousVerifyingKeys.length) { throw new Error('FaucetError: There are no more faucets to choose from') } From cbbc5a03cf84b94f28aef0bd507a2ac1d8daab6b Mon Sep 17 00:00:00 2001 From: Nayyir Jutha Date: Tue, 24 Sep 2024 13:40:25 -0400 Subject: [PATCH 6/6] added changelog --- CHANGELOG.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f982d02b..f00817ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,16 +27,21 @@ Version header format: `[version] Name - year-month-day (entropy-core compatibil - new: 'src/flows/user-program-management/view.ts' - service file for pure functions of viewing user programs - new: 'src/flows/user-program-management/helpers/utils.ts' - utility helper file for user program management specific methods - new: './src/flows/user-program-management/remove.ts' - service file for removing user program pure function -- new: './src/common/base-commands.ts' - base abstract class for new command classes +- new: './src/common/entropy-base.ts' - base abstract class for new command classes - new: './src/balance' - new file structure for our CLI/TUI flows - - new: './src/balance/command.ts' - main entry file for balance command for tui/cli + - new: './src/balance/main.ts' - main entry file for balance command for tui/cli - new: './src/balance/utils.ts' - utilities and helper methods for all things balance - new: './src/transfer' - new file structure for our CLI/TUI flows - - new: './src/transfer/command.ts' - main entry file for transfer command for tui/cli + - new: './src/transfer/main.ts' - main entry file for transfer command for tui/cli - new: './src/transfer/utils.ts' - utilities and helper methods for all things transfer -- new: './src/accounts' - new file structure for our CLI/TUI flows - - new: './src/accounts/command.ts' - main entry file for accounts command for tui/cli - - new: './src/accounts/utils.ts' - utilities and helper methods for all things accounts +- new: './src/account' - new file structure for our CLI/TUI flows + - new: './src/account/main.ts' - main entry file for accounts command for tui/cli + - new: './src/account/utils.ts' - utilities and helper methods for all things accounts +- new: './src/faucet' - new file structure for our CLI/TUI flows + - new: './src/faucet/main.ts' - main entry file for faucet methods used for command and interaction files + - new: './src/faucet/utils.ts' - utilities and helper methods for all things faucet + - new: './src/faucet/interaction.ts' - main entrypoint for TUI flows + - new: './src/faucet/command.ts' - main entrypoint for CLI flows ### Changed @@ -48,6 +53,7 @@ Version header format: `[version] Name - year-month-day (entropy-core compatibil - removed flows/entropyTransfer/*.ts directory with file restructure - removed flows/manage-accounts/*/*.ts directory with file restructure - removed flows/register/*.ts directory with file restructure +- removed flow/entropyFaucet/*.ts directory with file restructure ### Broke