diff --git a/examples/curated-paranet-demo.js b/examples/curated-paranet-demo.js index 00c45e3..a3a5fbc 100644 --- a/examples/curated-paranet-demo.js +++ b/examples/curated-paranet-demo.js @@ -10,7 +10,7 @@ const ENVIRONMENT = 'development'; const OT_NODE_HOSTNAME = 'http://localhost'; const OT_NODE_PORT = '8900'; const PUBLIC_KEY = '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'; -const PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'; +const PRIVATE_KEY = ''; const DkgClient = new DKG({ environment: ENVIRONMENT, diff --git a/examples/demo.js b/examples/demo.js index 4b51973..46360ce 100644 --- a/examples/demo.js +++ b/examples/demo.js @@ -2,18 +2,18 @@ import jsonld from 'jsonld'; import DKG from '../index.js'; import { sleepForMilliseconds } from '../services/utilities.js'; -const ENVIRONMENT = 'development'; -const OT_NODE_HOSTNAME = 'http://localhost'; +const ENVIRONMENT = 'testnet'; +const OT_NODE_HOSTNAME = 'https://v6-pegasus-node-06.origin-trail.network'; const OT_NODE_PORT = '8900'; -const PUBLIC_KEY = '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'; -const PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'; +const PUBLIC_KEY = ''; +const PRIVATE_KEY = ''; const DkgClient = new DKG({ environment: ENVIRONMENT, endpoint: OT_NODE_HOSTNAME, port: OT_NODE_PORT, blockchain: { - name: 'hardhat1', + name: 'otp:20430', publicKey: PUBLIC_KEY, privateKey: PRIVATE_KEY, }, @@ -117,15 +117,15 @@ function divider() { // divider(); - // console.time('Publish (5 replications, 5 finalizations)'); - // const result3 = await DkgClient.asset.create(content, { - // epochsNum: 2, - // minimumNumberOfFinalizationConfirmations: 3, - // minimumNumberOfNodeReplications: 3, - // }); - // console.timeEnd('Publish (5 replications, 5 finalizations)'); + console.time('Publish (5 replications, 5 finalizations)'); + const result3 = await DkgClient.asset.create(content, { + epochsNum: 2, + minimumNumberOfFinalizationConfirmations: 3, + minimumNumberOfNodeReplications: 3, + });//payer in options + console.timeEnd('Publish (5 replications, 5 finalizations)'); - // console.log(JSON.stringify(result3, null, 2)); + console.log(JSON.stringify(result3, null, 2)); // divider(); diff --git a/examples/paymaster-demo.js b/examples/paymaster-demo.js new file mode 100644 index 0000000..cb589db --- /dev/null +++ b/examples/paymaster-demo.js @@ -0,0 +1,115 @@ +import jsonld from 'jsonld'; +import DKG from '../index.js'; +import { sleepForMilliseconds } from '../services/utilities.js'; + +const ENVIRONMENT = 'testnet'; +const OT_NODE_HOSTNAME = 'https://v6-pegasus-node-02.origin-trail.network'; +const OT_NODE_PORT = '8900'; +const PUBLIC_KEY = '0x1dD2C730a2BcD26d6aEf7DCCF171FC2AB1384d14'; +const PRIVATE_KEY = '8ae4f7c247ad422913c1c60187856091ad2bcb4e53fb2936d7633d7d02bd180a'; + +const DkgClient = new DKG({ + environment: ENVIRONMENT, + endpoint: OT_NODE_HOSTNAME, + port: OT_NODE_PORT, + blockchain: { + name: 'otp:20430', + publicKey: PUBLIC_KEY, + privateKey: PRIVATE_KEY, + }, + maxNumberOfRetries: 300, + frequency: 2, + contentType: 'all', + nodeApiVersion: '/v1', +}); + +function divider() { + console.log('=================================================='); + console.log('=================================================='); + console.log('=================================================='); +} + + +(async () => { + + const content = { + private: { + '@context': 'https://www.schema.org', + '@id': 'urn:eu-pp:safety-test:3oRIwPtUOJapwNSAGZTzCOWR9bEo', + '@type': 'ProductSafetyTest', + testType: 'Functional Safety Test', + testResults: 'Fail', + relatedProduct: [ + { + '@id': 'urn:epc:id:sgtin:59G1yu8uivSRKLLu', + name: '59G1yu8uivSRKLLu', + }, + ], + }, + }; + + // const nodeInfo = await DkgClient.node.info(); + // console.log('======================== NODE INFO RECEIVED'); + // console.log(nodeInfo); + + divider(); + + //Publish paymaster + + // const paymasterAddress = await DkgClient.paymaster.deployPaymasterContract({ + // epochsNum: 2, + // minimumNumberOfFinalizationConfirmations: 3, + // minimumNumberOfNodeReplications: 3, + // }); + + // console.log('Deployed Address:', paymasterAddress); + + await DkgClient.paymaster.addAllowedAddress( + '0x1d23852331eDA24d1b6F5E21fdc419A38B0de28c', //Paymaster address + '0x1dD2C730a2BcD26d6aEf7DCCF171FC2AB1384d14' // address to be added + ); + + console.log('Added allowed address.'); + + + await DkgClient.paymaster.removeAllowedAddress( + '0x1d23852331eDA24d1b6F5E21fdc419A38B0de28c', //Paymaster address + '0x1dD2C730a2BcD26d6aEf7DCCF171FC2AB1384d14' // address to be removed + ); + + console.log('Removed allowed address.'); + + await DkgClient.paymaster.fundPaymaster( + '0x1d23852331eDA24d1b6F5E21fdc419A38B0de28c', + BigInt(1000000) + ); + console.log('Funded Paymaster.'); + + await DkgClient.paymaster.withdraw( + '0x1d23852331eDA24d1b6F5E21fdc419A38B0de28c', //Paymaster address + '0x1dD2C730a2BcD26d6aEf7DCCF171FC2AB1384d14', // address of recipient + BigInt(500000) + ); + console.log('Withdrawal complete.'); + + + // console.time('Publish (5 replications, 5 finalizations)'); + // const result3 = await DkgClient.asset.create(content, { + // epochsNum: 2, + // minimumNumberOfFinalizationConfirmations: 3, + // minimumNumberOfNodeReplications: 3, + // });//payer in options + + // console.timeEnd('Publish (5 replications, 5 finalizations)'); + + // console.log(JSON.stringify(result3, null, 2)); + + // console.time('get'); + // const getOperationResult = await DkgClient.graph.get( + // 'did:dkg:base:84532/0xd5550173b0f7b8766ab2770e4ba86caf714a5af5/2', + // ); + // console.log('======================== ASSET GET'); + // console.log(getOperationResult); + // console.timeEnd('get'); + +})(); diff --git a/index.cjs b/index.cjs index 1be15e8..87bfe65 100644 --- a/index.cjs +++ b/index.cjs @@ -3124,6 +3124,8 @@ const KnowledgeCollectionAbi = require$1('dkg-evm-module/abi/KnowledgeCollection const KnowledgeCollectionStorageAbi = require$1('dkg-evm-module/abi/KnowledgeCollectionStorage.json'); const AskStorageAbi = require$1('dkg-evm-module/abi/AskStorage.json'); const ChronosAbi = require$1('dkg-evm-module/abi/Chronos.json'); +const PaymasterAbi = require$1('dkg-evm-module/abi/Paymaster.json'); +const PaymasterManagerAbi = require$1('dkg-evm-module/abi/PaymasterManager.json'); class BlockchainServiceBase { constructor(config = {}) { @@ -3148,6 +3150,8 @@ class BlockchainServiceBase { this.abis.KnowledgeCollectionStorage = KnowledgeCollectionStorageAbi; this.abis.AskStorage = AskStorageAbi; this.abis.Chronos = ChronosAbi; + this.abis.Paymaster = PaymasterAbi; + this.abis.PaymasterManager = PaymasterManagerAbi; this.abis.KnowledgeCollectionStorage.filter((obj) => obj.type === 'event').forEach( (event) => { @@ -3242,8 +3246,8 @@ class BlockchainServiceBase { blockchain.name.startsWith('otp') ? DEFAULT_GAS_PRICE.OTP : blockchain.name.startsWith('base') - ? DEFAULT_GAS_PRICE.BASE - : DEFAULT_GAS_PRICE.GNOSIS, + ? DEFAULT_GAS_PRICE.BASE + : DEFAULT_GAS_PRICE.GNOSIS, 'Gwei', ); } @@ -3502,9 +3506,10 @@ class BlockchainServiceBase { paranetKaContract, paranetTokenId, blockchain, + paymaster = null, stepHooks = emptyHooks, ) { - const sender = await this.getPublicKey(blockchain); + const sender = paymaster || await this.getPublicKey(blockchain); try { let allowanceIncreased, allowanceGap; @@ -4231,8 +4236,8 @@ class BlockchainServiceBase { blockchain.name.startsWith('otp') ? DEFAULT_GAS_PRICE.OTP : blockchain.name.startsWith('base') - ? DEFAULT_GAS_PRICE.BASE - : DEFAULT_GAS_PRICE.GNOSIS, + ? DEFAULT_GAS_PRICE.BASE + : DEFAULT_GAS_PRICE.GNOSIS, 'Gwei', ); } @@ -4291,6 +4296,55 @@ class BlockchainServiceBase { convertToWei(ether) { return Web3.utils.toWei(ether.toString(), 'ether'); } + + //Paymaster functions + async deployPaymasterContract(blockchain) { + const paymasterAddressContract = await this.callContractFunction( + 'PaymasterManager', + 'constructor', + [], + blockchain, + ); + + let { paymasterAddress } = await this.decodeEventLogs(paymasterAddressContract, 'deployPaymaster', blockchain); + + return paymasterAddress; + } + + async addAllowedAddress(blockchain, public_adress) { + return this.callContractFunction( + 'Paymaster', + 'addAllowedAddress', + [public_adress], + blockchain, + ); + } + + async removeAllowedAddress(blockchain, public_adress) { + return this.callContractFunction( + 'Paymaster', + 'removeAllowedAddress', + [public_adress], + blockchain, + ); + } + + async fundPaymaster(blockchain, tokenAmount) { + return this.callContractFunction('Paymaster', 'fundPaymaster', [tokenAmount], blockchain); + } + + async withdrawPaymaster(blockchain, recipient, tokenAmount) { + return this.callContractFunction( + 'Paymaster', + 'withdraw', + [recipient, tokenAmount], + blockchain, + ); + } + + async coverCostPaymaster(blockchain, tokenAmount) { + return this.callContractFunction('Paymaster', 'coverCost', [tokenAmount], blockchain); + } } /* eslint-disable no-await-in-loop */ @@ -4433,7 +4487,7 @@ class NodeBlockchainService extends BlockchainServiceBase { this.abis.KnowledgeCollectionStorage.filter((obj) => obj.type === 'event').forEach( (event) => { const concatInputs = event.inputs.map((input) => input.internalType); - + this.events[event.name] = { hash: Web3.utils.keccak256(`${event.name}(${concatInputs})`), inputs: event.inputs, @@ -5326,6 +5380,26 @@ class ValidationService { minimumNumberOfFinalizationConfirmations, ); } + + //Paymaster validator + + validatePaymasterAddress(blockchain, hubAddress) { + this.validateBlockchain(blockchain); + this.validateAddress(hubAddress); + } + + validatePaymasterToken(blockchain, tokenAmount) { + this.validateBlockchain(blockchain); + this.validateTokenAmount(tokenAmount); + } + + validatePaymasterTokenAdress(blockchain, tokenAmount, recipient) { + this.validateBlockchain(blockchain); + this.validateTokenAmount(tokenAmount); + this.validateAddress(recipient); + } + + } class InputService { diff --git a/index.js b/index.js index b456fe9..9c2a3e0 100644 --- a/index.js +++ b/index.js @@ -6,6 +6,7 @@ import GraphOperationsManager from './managers/graph-operations-manager.js'; import NetworkOperationsManager from './managers/network-operations-manager.js'; import NodeOperationsManager from './managers/node-operations-manager.js'; import ParanetOperationsManager from './managers/paranet-operations-manager.js'; +import PaymasterOperationsManager from './managers/paymaster-operations-manager.js'; import BaseServiceManager from './services/base-service-manager.js'; @@ -21,6 +22,7 @@ export default class DkgClient { this.graph = new GraphOperationsManager(services); this.network = new NetworkOperationsManager(services); this.paranet = new ParanetOperationsManager(services); + this.paymaster = new PaymasterOperationsManager(services); // Backwards compatibility this.graph.get = this.asset.get.bind(this.asset); diff --git a/managers/paymaster-operations-manager.js b/managers/paymaster-operations-manager.js new file mode 100644 index 0000000..f9bc1d7 --- /dev/null +++ b/managers/paymaster-operations-manager.js @@ -0,0 +1,88 @@ +export default class PaymasterOperationsManager { + constructor(services) { + this.blockchainService = services.blockchainService; + this.inputService = services.inputService; + this.validationService = services.validationService; + } + + /** + * @async + * @param {BigInt} tokenAmount - The amount of tokens (Wei) to set the allowance. + * @param {Object} [options={}] - Additional options for increasing allowance - currently only blockchain option expected. + * @param {string} recipient - The address of the recipient (used for operations like withdrawal or funding). + * @returns {Object} Object containing hash of blockchain transaction and status. + */ + + async deployPaymasterContract(options = {}) { + try { + const blockchain = this.inputService.getBlockchain(options); + + this.validationService.validateBlockchain(blockchain); + + const paymasterAddress = await this.blockchainService.deployPaymasterContract(blockchain); + + return paymasterAddress; + + } catch (error) { + console.error('Error deploying Paymaster contract:', error); + } + } + + async addAllowedAddress(paymasterAddress,addresToBeWhitelested, options = {}) { + try { + const blockchain = this.inputService.getBlockchain(options); + + this.validationService.validatePaymasterAddress(blockchain, paymasterAddress, addresToBeWhitelested); + + await this.blockchainService.addAllowedAddress(blockchain, paymasterAddress, addresToBeWhitelested); + + } catch (error) { + console.error('Error adding allowed address:', error); + } + } + + async removeAllowedAddress(paymasterAddress, addresToBeWhitelested, options = {}) { + try { + const blockchain = this.inputService.getBlockchain(options); + + this.validationService.validatePaymasterAddress(blockchain, paymasterAddress, addresToBeWhitelested); + + await this.blockchainService.removeAllowedAddress(blockchain,paymasterAddress, addresToBeWhitelested); + + } catch (error) { + console.error('Error removing allowed address:', error); + } + } + + async fundPaymaster(paymasterAddress, tokenAmount, options = {}) { + try { + const blockchain = this.inputService.getBlockchain(options); + + this.validationService.validatePaymasterToken(blockchain, paymasterAddress, tokenAmount); + + await this.blockchainService.fundPaymaster(blockchain, paymasterAddress, tokenAmount); + + } catch (error) { + console.error('Error funding paymaster:', error); + } + } + + async withdraw(paymasterAddress, recipient, tokenAmount, options = {}) { + try { + const blockchain = this.inputService.getBlockchain(options); + + this.validationService.validatePaymasterTokenAdress( + blockchain, + paymasterAddress, + tokenAmount, + recipient, + ) + + await this.blockchainService.withdrawPaymaster(blockchain, paymasterAddress, recipient, tokenAmount); + + } catch (error) { + console.error('Error withdrawing:', error); + } + } + +} diff --git a/services/blockchain-service/blockchain-service-base.js b/services/blockchain-service/blockchain-service-base.js index 1c3a37a..7302816 100644 --- a/services/blockchain-service/blockchain-service-base.js +++ b/services/blockchain-service/blockchain-service-base.js @@ -26,6 +26,8 @@ const KnowledgeCollectionAbi = require('dkg-evm-module/abi/KnowledgeCollection.j const KnowledgeCollectionStorageAbi = require('dkg-evm-module/abi/KnowledgeCollectionStorage.json'); const AskStorageAbi = require('dkg-evm-module/abi/AskStorage.json'); const ChronosAbi = require('dkg-evm-module/abi/Chronos.json'); +const PaymasterAbi = require('dkg-evm-module/abi/Paymaster.json'); +const PaymasterManagerAbi = require('dkg-evm-module/abi/PaymasterManager.json'); export default class BlockchainServiceBase { constructor(config = {}) { @@ -50,6 +52,8 @@ export default class BlockchainServiceBase { this.abis.KnowledgeCollectionStorage = KnowledgeCollectionStorageAbi; this.abis.AskStorage = AskStorageAbi; this.abis.Chronos = ChronosAbi; + this.abis.Paymaster = PaymasterAbi; + this.abis.PaymasterManager = PaymasterManagerAbi; this.abis.KnowledgeCollectionStorage.filter((obj) => obj.type === 'event').forEach( (event) => { @@ -61,6 +65,18 @@ export default class BlockchainServiceBase { }; }, ); + + this.abis.PaymasterManager.filter((obj) => obj.type === 'event').forEach( + (event) => { + const concatInputs = event.inputs.map((input) => input.internalType); + + this.events[event.name] = { + hash: Web3.utils.keccak256(`${event.name}(${concatInputs})`), + inputs: event.inputs, + }; + + }, + ); } initializeWeb3() { @@ -144,8 +160,8 @@ export default class BlockchainServiceBase { blockchain.name.startsWith('otp') ? DEFAULT_GAS_PRICE.OTP : blockchain.name.startsWith('base') - ? DEFAULT_GAS_PRICE.BASE - : DEFAULT_GAS_PRICE.GNOSIS, + ? DEFAULT_GAS_PRICE.BASE + : DEFAULT_GAS_PRICE.GNOSIS, 'Gwei', ); } @@ -178,17 +194,123 @@ export default class BlockchainServiceBase { } } + async callContractFunctionPaymaster(paymasterAddress, contractName, functionName, args, blockchain) { + await this.ensureBlockchainInfo(blockchain); + + const web3Instance = await this.getWeb3Instance(blockchain); + const publicKey = await this.getPublicKey(blockchain); + + // const account = web3Instance.eth.accounts.privateKeyToAccount("8ae4f7c247ad422913c1c60187856091ad2bcb4e53fb2936d7633d7d02bd180a"); + + // web3Instance.eth.accounts.wallet.add(account); + + let paymasterContractInstance = new web3Instance.eth.Contract( + this.abis[contractName], + paymasterAddress, + { from: publicKey }, + ) + + try { + return await paymasterContractInstance.methods[functionName](...args).send({ + from: publicKey, + gas: 100000, + }); + + } catch (error) { + if (/revert|VM Exception/i.test(error.message)) { + let status; + try { + status = await paymasterContractInstance.methods.status().call(); + } catch (_) { + status = false; + } + + if (!status && contractName !== 'ParanetNeuroIncentivesPool') { + await this.updateContractInstance(contractName, blockchain, true); + let paymasterContractInstance = new web3Instance.eth.Contract( + this.abis[contractName], + this[blockchain.name].contractAddress[blockchain.hubContract][contractName], + { from: blockchain.publicKey }, + ) + + return paymasterContractInstance.methods[functionName](...args).call(); + } + } + + throw error; + } + } + + async executeContractFunctionPaymaster(paymasterAddress, contractName, functionName, args, blockchain) { + await this.ensureBlockchainInfo(blockchain); + + const web3Instance = await this.getWeb3Instance(blockchain); + const publicKey = await this.getPublicKey(blockchain); + + let paymasterContractInstance = new web3Instance.eth.Contract( + this.abis[contractName], + paymasterAddress, + { from: publicKey }, + ) + + // let paymasterContractInstance = await this.getContractInstance(contractName, blockchain); + + let tx; + + try { + + tx = await this.prepareTransaction(paymasterContractInstance, functionName, args, blockchain); + + let receipt = await paymasterContractInstance.methods[functionName](...args).send(tx); + if (blockchain.name.startsWith('otp') && blockchain.waitNeurowebTxFinalization) { + receipt = await this.waitForTransactionFinalization(receipt, blockchain); + } + + console.log(receipt); + return receipt; + } catch (error) { + if (/revert|VM Exception/i.test(error.message)) { + let status; + try { + status = await paymasterContractInstance.methods.status().call(); + } catch (_) { + status = false; + } + + if (!status) { + await this.updateContractInstance(contractName, blockchain, true); + paymasterContractInstance = await this.getContractInstance(contractName, blockchain); + const web3Instance = await this.getWeb3Instance(blockchain); + + await web3Instance.eth.call({ + to: paymasterContractInstance.options.address, + data: tx.data, + from: tx.from, + }); + + return paymasterContractInstance.methods[functionName](...args).send(tx); + } + } + + throw error; + } + } + async prepareTransaction(contractInstance, functionName, args, blockchain) { await this.ensureBlockchainInfo(blockchain); const web3Instance = await this.getWeb3Instance(blockchain); const publicKey = await this.getPublicKey(blockchain); const encodedABI = await contractInstance.methods[functionName](...args).encodeABI(); + console.log(contractInstance.methods) + let gasLimit = Number( await contractInstance.methods[functionName](...args).estimateGas({ from: publicKey, }), ); + + gasLimit = Math.round(gasLimit * blockchain.gasLimitMultiplier); let gasPrice; @@ -406,7 +528,7 @@ export default class BlockchainServiceBase { blockchain, stepHooks = emptyHooks, ) { - const sender = await this.getPublicKey(blockchain); + const sender = await this.getPublicKey(blockchain); let serviceAgreementV1Address; let allowanceIncreased = false; let allowanceGap = 0; @@ -1144,8 +1266,8 @@ export default class BlockchainServiceBase { blockchain.name.startsWith('otp') ? DEFAULT_GAS_PRICE.OTP : blockchain.name.startsWith('base') - ? DEFAULT_GAS_PRICE.BASE - : DEFAULT_GAS_PRICE.GNOSIS, + ? DEFAULT_GAS_PRICE.BASE + : DEFAULT_GAS_PRICE.GNOSIS, 'Gwei', ); } @@ -1204,4 +1326,60 @@ export default class BlockchainServiceBase { convertToWei(ether) { return Web3.utils.toWei(ether.toString(), 'ether'); } + + //Paymaster functions + async deployPaymasterContract(blockchain) { + const paymasterAddressContract = await this.executeContractFunction( + 'PaymasterManager', + 'deployPaymaster', + [], + blockchain, + ); + + + let { paymasterAddress } = await this.decodeEventLogs(paymasterAddressContract, 'PaymasterDeployed', blockchain); + + return paymasterAddress; + } + + async addAllowedAddress(blockchain, paymasterAddress, public_adress) { + return this.executeContractFunctionPaymaster( + paymasterAddress, + 'Paymaster', + 'addAllowedAddress', + [public_adress], + blockchain, + ); + } + + async removeAllowedAddress(blockchain, paymasterAddress, public_adress) { + return this.executeContractFunctionPaymaster( + paymasterAddress, + 'Paymaster', + 'removeAllowedAddress', + [public_adress], + blockchain, + ); + } + + async fundPaymaster(blockchain, paymasterAddress, tokenAmount) { + return this.executeContractFunctionPaymaster( + paymasterAddress, + 'Paymaster', + 'fundPaymaster', + [tokenAmount], + blockchain); + } + + async withdrawPaymaster(blockchain, paymasterAddress, recipient, tokenAmount) { + + return this.executeContractFunctionPaymaster( + paymasterAddress, + 'Paymaster', + 'withdraw', + [recipient, tokenAmount], + blockchain, + ); + } + } diff --git a/services/blockchain-service/implementations/node-blockchain-service.js b/services/blockchain-service/implementations/node-blockchain-service.js index ada2350..e9158f6 100644 --- a/services/blockchain-service/implementations/node-blockchain-service.js +++ b/services/blockchain-service/implementations/node-blockchain-service.js @@ -20,6 +20,18 @@ export default class NodeBlockchainService extends BlockchainServiceBase { }; }, ); + + this.abis.PaymasterManager.filter((obj) => obj.type === 'event').forEach( + (event) => { + const concatInputs = event.inputs.map((input) => input.internalType); + + this.events[event.name] = { + hash: Web3.utils.keccak256(`${event.name}(${concatInputs})`), + inputs: event.inputs, + }; + + }, + ); } initializeWeb3(blockchainName, blockchainRpc, blockchainOptions) { diff --git a/services/validation-service.js b/services/validation-service.js index a8b79a9..59f217c 100644 --- a/services/validation-service.js +++ b/services/validation-service.js @@ -605,7 +605,6 @@ export default class ValidationService { this.validateTransactionPollingTimeout(blockchain.transactionPollingTimeout); if (nodeSupported()) { this.validateRequiredParam('blockchain rpc', blockchain.rpc); - if (operation !== OPERATIONS.GET) { this.validateRequiredParam('blockchain public key', blockchain.publicKey); this.validateRequiredParam('blockchain private key', blockchain.privateKey); @@ -773,4 +772,27 @@ export default class ValidationService { minimumNumberOfFinalizationConfirmations, ); } + + //Paymaster validator + + validatePaymasterAddress(blockchain, paymasterAddress, hubAddress) { + this.validateBlockchain(blockchain); + this.validateAddress(paymasterAddress); + this.validateAddress(hubAddress); + } + + validatePaymasterToken(blockchain, paymasterAddress, tokenAmount) { + this.validateBlockchain(blockchain); + this.validateAddress(paymasterAddress); + this.validateTokenAmount(tokenAmount); + } + + validatePaymasterTokenAdress(blockchain, paymasterAddress, tokenAmount, recipient) { + this.validateBlockchain(blockchain); + this.validateAddress(paymasterAddress); + this.validateTokenAmount(tokenAmount); + this.validateAddress(recipient); + } + + }