From c2a10fc25a855db64e27036f275fc356d87c860e Mon Sep 17 00:00:00 2001 From: Mayukha Vadari Date: Fri, 15 Sep 2023 10:48:08 -0400 Subject: [PATCH] respond to comments --- .../src/types/xchain-bridge.ts | 10 +- packages/xrpl/.eslintrc.js | 12 ++ packages/xrpl/snippets/src/bridgeTransfer.ts | 19 ++- .../src/models/ledger/XChainOwnedClaimID.ts | 20 ++- .../ledger/XChainOwnedCreateAccountClaimID.ts | 18 ++- .../transactions/XChainAccountCreateCommit.ts | 4 +- .../XChainAddAccountCreateAttestation.ts | 4 +- .../transactions/XChainAddClaimAttestation.ts | 4 +- .../src/models/transactions/XChainClaim.ts | 4 +- .../src/models/transactions/XChainCommit.ts | 4 +- .../models/transactions/XChainCreateBridge.ts | 4 +- .../transactions/XChainCreateClaimID.ts | 4 +- .../models/transactions/XChainModifyBridge.ts | 4 +- packages/xrpl/tools/createValidate.js | 134 ++++++++++++++++++ packages/xrpl/tsconfig.eslint.json | 3 +- tools/createValidate.js | 132 ----------------- 16 files changed, 216 insertions(+), 164 deletions(-) create mode 100644 packages/xrpl/tools/createValidate.js delete mode 100644 tools/createValidate.js diff --git a/packages/ripple-binary-codec/src/types/xchain-bridge.ts b/packages/ripple-binary-codec/src/types/xchain-bridge.ts index 82fd512568..ec80027c43 100644 --- a/packages/ripple-binary-codec/src/types/xchain-bridge.ts +++ b/packages/ripple-binary-codec/src/types/xchain-bridge.ts @@ -57,8 +57,8 @@ class XChainBridge extends SerializedType { /** * Construct a cross-chain bridge from a JSON * - * @param value XChainBridge or JSON to parse into a XChainBridge - * @returns A XChainBridge object + * @param value XChainBridge or JSON to parse into an XChainBridge + * @returns An XChainBridge object */ static from( value: T, @@ -80,14 +80,14 @@ class XChainBridge extends SerializedType { return new XChainBridge(Buffer.concat(bytes)) } - throw new Error('Invalid type to construct a XChainBridge') + throw new Error('Invalid type to construct an XChainBridge') } /** - * Read a XChainBridge from a BinaryParser + * Read an XChainBridge from a BinaryParser * * @param parser BinaryParser to read the XChainBridge from - * @returns A XChainBridge object + * @returns An XChainBridge object */ static fromParser(parser: BinaryParser): XChainBridge { const bytes: Array = [] diff --git a/packages/xrpl/.eslintrc.js b/packages/xrpl/.eslintrc.js index 3d4b2d5e93..8bcde424e8 100644 --- a/packages/xrpl/.eslintrc.js +++ b/packages/xrpl/.eslintrc.js @@ -147,5 +147,17 @@ module.exports = { 'import/no-unused-modules': 'off', }, }, + { + files: ['tools/*.ts', 'tools/*.js'], + rules: { + 'no-console': ['off'], + 'node/no-process-exit': ['off'], + '@typescript-eslint/no-magic-numbers': ['off'], + 'max-lines-per-function': ['off'], + 'max-statements': ['off'], + complexity: ['off'], + 'max-depth': ['warn', 3], + }, + }, ], } diff --git a/packages/xrpl/snippets/src/bridgeTransfer.ts b/packages/xrpl/snippets/src/bridgeTransfer.ts index e42e1b9df9..9d23afc9a0 100644 --- a/packages/xrpl/snippets/src/bridgeTransfer.ts +++ b/packages/xrpl/snippets/src/bridgeTransfer.ts @@ -46,7 +46,9 @@ async function bridgeTransfer(): Promise { const bridge: XChainBridge = bridgeData.XChainBridge console.log(bridge) + console.log('Creating wallet on the locking chain via the faucet...') const { wallet: wallet1 } = await lockingClient.fundWallet() + console.log(wallet1) const wallet2 = Wallet.generate() console.log( @@ -68,7 +70,9 @@ async function bridgeTransfer(): Promise { }) console.log(fundResponse) - // wait for the attestation to go through + console.log( + 'Waiting for the attestation to go through... (usually 8-12 seconds)', + ) let ledgersWaited = 0 let initialBalance = '0' while (ledgersWaited < MAX_LEDGERS_WAITED) { @@ -83,6 +87,7 @@ async function bridgeTransfer(): Promise { ledgersWaited += 1 // eslint-disable-next-line max-depth -- needed here if (ledgersWaited === MAX_LEDGERS_WAITED) { + // This error should never be hit if the bridge is running throw Error('Destination account creation via the bridge failed.') } } @@ -106,7 +111,7 @@ async function bridgeTransfer(): Promise { wallet: wallet2, }) - // extract new claim ID from metadata + // Extract new claim ID from metadata const nodes = (claimIdResult.result.meta as TransactionMetadata).AffectedNodes const createdNodes = nodes.filter((node) => Object.keys(node).includes('CreatedNode'), @@ -123,9 +128,9 @@ async function bridgeTransfer(): Promise { console.log(`Claim ID for the transfer: ${xchainClaimId}`) - // XChainCommit - console.log('Step 2: Locking the funds on the locking chain...') - + console.log( + 'Step 2: Locking the funds on the locking chain with an XChainCommit transaction...', + ) const commitTx: XChainCommit = { TransactionType: 'XChainCommit', Account: wallet1.classicAddress, @@ -139,7 +144,9 @@ async function bridgeTransfer(): Promise { }) console.log(commitResult) - // wait for the attestations to go through + console.log( + 'Waiting for the attestation to go through... (usually 8-12 seconds)', + ) ledgersWaited = 0 while (ledgersWaited < MAX_LEDGERS_WAITED) { await sleep(LEDGER_CLOSE_TIME) diff --git a/packages/xrpl/src/models/ledger/XChainOwnedClaimID.ts b/packages/xrpl/src/models/ledger/XChainOwnedClaimID.ts index 2fd713f250..bc33d48a31 100644 --- a/packages/xrpl/src/models/ledger/XChainOwnedClaimID.ts +++ b/packages/xrpl/src/models/ledger/XChainOwnedClaimID.ts @@ -1,3 +1,5 @@ +import { Amount } from 'ripple-binary-codec/dist/types' + import { XChainBridge } from '../common' import BaseLedgerEntry from './BaseLedgerEntry' @@ -35,14 +37,28 @@ export default interface XChainOwnedClaimID extends BaseLedgerEntry { */ OtherChainSource: string - // TODO: type this better /** * Attestations collected from the witness servers. This includes the parameters * needed to recreate the message that was signed, including the amount, which * chain (locking or issuing), optional destination, and reward account for that * signature. */ - XChainClaimAttestations: object[] + XChainClaimAttestations: Array<{ + // TODO: add docs + XChainClaimProofSig: { + Amount: Amount + + AttestationRewardAccount: string + + AttestationSignerAccount: string + + Destination?: string + + PublicKey: string + + WasLockingChainSend: 0 | 1 + } + }> /** * The total amount to pay the witness servers for their signatures. It must be at diff --git a/packages/xrpl/src/models/ledger/XChainOwnedCreateAccountClaimID.ts b/packages/xrpl/src/models/ledger/XChainOwnedCreateAccountClaimID.ts index f61d6e9f61..85f4c43728 100644 --- a/packages/xrpl/src/models/ledger/XChainOwnedCreateAccountClaimID.ts +++ b/packages/xrpl/src/models/ledger/XChainOwnedCreateAccountClaimID.ts @@ -27,7 +27,6 @@ export default interface XChainOwnedCreateAccountClaimID */ XChainAccountCreateCount: number - // TODO: type this better /** * Attestations collected from the witness servers. This includes the parameters * needed to recreate the message that was signed, including the amount, destination, @@ -35,7 +34,22 @@ export default interface XChainOwnedCreateAccountClaimID * exception of the reward account, all signatures must sign the message created with * common parameters. */ - XChainCreateAccountAttestations: object[] + XChainCreateAccountAttestations: Array<{ + // TODO: add docs + XChainCreateAccountProofSig: { + Amount: string + + AttestationRewardAccount: string + + AttestationSignerAccount: string + + Destination: string + + PublicKey: string + + WasLockingChainSend: 0 | 1 + } + }> /** * A bit-map of boolean flags. No flags are defined for, diff --git a/packages/xrpl/src/models/transactions/XChainAccountCreateCommit.ts b/packages/xrpl/src/models/transactions/XChainAccountCreateCommit.ts index ce8165078a..6e7f92a0d9 100644 --- a/packages/xrpl/src/models/transactions/XChainAccountCreateCommit.ts +++ b/packages/xrpl/src/models/transactions/XChainAccountCreateCommit.ts @@ -47,9 +47,9 @@ export interface XChainAccountCreateCommit extends BaseTransaction { } /** - * Verify the form and type of a XChainAccountCreateCommit at runtime. + * Verify the form and type of an XChainAccountCreateCommit at runtime. * - * @param tx - A XChainAccountCreateCommit Transaction. + * @param tx - An XChainAccountCreateCommit Transaction. * @throws When the XChainAccountCreateCommit is malformed. */ // eslint-disable-next-line max-lines-per-function -- okay for this function, there's a lot of things to check diff --git a/packages/xrpl/src/models/transactions/XChainAddAccountCreateAttestation.ts b/packages/xrpl/src/models/transactions/XChainAddAccountCreateAttestation.ts index 8a8e250ddc..b14c0bf2e3 100644 --- a/packages/xrpl/src/models/transactions/XChainAddAccountCreateAttestation.ts +++ b/packages/xrpl/src/models/transactions/XChainAddAccountCreateAttestation.ts @@ -77,9 +77,9 @@ export interface XChainAddAccountCreateAttestation extends BaseTransaction { } /** - * Verify the form and type of a XChainAddAccountCreateAttestation at runtime. + * Verify the form and type of an XChainAddAccountCreateAttestation at runtime. * - * @param tx - A XChainAddAccountCreateAttestation Transaction. + * @param tx - An XChainAddAccountCreateAttestation Transaction. * @throws When the XChainAddAccountCreateAttestation is malformed. */ // eslint-disable-next-line max-lines-per-function, max-statements -- okay for this function, lots of things to check diff --git a/packages/xrpl/src/models/transactions/XChainAddClaimAttestation.ts b/packages/xrpl/src/models/transactions/XChainAddClaimAttestation.ts index 51e5983230..e56db60900 100644 --- a/packages/xrpl/src/models/transactions/XChainAddClaimAttestation.ts +++ b/packages/xrpl/src/models/transactions/XChainAddClaimAttestation.ts @@ -72,9 +72,9 @@ export interface XChainAddClaimAttestation extends BaseTransaction { } /** - * Verify the form and type of a XChainAddClaimAttestation at runtime. + * Verify the form and type of an XChainAddClaimAttestation at runtime. * - * @param tx - A XChainAddClaimAttestation Transaction. + * @param tx - An XChainAddClaimAttestation Transaction. * @throws When the XChainAddClaimAttestation is malformed. */ // eslint-disable-next-line max-lines-per-function, max-statements -- okay for this function, lots of things to check diff --git a/packages/xrpl/src/models/transactions/XChainClaim.ts b/packages/xrpl/src/models/transactions/XChainClaim.ts index 4c18ebe2dd..5e5e438a46 100644 --- a/packages/xrpl/src/models/transactions/XChainClaim.ts +++ b/packages/xrpl/src/models/transactions/XChainClaim.ts @@ -50,9 +50,9 @@ export interface XChainClaim extends BaseTransaction { } /** - * Verify the form and type of a XChainClaim at runtime. + * Verify the form and type of an XChainClaim at runtime. * - * @param tx - A XChainClaim Transaction. + * @param tx - An XChainClaim Transaction. * @throws When the XChainClaim is malformed. */ export function validateXChainClaim(tx: Record): void { diff --git a/packages/xrpl/src/models/transactions/XChainCommit.ts b/packages/xrpl/src/models/transactions/XChainCommit.ts index 949ef65111..3fc4ead3c4 100644 --- a/packages/xrpl/src/models/transactions/XChainCommit.ts +++ b/packages/xrpl/src/models/transactions/XChainCommit.ts @@ -49,9 +49,9 @@ export interface XChainCommit extends BaseTransaction { } /** - * Verify the form and type of a XChainCommit at runtime. + * Verify the form and type of an XChainCommit at runtime. * - * @param tx - A XChainCommit Transaction. + * @param tx - An XChainCommit Transaction. * @throws When the XChainCommit is malformed. */ export function validateXChainCommit(tx: Record): void { diff --git a/packages/xrpl/src/models/transactions/XChainCreateBridge.ts b/packages/xrpl/src/models/transactions/XChainCreateBridge.ts index 5c270a4262..8404d7b533 100644 --- a/packages/xrpl/src/models/transactions/XChainCreateBridge.ts +++ b/packages/xrpl/src/models/transactions/XChainCreateBridge.ts @@ -39,9 +39,9 @@ export interface XChainCreateBridge extends BaseTransaction { } /** - * Verify the form and type of a XChainCreateBridge at runtime. + * Verify the form and type of an XChainCreateBridge at runtime. * - * @param tx - A XChainCreateBridge Transaction. + * @param tx - An XChainCreateBridge Transaction. * @throws When the XChainCreateBridge is malformed. */ export function validateXChainCreateBridge(tx: Record): void { diff --git a/packages/xrpl/src/models/transactions/XChainCreateClaimID.ts b/packages/xrpl/src/models/transactions/XChainCreateClaimID.ts index 31992bde36..c2eceb2dee 100644 --- a/packages/xrpl/src/models/transactions/XChainCreateClaimID.ts +++ b/packages/xrpl/src/models/transactions/XChainCreateClaimID.ts @@ -36,9 +36,9 @@ export interface XChainCreateClaimID extends BaseTransaction { } /** - * Verify the form and type of a XChainCreateClaimID at runtime. + * Verify the form and type of an XChainCreateClaimID at runtime. * - * @param tx - A XChainCreateClaimID Transaction. + * @param tx - An XChainCreateClaimID Transaction. * @throws When the XChainCreateClaimID is malformed. */ export function validateXChainCreateClaimID(tx: Record): void { diff --git a/packages/xrpl/src/models/transactions/XChainModifyBridge.ts b/packages/xrpl/src/models/transactions/XChainModifyBridge.ts index 8fa1969e30..bb61d3a0dd 100644 --- a/packages/xrpl/src/models/transactions/XChainModifyBridge.ts +++ b/packages/xrpl/src/models/transactions/XChainModifyBridge.ts @@ -60,9 +60,9 @@ export interface XChainModifyBridge extends BaseTransaction { } /** - * Verify the form and type of a XChainModifyBridge at runtime. + * Verify the form and type of an XChainModifyBridge at runtime. * - * @param tx - A XChainModifyBridge Transaction. + * @param tx - An XChainModifyBridge Transaction. * @throws When the XChainModifyBridge is malformed. */ export function validateXChainModifyBridge(tx: Record): void { diff --git a/packages/xrpl/tools/createValidate.js b/packages/xrpl/tools/createValidate.js new file mode 100644 index 0000000000..62d2bbbcfe --- /dev/null +++ b/packages/xrpl/tools/createValidate.js @@ -0,0 +1,134 @@ +/* eslint-disable no-continue -- unneeded here */ +/** + * This file writes the `validate` function for a transaction, when provided the model name in the `src/models/transactions` + * folder. + */ +const fs = require('fs') + +const NORMAL_TYPES = ['number', 'string'] +const NUMBERS = ['0', '1'] + +// TODO: rewrite this to use regex + +async function main() { + if (process.argv.length < 3) { + console.log(`Usage: ${process.argv[0]} ${process.argv[1]} TxName`) + process.exit(1) + } + const modelName = process.argv[2] + const filename = `./src/models/transactions/${modelName}.ts` + const [model, txName] = await getModel(filename) + return processModel(model, txName) +} + +async function getModel(filename) { + let model = '' + let started = false + let ended = false + const data = await fs.promises.readFile(filename, { encoding: 'utf8' }) + const lines = data.split('\n') + for (const line of lines) { + if (ended) { + continue + } + if (!started && !line.startsWith('export')) { + continue + } + if (!started && line.includes('Flags')) { + continue + } + if (!started) { + started = true + } + model += `${line}\n` + if (line === '}') { + ended = true + } + } + const name_line = model.split('\n')[0].split(' ') + const txName = name_line[2] + return [model, txName] +} + +function getIfLineParamPart(param, paramType) { + if (NORMAL_TYPES.includes(paramType)) { + return `typeof tx.${param} !== "${paramType}"` + } + if (NUMBERS.includes(paramType)) { + return `tx.${param} !== ${paramType}` + } + return `!is${paramType}(tx.${param})` +} + +function processModel(model, txName) { + let output = '' + for (let line of model.split('\n')) { + if (line === '') { + continue + } + if (line.startsWith('export')) { + continue + } + if (line === '}') { + continue + } + line = line.trim() + if (line.startsWith('TransactionType')) { + continue + } + if (line.startsWith('Flags')) { + continue + } + if (line.startsWith('/**')) { + continue + } + if (line.startsWith('*')) { + continue + } + const split = line.split(' ') + const param = split[0].replace('?:', '').replace(':', '').trim() + const paramTypes = split.slice(1) + const optional = split[0].endsWith('?:') + if (optional) { + output += ` if (tx.${param} !== undefined && ` + } else { + output += ` if (tx.${param} == null) {\n` + output += ` throw new ValidationError('${txName}: missing field ${param}')\n` + output += ` }\n\n` + output += ` if (` + } + if (paramTypes.length === 1) { + const paramType = paramTypes[0] + output += getIfLineParamPart(param, paramType) + } else { + let idx = 0 + const if_outputs = [] + while (idx < paramTypes.length) { + const paramType = paramTypes[idx] + if_outputs.push(getIfLineParamPart(param, paramType)) + idx += 2 + } + output += `(${if_outputs.join(' && ')})` + } + output += ') {\n' + output += ` throw new ValidationError('${txName}: invalid field ${param}')\n` + output += ` }\n\n` + } + output = output.substring(0, output.length - 1) + output += '}\n' + + output = `/** + * Verify the form and type of a ${txName} at runtime. + * + * @param tx - A ${txName} Transaction. + * @throws When the ${txName} is malformed. + */ +export function validate${txName}(tx: Record): void { + validateBaseTransaction(tx) + +${output}` + + return output +} + +main().then(console.log) diff --git a/packages/xrpl/tsconfig.eslint.json b/packages/xrpl/tsconfig.eslint.json index 604663f0ab..70b9b96580 100644 --- a/packages/xrpl/tsconfig.eslint.json +++ b/packages/xrpl/tsconfig.eslint.json @@ -6,6 +6,7 @@ "./test/**/*.json", "./src/**/*.json", "./snippets/src/**/*.ts", - ".eslintrc.js" + ".eslintrc.js", ], + "exclude": ["./tools/*.js"] } diff --git a/tools/createValidate.js b/tools/createValidate.js deleted file mode 100644 index 5cb29f8efa..0000000000 --- a/tools/createValidate.js +++ /dev/null @@ -1,132 +0,0 @@ -const fs = require("fs"); - -const NORMAL_TYPES = ["number", "string"]; -const NUMBERS = ["0", "1"]; - -// TODO: rewrite this to use regex - -function main() { - if (process.argv.length < 3) { - console.log( - "Usage: " + process.argv[0] + " " + process.argv[1] + " TxName" - ); - process.exit(1); - } - const modelName = process.argv[2]; - const filename = `./packages/xrpl/src/models/transactions/${modelName}.ts`; - const [model, txName] = getModel(filename); - return processModel(model, txName); -} - -function getModel(filename) { - let model = ""; - let started = false; - let ended = false; - const data = fs.readFileSync(filename, "utf8"); - const lines = data.split("\n"); - for (let line of lines) { - if (ended) { - continue; - } - if (!started && !line.startsWith("export")) { - continue; - } - if (!started && line.includes("Flags")) { - continue; - } - if (!started) { - started = true; - } - model += line + "\n"; - if (line === "}") { - ended = true; - } - } - const name_line = model.split("\n")[0].split(" "); - const txName = name_line[2]; - return [model, txName]; -} - -function getIfLineParamPart(param, paramType) { - if (NORMAL_TYPES.includes(paramType)) { - return `typeof tx.${param} !== "${paramType}"`; - } else if (NUMBERS.includes(paramType)) { - return `tx.${param} !== ${paramType}`; - } else { - return `!is${paramType}(tx.${param})`; - } -} - -function processModel(model, txName) { - let output = ""; - for (let line of model.split("\n")) { - if (line == "") { - continue; - } - if (line.startsWith("export")) { - continue; - } - if (line == "}") { - continue; - } - line = line.trim(); - if (line.startsWith("TransactionType")) { - continue; - } - if (line.startsWith("Flags")) { - continue; - } - if (line.startsWith("/**")) { - continue; - } - if (line.startsWith("*")) { - continue; - } - const split = line.split(" "); - let param = split[0].replace("?:", "").replace(":", "").trim(); - let paramTypes = split.slice(1); - let optional = split[0].endsWith("?:"); - if (optional) { - output += ` if (tx.${param} !== undefined && `; - } else { - output += ` if (tx.${param} == null) {\n`; - output += ` throw new ValidationError('${txName}: missing field ${param}')\n`; - output += ` }\n\n`; - output += ` if (`; - } - if (paramTypes.length == 1) { - let paramType = paramTypes[0]; - output += getIfLineParamPart(param, paramType); - } else { - let i = 0; - let if_outputs = []; - while (i < paramTypes.length) { - let paramType = paramTypes[i]; - if_outputs.push(getIfLineParamPart(param, paramType)); - i += 2; - } - output += "(" + if_outputs.join(" && ") + ")"; - } - output += ") {\n"; - output += ` throw new ValidationError('${txName}: invalid field ${param}')\n`; - output += ` }\n\n`; - } - output = output.substring(0, output.length - 1); - output += "}\n"; - - output = - `/** - * Verify the form and type of a ${txName} at runtime. - * - * @param tx - A ${txName} Transaction. - * @throws When the ${txName} is malformed. - */ -export function validate${txName}(tx: Record): void { - validateBaseTransaction(tx) - -` + output; - - return output; -} - -console.log(main());