Skip to content
This repository was archived by the owner on Dec 21, 2021. It is now read-only.

Commit f4567bb

Browse files
committed
Merge branch 'master' into ETH-81-expose-signature-transport
2 parents a502204 + 72ab8b8 commit f4567bb

File tree

11 files changed

+196
-65
lines changed

11 files changed

+196
-65
lines changed

.github/workflows/test-build.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ jobs:
9595
- name: Start Streamr Docker Stack
9696
uses: streamr-dev/streamr-docker-dev-action@v1.0.0-alpha.3
9797
with:
98-
services-to-start: "mysql redis engine-and-editor cassandra parity-node0 parity-sidechain-node0 bridge broker-node-storage-1 nginx smtp"
98+
services-to-start: "mysql redis engine-and-editor cassandra parity-node0 parity-sidechain-node0 bridge broker-node-no-storage-1 broker-node-no-storage-2 broker-node-storage-1 nginx smtp"
9999

100100
- uses: nick-invision/retry@v2
101101
name: Run Test
@@ -125,7 +125,7 @@ jobs:
125125
- name: Start Streamr Docker Stack
126126
uses: streamr-dev/streamr-docker-dev-action@v1.0.0-alpha.3
127127
with:
128-
services-to-start: "mysql redis engine-and-editor cassandra parity-node0 parity-sidechain-node0 bridge broker-node-storage-1 nginx smtp"
128+
services-to-start: "mysql redis engine-and-editor cassandra parity-node0 parity-sidechain-node0 bridge broker-node-no-storage-1 broker-node-no-storage-2 broker-node-storage-1 nginx smtp"
129129
- name: npm ci
130130
run: npm ci
131131
- name: benchmarks
@@ -172,7 +172,7 @@ jobs:
172172
- name: Start Streamr Docker Stack
173173
uses: streamr-dev/streamr-docker-dev-action@v1.0.0-alpha.3
174174
with:
175-
services-to-start: "mysql redis engine-and-editor cassandra parity-node0 parity-sidechain-node0 bridge broker-node-storage-1 nginx smtp"
175+
services-to-start: "mysql redis engine-and-editor cassandra parity-node0 parity-sidechain-node0 bridge broker-node-no-storage-1 broker-node-no-storage-2 broker-node-storage-1 nginx smtp"
176176
- name: npm ci
177177
run: npm ci
178178
- name: npm link

.github/workflows/test-code.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ jobs:
109109
- name: Start Streamr Docker Stack
110110
uses: streamr-dev/streamr-docker-dev-action@v1.0.0-alpha.3
111111
with:
112-
services-to-start: "mysql redis engine-and-editor cassandra parity-node0 parity-sidechain-node0 bridge broker-node-storage-1 nginx smtp"
112+
services-to-start: "mysql redis engine-and-editor cassandra parity-node0 parity-sidechain-node0 bridge broker-node-no-storage-1 broker-node-no-storage-2 broker-node-storage-1 nginx smtp"
113113
- name: Run Test
114114
run: npm run $TEST_NAME
115115

@@ -131,7 +131,7 @@ jobs:
131131
- name: Start Streamr Docker Stack
132132
uses: streamr-dev/streamr-docker-dev-action@v1.0.0-alpha.3
133133
with:
134-
services-to-start: "mysql redis engine-and-editor cassandra parity-node0 parity-sidechain-node0 bridge broker-node-storage-1 nginx smtp"
134+
services-to-start: "mysql redis engine-and-editor cassandra parity-node0 parity-sidechain-node0 bridge broker-node-no-storage-1 broker-node-no-storage-2 broker-node-storage-1 nginx smtp"
135135
- uses: nick-invision/retry@v2
136136
name: Run Test
137137
with:

src/Session.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export default class Session extends EventEmitter {
6868
this.options.unauthenticated = true
6969
}
7070
this.loginFunction = async () => {
71-
throw new Error('Need either "privateKey", "ethereum", "apiKey", "username"+"password" or "sessionToken" to login.')
71+
throw new Error('Need either "privateKey", "ethereum" or "sessionToken" to login.')
7272
}
7373
}
7474
}

src/dataunion/DataUnion.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,21 @@ export class DataUnion {
492492
return tx.wait()
493493
}
494494

