Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions packages/cli-tools/bin/streamr-internal-operator-delegate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env node
import '../src/logLevel'

import { StreamrClient, _operatorContractUtils } from '@streamr/sdk'
import { createClientCommand } from '../src/command'
import { parseEther } from 'ethers'

createClientCommand(async (client: StreamrClient, operatorAddress: string, dataTokenAmount: string) => {
await _operatorContractUtils.delegate(
await client.getSigner(),
operatorAddress,
parseEther(dataTokenAmount),
_operatorContractUtils.getTestTokenContract()
)
})
.description('delegate funds to an operator')
.arguments('<operatorAddress> <dataTokenAmount>')
.parseAsync()
18 changes: 18 additions & 0 deletions packages/cli-tools/bin/streamr-internal-operator-stake.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env node
import '../src/logLevel'

import { StreamrClient, _operatorContractUtils } from '@streamr/sdk'
import { createClientCommand } from '../src/command'
import { parseEther } from 'ethers'

createClientCommand(async (client: StreamrClient, operatorContractAddress: string, sponsorshipAddress: string, dataTokenAmount: string) => {
const operatorContract = _operatorContractUtils.getOperatorContract(operatorContractAddress).connect(await client.getSigner())
await _operatorContractUtils.stake(
operatorContract,
sponsorshipAddress,
parseEther(dataTokenAmount)
)
})
.description('stake funds to a sponsorship')
.arguments('<operatorContractAddress> <sponsorshipAddress> <dataTokenAmount>')
.parseAsync()
17 changes: 17 additions & 0 deletions packages/cli-tools/bin/streamr-internal-operator-undelegate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env node
import '../src/logLevel'

import { StreamrClient, _operatorContractUtils } from '@streamr/sdk'
import { createClientCommand } from '../src/command'
import { parseEther } from 'ethers'

createClientCommand(async (client: StreamrClient, operatorAddress: string, dataTokenAmount: string) => {
await _operatorContractUtils.undelegate(
await client.getSigner(),
_operatorContractUtils.getOperatorContract(operatorAddress),
parseEther(dataTokenAmount)
)
})
.description('undelegate funds from an operator')
.arguments('<operatorAddress> <dataTokenAmount>')
.parseAsync()
16 changes: 16 additions & 0 deletions packages/cli-tools/bin/streamr-internal-operator-unstake.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env node
import '../src/logLevel'

import { StreamrClient, _operatorContractUtils } from '@streamr/sdk'
import { createClientCommand } from '../src/command'

createClientCommand(async (client: StreamrClient, operatorContractAddress: string, sponsorshipAddress: string) => {
const operatorContract = _operatorContractUtils.getOperatorContract(operatorContractAddress).connect(await client.getSigner())
await _operatorContractUtils.unstake(
operatorContract,
sponsorshipAddress
)
})
.arguments('<operatorContractAddress> <sponsorshipAddress>')
.description('unstake all funds from a sponsorship')
.parseAsync()
18 changes: 18 additions & 0 deletions packages/cli-tools/bin/streamr-internal-sponsorship-sponsor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env node
import '../src/logLevel'

import { StreamrClient, _operatorContractUtils } from '@streamr/sdk'
import { createClientCommand } from '../src/command'
import { parseEther } from 'ethers'

createClientCommand(async (client: StreamrClient, sponsorshipAddress: string, dataTokenAmount: string) => {
await _operatorContractUtils.sponsor(
await client.getSigner(),
sponsorshipAddress,
parseEther(dataTokenAmount),
_operatorContractUtils.getTestTokenContract()
)
})
.description('sponsor a stream')
.arguments('<sponsorshipAddress> <tokenAmount>')
.parseAsync()
5 changes: 5 additions & 0 deletions packages/cli-tools/bin/streamr-internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,9 @@ program
.command('node-info', 'info about a node')
.command('visualize-topology', 'visualize network topology')
.command('show-sdk-config', 'show config used by internal StreamrClient')
.command('sponsorship-sponsor', 'sponsor a sponsorship')
.command('operator-delegate', 'delegate funds to an operator')
.command('operator-undelegate', 'undelegate funds from an operator')
.command('operator-stake', 'stake operator\'s funds to a sponsorship')
.command('operator-unstake', 'unstake all operator\'s funds from a sponsorship')
.parse()
57 changes: 57 additions & 0 deletions packages/cli-tools/test/internal-operator.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { _operatorContractUtils } from '@streamr/sdk'
import { fetchPrivateKeyWithGas, generateWalletWithGasAndTokens } from '@streamr/test-utils'
import { createTestClient, runCommand } from './utils'
import { parseEther, Wallet } from 'ethers'
import { wait } from '@streamr/utils'

