Skip to content

Commit bf78d4d

Browse files
authored
Merge pull request #376 from trustlines-protocol/feature/nonce-mechanism-option
Extend configuration to set nonce mechanism
2 parents 5e9c2fe + 7a390f3 commit bf78d4d

File tree

6 files changed

+98
-26
lines changed

6 files changed

+98
-26
lines changed

CHANGELOG.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
99
### Changed
1010

1111
- Use `feeRecipient` as given by the provider instead of zeroAddress for meta-tx
12+
- Use random none generation at the identity wallet for meta transactions
1213

1314
### Added
1415

@@ -17,13 +18,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
1718
where the fee payer is the loaded user
1819
- Add `extraData` to `TransferDetails`, it contains the raw `extraData` that was present in the transfer
1920
for which details are returned
20-
- Add `paymentRequestId` and `transferId` to `TransferDetails` corresponding to the decoded `extraData`
21-
- Add option to `Payment.preparePayment` function `options.addTransferId: boolean = true` that signals whether
22-
a `transferId` should be generated and added to the payment's extraData.
23-
- Add `transferId` to the returned values of `Payment.preparePayment`
21+
- Add `paymentRequestId` and `messageId` to `TransferDetails` corresponding to the decoded `extraData`
22+
- Add option to `Payment.preparePayment` function `options.addMessageId: boolean = true` that signals whether
23+
a messageId should be generated and added to the payment's extraData.
24+
- Add `messageId` to the returned values of `Payment.preparePayment`
2425
- Add function `Payment.confirmPayment` to confirm any `PaymentTxObject` returned by `prepare`
2526
and potentially send a payment message along with the payment
26-
- Add function `Messaging.paymentMessage` to send a payment message for a `transferId` to a counterparty address
27+
- Add function `Messaging.paymentMessage` to send a payment message for a messageId to a counterparty address
28+
- Add optional field to the `TLNetworkConfig` for the nonce mechanism to use
2729

2830
### Deprecated
2931

src/TLNetwork.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {
2727

2828
import utils from './utils'
2929

30-
import { ProviderUrl, TLNetworkConfig } from './typings'
30+
import { NonceMechanism, ProviderUrl, TLNetworkConfig } from './typings'
3131
import { IdentityWallet } from './wallets/IdentityWallet'
3232

3333
/**
@@ -141,7 +141,8 @@ export class TLNetwork {
141141
identityFactoryAddress,
142142
identityImplementationAddress,
143143
walletType = WALLET_TYPE_ETHERS,
144-
chainId
144+
chainId,
145+
nonceMechanism = NonceMechanism.Random
145146
} = config
146147

147148
const defaultUrlParameters: ProviderUrl = {
@@ -162,10 +163,14 @@ export class TLNetwork {
162163
)
163164
)
164165

165-
this.setWallet(walletType, this.relayProvider, chainId, {
166+
this.setWallet(
167+
walletType,
168+
this.relayProvider,
169+
chainId,
166170
identityFactoryAddress,
167-
identityImplementationAddress
168-
})
171+
identityImplementationAddress,
172+
nonceMechanism
173+
)
169174
this.setSigner(web3Provider, this.wallet)
170175

171176
this.currencyNetwork = new CurrencyNetwork(this.relayProvider)
@@ -264,15 +269,20 @@ export class TLNetwork {
264269
walletType: string,
265270
provider: TLProvider,
266271
chainId: number,
267-
{ identityFactoryAddress, identityImplementationAddress }
272+
identityFactoryAddress: string,
273+
identityImplementationAddress: string,
274+
nonceMechanism: NonceMechanism
268275
): void {
269276
let wallet: TLWallet
270277

271278
if (walletType === WALLET_TYPE_IDENTITY) {
272-
wallet = new IdentityWallet(provider, chainId, {
279+
wallet = new IdentityWallet(
280+
provider,
281+
chainId,
273282
identityFactoryAddress,
274-
identityImplementationAddress
275-
})
283+
identityImplementationAddress,
284+
nonceMechanism
285+
)
276286
} else if (walletType === WALLET_TYPE_ETHERS) {
277287
wallet = new EthersWallet(provider)
278288
} else {

src/typings.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ export interface TLNetworkConfig {
3333
* Chain id used in the signature of meta-tx
3434
*/
3535
chainId?: number
36+
/**
37+
* Mechanism how to generate nonces for identity meta-tx
38+
*/
39+
nonceMechanism?: NonceMechanism
3640
}
3741

