From 2a9f06650014b1568ce618d00b45b80736982b92 Mon Sep 17 00:00:00 2001 From: Enzo Cioppettini Date: Mon, 6 Nov 2023 23:15:09 -0300 Subject: [PATCH] add delegation check in batcher's address validator --- .../batcher/address-validator/package.json | 3 +- .../batcher/address-validator/src/index.ts | 34 +++++++++++++++++++ packages/batcher/utils/src/config.ts | 8 +++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/packages/batcher/address-validator/package.json b/packages/batcher/address-validator/package.json index 032b5e7da..e7b754330 100644 --- a/packages/batcher/address-validator/package.json +++ b/packages/batcher/address-validator/package.json @@ -12,7 +12,8 @@ "dependencies": { "pg": "^8.7.3", "web3": "1.10.0", - "assert-never": "^1.2.1" + "assert-never": "^1.2.1", + "@dcspark/carp-client": "../../../tmp-carp-client" }, "devDependencies": { "@types/pg": "^8.6.5" diff --git a/packages/batcher/address-validator/src/index.ts b/packages/batcher/address-validator/src/index.ts index ffafa3c6a..e329650e0 100644 --- a/packages/batcher/address-validator/src/index.ts +++ b/packages/batcher/address-validator/src/index.ts @@ -17,6 +17,8 @@ import { CryptoManager } from '@paima/crypto'; import { createMessageForBatcher } from '@paima/concise'; import { initWeb3, AddressType, getReadNamespaces } from '@paima/utils'; import assertNever from 'assert-never'; +import { query, getErrorResponse } from '@dcspark/carp-client/client/src/index'; +import { Routes } from '@dcspark/carp-client/shared/routes'; class PaimaAddressValidator { private web3: Web3 | undefined; @@ -59,6 +61,13 @@ class PaimaAddressValidator { return GenericRejectionCode.ADDRESS_NOT_ALLOWED; } + // If a list of allowed cardano pools is provided, check that this user is delegating to that address + const isDelegatingToAllowedPools = await this.isDelegatingToAllowedPools(input.userAddress); + if (!isDelegatingToAllowedPools) { + console.log('[address-validator] Address not allowed!'); + return GenericRejectionCode.ADDRESS_NOT_ALLOWED; + } + // All tests passed: return 0; }; @@ -208,6 +217,31 @@ class PaimaAddressValidator { ): boolean { return inputsMinute < ENV.MAX_USER_INPUTS_PER_MINUTE && inputsDay < ENV.MAX_USER_INPUTS_PER_DAY; } + + private isDelegatingToAllowedPools = async (userAddress: string): Promise => { + const pools = ENV.BATCHER_CARDANO_ENABLED_POOLS; + + if (!pools) { + return true; + } + + if (!ENV.CARP_URL) { + throw new Error(`[address-validator] missing CARP_URL setting`); + } + + const latest = await query(ENV.CARP_URL, Routes.blockLatest, { + offset: 0, + }); + + const delegatingTo = await query(ENV.CARP_URL, Routes.delegationForAddress, { + address: userAddress, + until: { + absoluteSlot: latest.block.slot, + }, + }); + + return !!pools.find(pool => delegatingTo.pool === pool); + }; } export default PaimaAddressValidator; diff --git a/packages/batcher/utils/src/config.ts b/packages/batcher/utils/src/config.ts index 6d6bb52a4..761989fbb 100644 --- a/packages/batcher/utils/src/config.ts +++ b/packages/batcher/utils/src/config.ts @@ -84,6 +84,14 @@ export class ENV { return parseInt(process.env.MAX_USER_INPUTS_PER_DAY || '0', 10); } + static get CARP_URL(): string | undefined { + return process.env.BATCHER_CARP_URL; + } + + static get BATCHER_CARDANO_ENABLED_POOLS(): string[] | undefined { + return process.env.BATCHER_CARDANO_ENABLED_POOLS?.split(','); + } + // NOTE: this variable is not currently used, with DEFAULT_VALIDATION_ACTIVE determining the type. static get GAME_INPUT_VALIDATION_TYPE_NAME(): string { return process.env.GAME_INPUT_VALIDATION_TYPE_NAME || '';