const DELEGATION_AMOUNT = '20000'
const STAKE_AMOUNT = '10000'
const SELF_DELEGATION_AMOUNT = '100000'
const MINIMUM_DELEGATION_SECONDS = 1 // the config value defined in StreamrEnvDeployer in network-contracts repo

describe('operator', () => {

it('happy path', async () => {
const client = createTestClient(await fetchPrivateKeyWithGas())
const stream = await client.createStream('/test')
const sponsorshipContract = await _operatorContractUtils.deploySponsorshipContract({
streamId: stream.id,
deployer: new Wallet(await fetchPrivateKeyWithGas()).connect(_operatorContractUtils.getProvider())
})
const sponsorshipAddress: string = await sponsorshipContract.getAddress()
const operator = await generateWalletWithGasAndTokens()
const operatorContract = await _operatorContractUtils.deployOperatorContract({
deployer: operator
})
await _operatorContractUtils.delegate(operator, await operatorContract.getAddress(), parseEther(SELF_DELEGATION_AMOUNT))
const delegator = await generateWalletWithGasAndTokens()
const operatorAddress: string = await operatorContract.getAddress()

// delegate
await runCommand(`internal operator-delegate ${operatorAddress} ${DELEGATION_AMOUNT}`, {
privateKey: delegator.privateKey
})
expect(await operatorContract.balanceInData(await delegator.getAddress())).toEqual(parseEther(DELEGATION_AMOUNT))

// stake
await runCommand(`internal operator-stake ${operatorAddress} ${sponsorshipAddress} ${STAKE_AMOUNT}`, {
privateKey: operator.privateKey
})
expect(await operatorContract.totalStakedIntoSponsorshipsWei()).toEqual(parseEther(STAKE_AMOUNT))

// unstake
await runCommand(`internal operator-unstake ${operatorAddress} ${sponsorshipAddress}`, {
privateKey: operator.privateKey
})
expect(await operatorContract.totalStakedIntoSponsorshipsWei()).toEqual(0n)

// undelegate
await wait(MINIMUM_DELEGATION_SECONDS)
await runCommand(`internal operator-undelegate ${operatorAddress} ${DELEGATION_AMOUNT}`, {
privateKey: delegator.privateKey
})
expect(await operatorContract.balanceInData(await delegator.getAddress())).toEqual(0n)

await client.destroy()
}, 30 * 1000)
})
28 changes: 28 additions & 0 deletions packages/cli-tools/test/internal-sponsorship-sponsor.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { _operatorContractUtils } from '@streamr/sdk'
import { fetchPrivateKeyWithGas, generateWalletWithGasAndTokens } from '@streamr/test-utils'
import { createTestClient, runCommand } from './utils'
import { parseEther, Wallet } from 'ethers'

const SPONSOR_AMOUNT = '12345'