3842
export interface ProviderUrl {
@@ -586,6 +590,11 @@ export interface IdentityWalletData extends TLWalletData {
586590
meta: TLWalletDataMeta
587591
}
588592

593+
export enum NonceMechanism {
594+
Random = 'random',
595+
Counting = 'counting'
596+
}
597+
589598
// TRUSTLINE
590599
export interface TrustlineObject {
591600
id: string

src/wallets/IdentityWallet.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
IdentityWalletData,
1717
MetaTransaction,
1818
MetaTransactionFees,
19+
NonceMechanism,
1920
RawTxObject,
2021
Signature,
2122
TransactionStatusObject,
@@ -43,16 +44,20 @@ export class IdentityWallet implements TLWallet {
4344
private identityAddress: string
4445
private identityFactoryAddress: string
4546
private identityImplementationAddress: string
47+
private nonceMechanism: NonceMechanism
4648
private chainId: number
4749
private identityVersion = 1
4850

4951
constructor(
5052
provider: TLProvider,
5153
chainId: number,
52-
{ identityFactoryAddress, identityImplementationAddress }
54+
identityFactoryAddress: string,
55+
identityImplementationAddress: string,
56+
nonceMechanism: NonceMechanism
5357
) {
5458
this.identityFactoryAddress = identityFactoryAddress
5559
this.identityImplementationAddress = identityImplementationAddress
60+
this.nonceMechanism = nonceMechanism
5661
this.provider = provider
5762
this.chainId = chainId
5863
}
@@ -337,7 +342,7 @@ export class IdentityWallet implements TLWallet {
337342
}
338343

339344
public async prepareTransaction(rawTx: RawTxObject): Promise<TxObjectRaw> {
340-
rawTx.nonce = getRandomNonce()
345+
rawTx.nonce = await this.getNonce() // Must take place before the fee calculation!
341346

342347
const metaTxFees = await this.getMetaTxFees(rawTx)
343348

@@ -425,6 +430,22 @@ export class IdentityWallet implements TLWallet {
425430
}
426431
}
427432

433+
public async getNonce(): Promise<string> {
434+
switch (this.nonceMechanism) {
435+
case NonceMechanism.Random:
436+
return getRandomNonce()
437+
438+
case NonceMechanism.Counting:
439+
const nonce = await this.provider.getIdentityNonce(this.address)
440+
return nonce.toString()
441+
442+
default:
443+
throw new Error(
444+
`Can not generate nonce for unknown mechanism: ${this.nonceMechanism}`
445+
)
446+
}
447+
}
448+
428449
/**
429450
* Takes a string hash and signs it using the loaded wallet without appending `\x19Ethereum Signed Message:\n` to it
430451
* and hashing it again, contrary to what ethers.sign or ethers.signMessage does.

tests/e2e/Identity.test.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
wait
2020
} from '../Fixtures'
2121

22-
import { FeePayer, RawTxObject } from '../../src/typings'
22+
import { FeePayer, NonceMechanism, RawTxObject } from '../../src/typings'
2323

2424
import { TLNetwork } from '../../src/TLNetwork'
2525

@@ -141,10 +141,9 @@ describe('e2e', () => {
141141
const secondWallet = new IdentityWallet(
142142
relayProvider,
143143
tlNetworkConfigIdentity.chainId,
144-
{
145-
identityFactoryAddress,
146-
identityImplementationAddress
147-
}
144+
identityFactoryAddress,
145+
identityImplementationAddress,
146+
NonceMechanism.Random
148147
)
149148
const walletData = await secondWallet.create()
150149
await secondWallet.loadFrom(walletData)

tests/unit/IdentityWallet.test.ts

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
USER_1_IDENTITY_WALLET_V1
2424
} from '../Fixtures'
2525

26-
import { MetaTransaction } from '../../src/typings'
26+
import { MetaTransaction, NonceMechanism } from '../../src/typings'
2727
import {
2828
calculateIdentityAddress,
2929
getRandomNonce,
@@ -43,10 +43,13 @@ describe('unit', () => {
4343

4444
const init = () => {
4545
fakeTLProvider = new FakeTLProvider()
46-
identityWallet = new IdentityWallet(fakeTLProvider, FAKE_CHAIN_ID, {
47-
identityFactoryAddress: IDENTITY_FACTORY_ADDRESS,
48-
identityImplementationAddress: IDENTITY_IMPLEMENTATION_ADDRESS
49-
})
46+
identityWallet = new IdentityWallet(
47+
fakeTLProvider,
48+
FAKE_CHAIN_ID,
49+
IDENTITY_FACTORY_ADDRESS,
50+
IDENTITY_IMPLEMENTATION_ADDRESS,
51+
NonceMechanism.Random
52+
)
5053
}
5154

5255
describe('#create()', () => {
@@ -230,6 +233,34 @@ describe('unit', () => {
230233
)
231234
})
232235
})
236+
237+
describe('#getNonce', () => {
238+
beforeEach(() => init())
239+
240+
it('should generate nonce with random mechanism', async () => {
241+
const randomIdentityWallet = new IdentityWallet(
242+
fakeTLProvider,
243+
FAKE_CHAIN_ID,
244+
IDENTITY_FACTORY_ADDRESS,
245+
IDENTITY_IMPLEMENTATION_ADDRESS,
246+
NonceMechanism.Random
247+
)
248+
assert.isString(await randomIdentityWallet.getNonce())
249+
})
250+
251+
it('should generate nonce with counting mechanism', async () => {
252+
const countingIdentityWallet = new IdentityWallet(
253+
fakeTLProvider,
254+
FAKE_CHAIN_ID,
255+
IDENTITY_FACTORY_ADDRESS,
256+
IDENTITY_IMPLEMENTATION_ADDRESS,
257+
NonceMechanism.Counting
258+
)
259+
const walletData = await countingIdentityWallet.create()
260+
await countingIdentityWallet.loadFrom(walletData)
261+
assert.isString(await countingIdentityWallet.getNonce())
262+
})
263+
})
233264
})
234265

235266
describe('#getRandomNonce', () => {

0 commit comments

Comments
 (0)