495+
/**
496+
* Transfer amount to specific member in DataunionSidechain
497+
* @param memberAddress - the other member who gets their tokens out of the Data Union
498+
* @param amountTokenWei - the amount that want to add to the member
499+
* @returns receipt once transfer transaction is confirmed
500+
*/
501+
async transferToMemberInContract(
502+
memberAddress: EthereumAddress,
503+
amountTokenWei: BigNumber|number|string
504+
): Promise<TransactionResponse> {
505+
const address = getAddress(memberAddress) // throws if bad address
506+
const duSidechain = await this.getContracts().getSidechainContract(this.contractAddress)
507+
return duSidechain.transferToMemberInContract(address, amountTokenWei)
508+
}
509+
495510
/**
496511
* Create a new DataUnionMainnet contract to mainnet with DataUnionFactoryMainnet
497512
* This triggers DataUnionSidechain contract creation in sidechain, over the bridge (AMB)

src/dataunion/abi.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,15 @@ export const dataUnionSidechainABI = [{
125125
],
126126
anonymous: false,
127127
type: 'event'
128+
}, {
129+
name: 'transferToMemberInContract',
130+
inputs: [
131+
{ name: 'recipient', type: 'address', internalType: 'address' },
132+
{ name: 'amount', type: 'uint256', internalType: 'uint256' }
133+
],
134+
outputs: [],
135+
stateMutability: 'nonpayable',
136+
type: 'function'
128137
}]
129138

130139
// Only the part of ABI that is needed by deployment (and address resolution)

src/rest/LoginEndpoints.ts

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -77,38 +77,17 @@ export class LoginEndpoints {
7777
}
7878

7979
/** @internal */
80-
async loginWithApiKey(apiKey: string) {
81-
this.client.debug('loginWithApiKey %o', {
82-
apiKey,
83-
})
84-
const url = getEndpointUrl(this.client.options.restUrl, 'login', 'apikey')
85-
const props = {
86-
apiKey,
87-
}
88-
return getSessionToken(url, props)
80+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, class-methods-use-this
81+
async loginWithApiKey(_apiKey: string): Promise<any> {
82+
const message = 'apiKey auth is no longer supported. Please create an ethereum identity.'
83+
throw new AuthFetchError(message)
8984
}
9085

9186
/** @internal */
92-
async loginWithUsernamePassword(username: string, password: string) {
93-
this.client.debug('loginWithUsernamePassword %o', {
94-
username,
95-
})
96-
const url = getEndpointUrl(this.client.options.restUrl, 'login', 'password')
97-
const props = {
98-
username,
99-
password,
100-
}
101-
try {
102-
return await getSessionToken(url, props)
103-
} catch (err) {
104-
if (err && err.response && err.response.status === 404) {
105-
// this 404s if running against new backend with username/password support removed
106-
// wrap with appropriate error message
107-
const message = 'username/password auth is no longer supported. Please create an ethereum identity.'
108-
throw new AuthFetchError(message, err.response, err.body)
109-
}
110-
throw err
111-
}
87+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, class-methods-use-this
88+
async loginWithUsernamePassword(_username: string, _password: string): Promise<any> {
89+
const message = 'username/password auth is no longer supported. Please create an ethereum identity.'
90+
throw new AuthFetchError(message)
11291
}
11392

11493
async getUserInfo() {

src/user/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ async function getUsername(client: StreamrClient) {
1313
return (
1414
username
1515
// edge case: if auth.apiKey is an anonymous key, userInfo.id is that anonymous key
16+
// update: not sure if still needed now that apiKey auth has been disabled
1617
|| id
1718
)
1819
}
@@ -48,5 +49,5 @@ export async function getUserId(client: StreamrClient) {
4849
return sha256(hexString)
4950
}
5051

51-
throw new Error('Need either "privateKey", "ethereum", "apiKey", "username"+"password" or "sessionToken" to derive the publisher Id.')
52+
throw new Error('Need either "privateKey", "ethereum" or "sessionToken" to derive the publisher Id.')
5253
}

test/integration/LoginEndpoints.test.ts

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ import { ethers } from 'ethers'
55
import { StreamrClient } from '../../src/StreamrClient'
66

77
import config from './config'
8+
import { fakePrivateKey } from '../utils'
89

910
describe('LoginEndpoints', () => {
1011
let client: StreamrClient
1112

1213
const createClient = (opts = {}) => new StreamrClient({
1314
...config.clientOptions,
1415
auth: {
15-
apiKey: 'tester1-api-key',
16+
privateKey: fakePrivateKey()
1617
},
1718
autoConnect: false,
1819
autoDisconnect: false,
@@ -73,19 +74,11 @@ describe('LoginEndpoints', () => {
7374
})
7475

7576
describe('API key login', () => {
76-
it('should fail to get a session token', async () => {
77+
it('should fail', async () => {
7778
await expect(async () => {
7879
await client.loginWithApiKey('apikey')
7980
}).rejects.toThrow()
8081
})
81-
82-
it('should get a session token', async () => {
83-
const sessionToken = await client.loginWithApiKey('tester1-api-key')
84-
assert(sessionToken)
85-
assert(sessionToken.token)
86-
// @ts-expect-error
87-
assert(sessionToken.expires)
88-
})
8982
})
9083

9184
describe('Username/password login', () => {

test/integration/Session.test.ts

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,13 @@ describe('Session', () => {
1212
})
1313

1414
describe('Token retrievals', () => {
15-
it('gets the token using api key', async () => {
15+
it('fails if trying to use apiKey', async () => {
1616
expect.assertions(1)
17-
await expect(createClient({
17+
await expect(() => createClient({
1818
auth: {
1919
apiKey: 'tester1-api-key',
2020
},
21-
}).session.getSessionToken()).resolves.toBeTruthy()
22-
})
23-
24-
it('fails when the used api key is invalid', async () => {
25-
expect.assertions(1)
26-
await expect(createClient({
27-
auth: {
28-
apiKey: 'wrong-api-key',
29-
},
30-
}).session.getSessionToken()).rejects.toMatchObject({
31-
body: expect.stringMatching(/invalid api key/i),
32-
})
21+
}).session.getSessionToken()).rejects.toThrow('no longer supported')
3322
})
3423

3524
it('gets the token using private key', async () => {
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import { BigNumber, Contract, providers, Wallet } from 'ethers'
2+
import { parseEther } from 'ethers/lib/utils'
3+
import debug from 'debug'
4+
import * as Token from '../../../contracts/TestToken.json'
5+
import config from '../config'
6+
import { getEndpointUrl, until } from '../../../src/utils'
7+
import { MemberStatus } from '../../../src/dataunion/DataUnion'
8+
import { StreamrClient } from '../../../src/StreamrClient'
9+
import { EthereumAddress } from '../../../src/types'
10+
import authFetch from '../../../src/rest/authFetch'
11+
12+
const log = debug('StreamrClient::DataUnion::integration-test-transfer')
13+
14+
const providerSidechain = new providers.JsonRpcProvider(config.clientOptions.sidechain)
15+
const providerMainnet = new providers.JsonRpcProvider(config.clientOptions.mainnet)
16+
17+
const tokenAdminWallet = new Wallet(config.tokenAdminPrivateKey, providerMainnet)
18+
const tokenMainnet = new Contract(config.clientOptions.tokenAddress, Token.abi, tokenAdminWallet)
19+
20+
const adminWalletSidechain = new Wallet(config.clientOptions.auth.privateKey, providerSidechain)
21+
const tokenSidechain = new Contract(config.clientOptions.tokenSidechainAddress, Token.abi, adminWalletSidechain)
22+
23+
const sendTokensToSidechain = async (receiverAddress: EthereumAddress, amount: BigNumber) => {
24+
const relayTokensAbi = [
25+
{
26+
inputs: [
27+
{
28+
internalType: 'address',
29+
name: 'token',
30+
type: 'address'
31+
},
32+
{
33+
internalType: 'address',
34+
name: '_receiver',
35+
type: 'address'
36+
},
37+
{
38+
internalType: 'uint256',
39+
name: '_value',
40+
type: 'uint256'
41+
},
42+
{
43+
internalType: 'bytes',
44+
name: '_data',
45+
type: 'bytes'
46+
}
47+
],
48+
name: 'relayTokensAndCall',
49+
outputs: [],
50+
stateMutability: 'nonpayable',
51+
type: 'function'
52+
}
53+
]
54+
const tokenMediator = new Contract(config.tokenMediator, relayTokensAbi, tokenAdminWallet)
55+
const tx1 = await tokenMainnet.approve(tokenMediator.address, amount)
56+
await tx1.wait()
57+
log('Approved')
58+
const tx2 = await tokenMediator.relayTokensAndCall(tokenMainnet.address, receiverAddress, amount, '0x1234') // dummy 0x1234
59+
await tx2.wait()
60+
log('Relayed tokens')
61+
await until(async () => !(await tokenSidechain.balanceOf(receiverAddress)).eq('0'), 300000, 3000)
62+
log('Sidechain balance changed')
63+
}
64+
65+
describe('DataUnion transfer within contract', () => {
66+
let adminClient: StreamrClient
67+
68+
beforeAll(async () => {
69+
log(`Connecting to Ethereum networks, config = ${JSON.stringify(config)}`)
70+
const network = await providerMainnet.getNetwork()
71+
log('Connected to "mainnet" network: ', JSON.stringify(network))
72+
const network2 = await providerSidechain.getNetwork()
73+
log('Connected to sidechain network: ', JSON.stringify(network2))
74+
log(`Minting 100 tokens to ${tokenAdminWallet.address}`)
75+
const tx1 = await tokenMainnet.mint(tokenAdminWallet.address, parseEther('100'))
76+
await tx1.wait()
77+
78+
await sendTokensToSidechain(adminWalletSidechain.address, parseEther('10'))
79+
80+
adminClient = new StreamrClient(config.clientOptions as any)
81+
}, 150000)
82+
83+
afterAll(() => {
84+
providerMainnet.removeAllListeners()
85+
providerSidechain.removeAllListeners()
86+
})
87+
88+
it('transfer token to member', async () => {
89+
const dataUnion = await adminClient.deployDataUnion()
90+
const secret = await dataUnion.createSecret('test secret')
91+
// eslint-disable-next-line no-underscore-dangle
92+
const contract = await dataUnion._getContract()
93+
log(`DU owner: ${await dataUnion.getAdminAddress()}`)
94+
log(`Sending tx from ${await adminClient.getAddress()}`)
95+
96+
// product is needed for join requests to analyze the DU version
97+
const createProductUrl = getEndpointUrl(config.clientOptions.restUrl, 'products')
98+
await authFetch(createProductUrl, adminClient.session, {
99+
method: 'POST',
100+
body: JSON.stringify({
101+
beneficiaryAddress: dataUnion.getAddress(),
102+
type: 'DATAUNION',
103+
dataUnionVersion: 2
104+
})
105+
})
106+
107+
const memberWallet = new Wallet(`0x100000000000000000000000000000000000000012300000001${Date.now()}`, providerSidechain)
108+
const memberClient = new StreamrClient({
109+
...config.clientOptions,
110+
auth: {
111+
privateKey: memberWallet.privateKey
112+
}
113+
} as any)
114+
const res = await memberClient.getDataUnion(dataUnion.getAddress()).join(secret)
115+
log(`Member joined data union: ${JSON.stringify(res)}`)
116+
log(`DU member count: ${await contract.sidechain.activeMemberCount()}`)
117+
118+
const stats = await memberClient.getDataUnion(dataUnion.getAddress()).getMemberStats(memberWallet.address)
119+
log(`Stats: ${JSON.stringify(stats)}`)
120+
121+
const approve = await tokenSidechain.approve(dataUnion.getSidechainAddress(), parseEther('1'))
122+
await approve.wait()
123+
log(`Approve DU ${dataUnion.getSidechainAddress()} to access 1 token from ${adminWalletSidechain.address}`)
124+
125+
const tx = await dataUnion.transferToMemberInContract(memberWallet.address, parseEther('1'))
126+
await tx.wait()
127+
log(`Transfer 1 token with transferWithinContract to ${memberWallet.address}`)
128+
129+
const newStats = await memberClient.getDataUnion(dataUnion.getAddress()).getMemberStats(memberWallet.address)
130+
log(`Stats: ${JSON.stringify(newStats)}`)
131+
132+
expect(stats).toMatchObject({
133+
status: MemberStatus.ACTIVE,
134+
earningsBeforeLastJoin: BigNumber.from(0),
135+
totalEarnings: BigNumber.from(0),
136+
withdrawableEarnings: BigNumber.from(0)
137+
})
138+
expect(newStats).toMatchObject({
139+
status: MemberStatus.ACTIVE,
140+
earningsBeforeLastJoin: parseEther('1'),
141+
totalEarnings: parseEther('1'),
142+
withdrawableEarnings: parseEther('1')
143+
})
144+
}, 150000)
145+
})

0 commit comments

Comments
 (0)