diff --git a/package-lock.json b/package-lock.json index 4065de8716..74312c6f1a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27552,6 +27552,7 @@ "version": "102.0.0-beta.0", "license": "Apache-2.0", "dependencies": { + "@streamr/config": "^5.4.1", "@streamr/utils": "102.0.0-beta.0", "cors": "^2.8.5", "ethers": "^6.13.0", diff --git a/packages/node/test/integration/plugins/operator/MaintainTopologyService.test.ts b/packages/node/test/integration/plugins/operator/MaintainTopologyService.test.ts index 152660c5b9..9ef575380e 100644 --- a/packages/node/test/integration/plugins/operator/MaintainTopologyService.test.ts +++ b/packages/node/test/integration/plugins/operator/MaintainTopologyService.test.ts @@ -1,21 +1,20 @@ import { Stream, StreamrClient, _operatorContractUtils } from '@streamr/sdk' -import { fastPrivateKey, fetchPrivateKeyWithGas } from '@streamr/test-utils' +import { fastPrivateKey, fetchPrivateKeyWithGas, generateWalletWithGasAndTokens } from '@streamr/test-utils' import { StreamPartID, toEthereumAddress, until } from '@streamr/utils' +import { parseEther } from 'ethers' import { MaintainTopologyHelper } from '../../../../src/plugins/operator/MaintainTopologyHelper' import { MaintainTopologyService } from '../../../../src/plugins/operator/MaintainTopologyService' import { OperatorFleetState } from '../../../../src/plugins/operator/OperatorFleetState' import { StreamPartAssignments } from '../../../../src/plugins/operator/StreamPartAssignments' import { formCoordinationStreamId } from '../../../../src/plugins/operator/formCoordinationStreamId' import { createClient, createTestStream } from '../../../utils' -import { parseEther } from 'ethers' const { delegate, deployOperatorContract, deploySponsorshipContract, - generateWalletWithGasAndTokens, stake } = _operatorContractUtils diff --git a/packages/node/test/integration/plugins/operator/OperatorPlugin.test.ts b/packages/node/test/integration/plugins/operator/OperatorPlugin.test.ts index a6f6328c95..1baeb24e69 100644 --- a/packages/node/test/integration/plugins/operator/OperatorPlugin.test.ts +++ b/packages/node/test/integration/plugins/operator/OperatorPlugin.test.ts @@ -4,9 +4,9 @@ import { StreamPermission, _operatorContractUtils } from '@streamr/sdk' -import { fastPrivateKey, fetchPrivateKeyWithGas } from '@streamr/test-utils' +import { fastPrivateKey, fetchPrivateKeyWithGas, generateWalletWithGasAndTokens } from '@streamr/test-utils' import { EthereumAddress, collect, toEthereumAddress, toStreamPartID, until } from '@streamr/utils' -import { parseEther, Wallet } from 'ethers' +import { Wallet, parseEther } from 'ethers' import { cloneDeep, set } from 'lodash' import { Broker, createBroker } from '../../../../src/broker' import { formCoordinationStreamId } from '../../../../src/plugins/operator/formCoordinationStreamId' @@ -15,7 +15,6 @@ import { createClient, createTestStream, formConfig, startBroker } from '../../. const { delegate, deploySponsorshipContract, - generateWalletWithGasAndTokens, setupOperatorContract, sponsor, stake @@ -32,7 +31,8 @@ describe('OperatorPlugin', () => { beforeAll(async () => { const deployment = (await setupOperatorContract({ - nodeCount: 1 + nodeCount: 1, + generateWalletWithGasAndTokens })) brokerWallet = deployment.nodeWallets[0] operatorWallet = deployment.operatorWallet diff --git a/packages/node/test/integration/plugins/operator/announceNodeToContract.test.ts b/packages/node/test/integration/plugins/operator/announceNodeToContract.test.ts index 977a7124b6..c3d52b50ec 100644 --- a/packages/node/test/integration/plugins/operator/announceNodeToContract.test.ts +++ b/packages/node/test/integration/plugins/operator/announceNodeToContract.test.ts @@ -2,6 +2,7 @@ import { Operator, _operatorContractUtils } from '@streamr/sdk' import { toEthereumAddress, until } from '@streamr/utils' import { announceNodeToContract } from '../../../../src/plugins/operator/announceNodeToContract' import { createClient } from '../../../utils' +import { generateWalletWithGasAndTokens } from '@streamr/test-utils' const TIMEOUT = 30 * 1000 @@ -11,7 +12,8 @@ describe('announceNodeToContract', () => { beforeEach(async () => { const { operatorContract, nodeWallets } = await _operatorContractUtils.setupOperatorContract({ - nodeCount: 1 + nodeCount: 1, + generateWalletWithGasAndTokens }) operator = createClient(nodeWallets[0].privateKey).getOperator(toEthereumAddress(await operatorContract.getAddress())) }, TIMEOUT) diff --git a/packages/node/test/integration/plugins/operator/announceNodeToStream.test.ts b/packages/node/test/integration/plugins/operator/announceNodeToStream.test.ts index fa37e8dc2a..7ce23e1cd1 100644 --- a/packages/node/test/integration/plugins/operator/announceNodeToStream.test.ts +++ b/packages/node/test/integration/plugins/operator/announceNodeToStream.test.ts @@ -1,5 +1,5 @@ import { _operatorContractUtils } from '@streamr/sdk' -import { fastPrivateKey } from '@streamr/test-utils' +import { fastPrivateKey, generateWalletWithGasAndTokens } from '@streamr/test-utils' import { collect, toEthereumAddress } from '@streamr/utils' import { announceNodeToStream } from '../../../../src/plugins/operator/announceNodeToStream' import { formCoordinationStreamId } from '../../../../src/plugins/operator/formCoordinationStreamId' @@ -11,7 +11,8 @@ describe('announceNodeToStream', () => { it('publishes to stream', async () => { const { operatorContract, nodeWallets } = await _operatorContractUtils.setupOperatorContract({ - nodeCount: 1 + nodeCount: 1, + generateWalletWithGasAndTokens }) const operatorContractAddress = toEthereumAddress(await operatorContract.getAddress()) const nodeWallet = nodeWallets[0] diff --git a/packages/node/test/integration/plugins/operator/checkOperatorValueBreach.test.ts b/packages/node/test/integration/plugins/operator/checkOperatorValueBreach.test.ts index b184a5860b..2abcd92991 100644 --- a/packages/node/test/integration/plugins/operator/checkOperatorValueBreach.test.ts +++ b/packages/node/test/integration/plugins/operator/checkOperatorValueBreach.test.ts @@ -3,6 +3,7 @@ import { SetupOperatorContractOpts, _operatorContractUtils, } from '@streamr/sdk' +import { generateWalletWithGasAndTokens } from '@streamr/test-utils' import { Logger, toEthereumAddress, until } from '@streamr/utils' import { Contract, parseEther } from 'ethers' import { checkOperatorValueBreach } from '../../../../src/plugins/operator/checkOperatorValueBreach' @@ -11,7 +12,6 @@ import { createClient, createTestStream } from '../../../utils' const { delegate, deploySponsorshipContract, - generateWalletWithGasAndTokens, getProvider, setupOperatorContract, sponsor, @@ -40,13 +40,14 @@ describe('checkOperatorValueBreach', () => { deployConfig = { operatorConfig: { operatorsCutPercentage: 10 - } + }, + generateWalletWithGasAndTokens } }, 60 * 1000) it('withdraws the other Operators earnings when they are above the limit', async () => { // eslint-disable-next-line max-len - const { operatorContract: watcherOperatorContract, nodeWallets: watcherWallets } = await setupOperatorContract({ nodeCount: 1, ...deployConfig }) + const { operatorContract: watcherOperatorContract, nodeWallets: watcherWallets } = await setupOperatorContract({ nodeCount: 1, ...deployConfig, generateWalletWithGasAndTokens }) const { operatorWallet, operatorContract } = await setupOperatorContract(deployConfig) const sponsorer = await generateWalletWithGasAndTokens() await delegate(operatorWallet, await operatorContract.getAddress(), parseEther('20000')) diff --git a/packages/node/test/integration/plugins/operator/maintainOperatorValue.test.ts b/packages/node/test/integration/plugins/operator/maintainOperatorValue.test.ts index bff2683916..935ea61dee 100644 --- a/packages/node/test/integration/plugins/operator/maintainOperatorValue.test.ts +++ b/packages/node/test/integration/plugins/operator/maintainOperatorValue.test.ts @@ -1,5 +1,5 @@ import { _operatorContractUtils } from '@streamr/sdk' -import { fetchPrivateKeyWithGas } from '@streamr/test-utils' +import { fetchPrivateKeyWithGas, generateWalletWithGasAndTokens } from '@streamr/test-utils' import { Logger, multiplyWeiAmount, toEthereumAddress, until } from '@streamr/utils' import { parseEther } from 'ethers' import { maintainOperatorValue } from '../../../../src/plugins/operator/maintainOperatorValue' @@ -8,7 +8,6 @@ import { createClient, createTestStream } from '../../../utils' const { delegate, deploySponsorshipContract, - generateWalletWithGasAndTokens, setupOperatorContract, sponsor, stake @@ -41,7 +40,8 @@ describe('maintainOperatorValue', () => { nodeCount: 1, operatorConfig: { operatorsCutPercentage: 10 - } + }, + generateWalletWithGasAndTokens }) const sponsorer = await generateWalletWithGasAndTokens() const sponsorship = await deploySponsorshipContract({ earningsPerSecond: parseEther('100'), streamId, deployer: operatorWallet }) diff --git a/packages/node/test/smoke/inspect.test.ts b/packages/node/test/smoke/inspect.test.ts index 9748f48a8d..cfb965cd91 100644 --- a/packages/node/test/smoke/inspect.test.ts +++ b/packages/node/test/smoke/inspect.test.ts @@ -1,8 +1,8 @@ import { config as CHAIN_CONFIG } from '@streamr/config' import { StreamrConfig, streamrConfigABI } from '@streamr/network-contracts' import { _operatorContractUtils } from '@streamr/sdk' -import { fetchPrivateKeyWithGas } from '@streamr/test-utils' -import { Logger, StreamID, TheGraphClient, wait, until, multiplyWeiAmount } from '@streamr/utils' +import { fetchPrivateKeyWithGas, generateWalletWithGasAndTokens } from '@streamr/test-utils' +import { Logger, multiplyWeiAmount, StreamID, TheGraphClient, until, wait } from '@streamr/utils' import { Contract, JsonRpcProvider, parseEther, Wallet } from 'ethers' import { Broker, createBroker } from '../../src/broker' import { createClient, createTestStream, formConfig } from '../utils' @@ -38,7 +38,6 @@ import { OperatorPluginConfig } from './../../src/plugins/operator/OperatorPlugi const { setupOperatorContract, getProvider, - generateWalletWithGasAndTokens, deploySponsorshipContract, delegate, stake, @@ -95,7 +94,8 @@ const createOperator = async ( nodeCount: 1, operatorConfig: { metadata: JSON.stringify({ redundancyFactor: 1 }) - } + }, + generateWalletWithGasAndTokens }) await delegate(operator.operatorWallet, await operator.operatorContract.getAddress(), DELEGATE_AMOUNT) await stake(operator.operatorContract, sponsorshipAddress, STAKE_AMOUNT) diff --git a/packages/node/test/smoke/profit.test.ts b/packages/node/test/smoke/profit.test.ts index 2b45d443ab..605a6bb82f 100644 --- a/packages/node/test/smoke/profit.test.ts +++ b/packages/node/test/smoke/profit.test.ts @@ -2,7 +2,7 @@ import { config as CHAIN_CONFIG } from '@streamr/config' import type { Operator, Sponsorship } from '@streamr/network-contracts' import { StreamrConfig, streamrConfigABI } from '@streamr/network-contracts' import { _operatorContractUtils } from '@streamr/sdk' -import { fetchPrivateKeyWithGas } from '@streamr/test-utils' +import { fetchPrivateKeyWithGas, generateWalletWithGasAndTokens } from '@streamr/test-utils' import { multiplyWeiAmount, until, WeiAmount } from '@streamr/utils' import { Contract, Wallet, parseEther } from 'ethers' import { createClient, createTestStream, startBroker } from '../utils' @@ -35,7 +35,6 @@ import { createClient, createTestStream, startBroker } from '../utils' const { setupOperatorContract, getProvider, - generateWalletWithGasAndTokens, deploySponsorshipContract, sponsor, delegate, @@ -104,7 +103,8 @@ describe('profit', () => { nodeCount: 1, operatorConfig: { operatorsCutPercentage: OPERATORS_CUT_PERCENTAGE - } + }, + generateWalletWithGasAndTokens })) sponsorshipContract = await deploySponsorshipContract({ earningsPerSecond: EARNINGS_PER_SECOND, diff --git a/packages/sdk/src/contracts/operatorContractUtils.ts b/packages/sdk/src/contracts/operatorContractUtils.ts index f901751ac7..a5e1123a48 100644 --- a/packages/sdk/src/contracts/operatorContractUtils.ts +++ b/packages/sdk/src/contracts/operatorContractUtils.ts @@ -1,7 +1,10 @@ import { config as CHAIN_CONFIG } from '@streamr/config' -import { Logger, multiplyWeiAmount, retry, WeiAmount } from '@streamr/utils' -import { Contract, EventLog, JsonRpcProvider, Provider, Wallet, ZeroAddress, parseEther } from 'ethers' +import { Logger, multiplyWeiAmount, WeiAmount } from '@streamr/utils' +import { Contract, EventLog, JsonRpcProvider, parseEther, Provider, Wallet, ZeroAddress } from 'ethers' import { range } from 'lodash' +import { SignerWithProvider } from '../Authentication' +import type { DATAv2 as DATATokenContract } from '../ethereumArtifacts/DATAv2' +import DATATokenArtifact from '../ethereumArtifacts/DATAv2Abi.json' import type { Operator as OperatorContract } from '../ethereumArtifacts/Operator' import OperatorArtifact from '../ethereumArtifacts/OperatorAbi.json' import type { OperatorFactory as OperatorFactoryContract } from '../ethereumArtifacts/OperatorFactory' @@ -10,10 +13,6 @@ import type { Sponsorship as SponsorshipContract } from '../ethereumArtifacts/Sp import SponsorshipArtifact from '../ethereumArtifacts/SponsorshipAbi.json' import type { SponsorshipFactory as SponsorshipFactoryContract } from '../ethereumArtifacts/SponsorshipFactory' import SponsorshipFactoryArtifact from '../ethereumArtifacts/SponsorshipFactoryAbi.json' -import type { DATAv2 as DATATokenContract } from '../ethereumArtifacts/DATAv2' -import DATATokenArtifact from '../ethereumArtifacts/DATAv2Abi.json' -import { SignerWithProvider } from '../Authentication' -import crypto from 'crypto' const TEST_CHAIN_CONFIG = CHAIN_CONFIG.dev2 const FRACTION_MAX = parseEther('1') @@ -28,6 +27,7 @@ export interface SetupOperatorContractOpts { operatorsCutPercentage?: number metadata?: string } + generateWalletWithGasAndTokens: () => Promise } /** @@ -43,9 +43,9 @@ export interface SetupOperatorContractReturnType { const logger = new Logger(module) export async function setupOperatorContract( - opts?: SetupOperatorContractOpts + opts: SetupOperatorContractOpts ): Promise { - const operatorWallet = await generateWalletWithGasAndTokens() + const operatorWallet = await opts.generateWalletWithGasAndTokens() const operatorContract = await deployOperatorContract({ deployer: operatorWallet, operatorsCutPercentage: opts?.operatorConfig?.operatorsCutPercentage, @@ -54,7 +54,7 @@ export async function setupOperatorContract( const nodeWallets: (Wallet & SignerWithProvider)[] = [] if ((opts?.nodeCount !== undefined) && (opts?.nodeCount > 0)) { for (const _ of range(opts.nodeCount)) { - nodeWallets.push(await generateWalletWithGasAndTokens()) + nodeWallets.push(await opts.generateWalletWithGasAndTokens()) } await (await operatorContract.setNodeAddresses(nodeWallets.map((w) => w.address))).wait() } @@ -161,30 +161,6 @@ export const getTestAdminWallet = (adminKey?: string, provider?: Provider): Wall return new Wallet(adminKey ?? TEST_CHAIN_CONFIG.adminPrivateKey).connect(provider ?? getProvider()) } -export async function generateWalletWithGasAndTokens(): Promise { - const provider = getProvider() - const privateKey = crypto.randomBytes(32).toString('hex') - const newWallet = new Wallet(privateKey) - const adminWallet = getTestAdminWallet() - const token = getTestTokenContract().connect(adminWallet) - await retry( - async () => { - await (await token.mint(newWallet.address, parseEther('1000000'))).wait() - await (await adminWallet.sendTransaction({ - to: newWallet.address, - value: parseEther('1') - })).wait() - }, - (message: string, err: any) => { - logger.debug(message, { err }) - }, - 'Token minting', - 10, - 100 - ) - return newWallet.connect(provider) as (Wallet & SignerWithProvider) -} - export const delegate = async (delegator: Wallet, operatorContractAddress: string, amount: WeiAmount, token?: DATATokenContract): Promise => { logger.debug('Delegate', { amount: amount.toString() }) // onTokenTransfer: the tokens are delegated on behalf of the given data address diff --git a/packages/sdk/src/exports.ts b/packages/sdk/src/exports.ts index 08ef4ca55a..888093094b 100644 --- a/packages/sdk/src/exports.ts +++ b/packages/sdk/src/exports.ts @@ -102,7 +102,6 @@ import { stake, unstake, getProvider, - generateWalletWithGasAndTokens, DeploySponsorshipContractOpts, getTestTokenContract, getTestAdminWallet, @@ -122,7 +121,6 @@ const _operatorContractUtils = { stake, unstake, getProvider, - generateWalletWithGasAndTokens, deployOperatorContract, getTestTokenContract, getTestAdminWallet, diff --git a/packages/sdk/test/end-to-end/Operator.test.ts b/packages/sdk/test/end-to-end/Operator.test.ts index 35f5a04bee..28719fbb71 100644 --- a/packages/sdk/test/end-to-end/Operator.test.ts +++ b/packages/sdk/test/end-to-end/Operator.test.ts @@ -1,5 +1,5 @@ import { config as CHAIN_CONFIG } from '@streamr/config' -import { fetchPrivateKeyWithGas } from '@streamr/test-utils' +import { fetchPrivateKeyWithGas, generateWalletWithGasAndTokens } from '@streamr/test-utils' import { Logger, TheGraphClient, toEthereumAddress, until } from '@streamr/utils' import { Contract, parseEther, Wallet } from 'ethers' import { StreamrClient } from '../../src/StreamrClient' @@ -61,7 +61,7 @@ describe('Operator', () => { const concurrentTasks = await Promise.all([ createStream(), createStream(), - setupOperatorContract({ nodeCount: 1 }) + setupOperatorContract({ nodeCount: 1, generateWalletWithGasAndTokens }) ]) streamId1 = concurrentTasks[0] streamId2 = concurrentTasks[1] @@ -135,7 +135,9 @@ describe('Operator', () => { it('flag', async () => { const flagger = deployedOperator - const target = await setupOperatorContract() + const target = await setupOperatorContract({ + generateWalletWithGasAndTokens + }) await sponsor(flagger.operatorWallet, await sponsorship2.getAddress(), parseEther('50000')) diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 9b7e9ce22d..25576fa33a 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -23,6 +23,7 @@ "author": "Streamr Network AG ", "license": "Apache-2.0", "dependencies": { + "@streamr/config": "^5.4.1", "@streamr/utils": "102.0.0-beta.0", "cors": "^2.8.5", "ethers": "^6.13.0", diff --git a/packages/test-utils/src/index.ts b/packages/test-utils/src/index.ts index dced9ffa8f..71acdf3150 100644 --- a/packages/test-utils/src/index.ts +++ b/packages/test-utils/src/index.ts @@ -1,16 +1,19 @@ -import { EthereumAddress, toEthereumAddress, toUserId, UserID, until, waitForEvent } from '@streamr/utils' +import { EthereumAddress, toEthereumAddress, toUserId, UserID, until, waitForEvent, Logger, retry } from '@streamr/utils' import cors from 'cors' import crypto, { randomBytes } from 'crypto' -import { Wallet } from 'ethers' +import { AbstractSigner, Contract, JsonRpcProvider, parseEther, Provider, TransactionResponse, Wallet } from 'ethers' import { EventEmitter, once } from 'events' import express from 'express' import http from 'http' import random from 'lodash/random' import { AddressInfo } from 'net' import { Readable } from 'stream' +import { config as CHAIN_CONFIG } from '@streamr/config' export type Event = string +const logger = new Logger(module) + /** * Collect data of a stream into an array. The array is wrapped in a * Promise that resolves when the stream has ended, i.e., event `end` is @@ -341,3 +344,62 @@ export type Methods = Pick> import * as customMatchers from './customMatchers' export { customMatchers } + +const TEST_CHAIN_CONFIG = CHAIN_CONFIG.dev2 + +const getTestProvider = (): Provider => { + return new JsonRpcProvider(TEST_CHAIN_CONFIG.rpcEndpoints[0].url, undefined, { + batchStallTime: 0, // Don't batch requests, send them immediately + cacheTimeout: -1 // Do not employ result caching + }) +} + +export function getTestTokenContract(adminWallet: Wallet): { mint: (targetAddress: string, amountWei: bigint) => Promise } { + const ABI = [{ + inputs: [ + { + internalType: 'address', + name: 'to', + type: 'address' + }, + { + internalType: 'uint256', + name: 'amount', + type: 'uint256' + } + ], + name: 'mint', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }] + return new Contract(TEST_CHAIN_CONFIG.contracts.DATA, ABI).connect(adminWallet) as unknown as { mint: () => Promise } +} + +export const getTestAdminWallet = (provider: Provider): Wallet => { + return new Wallet(TEST_CHAIN_CONFIG.adminPrivateKey).connect(provider) +} + +export const generateWalletWithGasAndTokens = async (): Promise> => { + const provider = getTestProvider() + const privateKey = crypto.randomBytes(32).toString('hex') + const newWallet = new Wallet(privateKey) + const adminWallet = getTestAdminWallet(provider) + const token = getTestTokenContract(adminWallet) + await retry( + async () => { + await (await token.mint(newWallet.address, parseEther('1000000'))).wait() + await (await adminWallet.sendTransaction({ + to: newWallet.address, + value: parseEther('1') + })).wait() + }, + (message: string, err: any) => { + logger.debug(message, { err }) + }, + 'Token minting', + 10, + 100 + ) + return newWallet.connect(provider) as (Wallet & AbstractSigner) +}