describe('sponsorship-sponsor', () => {

it('happy path', async () => {
const client = createTestClient(await fetchPrivateKeyWithGas())
const stream = await client.createStream('/test')
const sponsorshipContract = await _operatorContractUtils.deploySponsorshipContract({
streamId: stream.id,
deployer: new Wallet(await fetchPrivateKeyWithGas()).connect(_operatorContractUtils.getProvider())
})

const sponsorer = await generateWalletWithGasAndTokens()
const sponsorshipAddress: string = await sponsorshipContract.getAddress()
await runCommand(`internal sponsorship-sponsor ${sponsorshipAddress} ${SPONSOR_AMOUNT}`, {
privateKey: sponsorer.privateKey
})

const remainingWei = await sponsorshipContract.connect(sponsorer, _operatorContractUtils.getProvider()).remainingWei()
expect(remainingWei).toEqual(parseEther(SPONSOR_AMOUNT))
await client.destroy()
})
})
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Operator } from '@streamr/network-contracts'
import {
ProxyDirection,
SignerWithProvider,
StreamPermission,
_operatorContractUtils
} from '@streamr/sdk'
Expand All @@ -27,7 +28,7 @@ describe('OperatorPlugin', () => {
let broker: Broker
let brokerWallet: Wallet
let operatorContract: Operator
let operatorWallet: Wallet
let operatorWallet: Wallet & SignerWithProvider

beforeAll(async () => {
const deployment = (await setupOperatorContract({
Expand Down
10 changes: 5 additions & 5 deletions packages/node/test/smoke/profit.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,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 { _operatorContractUtils, SignerWithProvider } from '@streamr/sdk'
import { fetchPrivateKeyWithGas, generateWalletWithGasAndTokens } from '@streamr/test-utils'
import { multiplyWeiAmount, until, WeiAmount } from '@streamr/utils'
import { Contract, Wallet, parseEther } from 'ethers'
Expand Down Expand Up @@ -66,10 +66,10 @@ const PROFIT_INACCURACY = parseEther('50')

describe('profit', () => {

let operatorWallet: Wallet
let delegatorWallet: Wallet
let sponsorWallet: Wallet
let operatorNodeWallet: Wallet
let operatorWallet: Wallet & SignerWithProvider
let delegatorWallet: Wallet & SignerWithProvider
let sponsorWallet: Wallet & SignerWithProvider
let operatorNodeWallet: Wallet & SignerWithProvider
let operatorContract: Operator
let sponsorshipContract: Sponsorship

Expand Down
43 changes: 35 additions & 8 deletions packages/sdk/src/contracts/operatorContractUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export interface SetupOperatorContractOpts {
* @hidden
*/
export interface SetupOperatorContractReturnType {
operatorWallet: Wallet
operatorWallet: Wallet & SignerWithProvider
operatorContract: OperatorContract
nodeWallets: (Wallet & SignerWithProvider)[]
}
Expand Down Expand Up @@ -161,36 +161,63 @@ export const getTestAdminWallet = (adminKey?: string, provider?: Provider): Wall
return new Wallet(adminKey ?? TEST_CHAIN_CONFIG.adminPrivateKey).connect(provider ?? getProvider())
}

export const delegate = async (delegator: Wallet, operatorContractAddress: string, amount: WeiAmount, token?: DATATokenContract): Promise<void> => {
export const delegate = async (
delegator: SignerWithProvider,
operatorContractAddress: string,
amount: WeiAmount,
token?: DATATokenContract
): Promise<void> => {
logger.debug('Delegate', { amount: amount.toString() })
// onTokenTransfer: the tokens are delegated on behalf of the given data address
// eslint-disable-next-line max-len
// https://github.com/streamr-dev/network-contracts/blob/01ec980cfe576e25e8c9acc08a57e1e4769f3e10/packages/network-contracts/contracts/OperatorTokenomics/Operator.sol#L233
await transferTokens(delegator, operatorContractAddress, amount, delegator.address, token)
await transferTokens(delegator, operatorContractAddress, amount, await delegator.getAddress(), token)
}

export const undelegate = async (delegator: Wallet, operatorContract: OperatorContract, amount: WeiAmount): Promise<void> => {
export const undelegate = async (
delegator: SignerWithProvider,
operatorContract: OperatorContract,
amount: WeiAmount
): Promise<void> => {
await (await operatorContract.connect(delegator).undelegate(amount)).wait()
}

export const stake = async (operatorContract: OperatorContract, sponsorshipContractAddress: string, amount: WeiAmount): Promise<void> => {
export const stake = async (
operatorContract: OperatorContract,
sponsorshipContractAddress: string,
amount: WeiAmount
): Promise<void> => {
logger.debug('Stake', { amount: amount.toString() })
await (await operatorContract.stake(sponsorshipContractAddress, amount)).wait()
}

export const unstake = async (operatorContract: OperatorContract, sponsorshipContractAddress: string): Promise<void> => {
export const unstake = async (
operatorContract: OperatorContract,
sponsorshipContractAddress: string
): Promise<void> => {
logger.debug('Unstake')
await (await operatorContract.unstake(sponsorshipContractAddress)).wait()
}

export const sponsor = async (sponsorer: Wallet, sponsorshipContractAddress: string, amount: WeiAmount, token?: DATATokenContract): Promise<void> => {
export const sponsor = async (
sponsorer: SignerWithProvider,
sponsorshipContractAddress: string,
amount: WeiAmount,
token?: DATATokenContract
): Promise<void> => {
logger.debug('Sponsor', { amount: amount.toString() })
// eslint-disable-next-line max-len
// https://github.com/streamr-dev/network-contracts/blob/01ec980cfe576e25e8c9acc08a57e1e4769f3e10/packages/network-contracts/contracts/OperatorTokenomics/Sponsorship.sol#L139
await transferTokens(sponsorer, sponsorshipContractAddress, amount, undefined, token)
}

export const transferTokens = async (from: Wallet, to: string, amount: WeiAmount, data?: string, token?: DATATokenContract): Promise<void> => {
export const transferTokens = async (
from: SignerWithProvider,
to: string,
amount: WeiAmount,
data?: string,
token?: DATATokenContract
): Promise<void> => {
const tx = await ((token ?? getTestTokenContract()).connect(from).transferAndCall(to, amount, data ?? '0x'))
await tx.wait()
}
Expand Down
Loading