Skip to content

Commit

Permalink
feat: support for timestamp nonce (#255)
Browse files Browse the repository at this point in the history
- account sequence number can soon be replaced by timestamp
- this eliminates the need to to fetch account sequence number from
account as part of tx options
- adding a flag / config param since this isn't completely out yet

testing:
- tested locally / breakpoints that transactions work, and no
unnecessary fetch to account for placing stateful orders
  • Loading branch information
aforaleka authored Sep 26, 2024
1 parent d6db952 commit dcdd233
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 30 deletions.
50 changes: 33 additions & 17 deletions v4-client-js/__native__/__ios__/v4-native-client.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions v4-client-js/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion v4-client-js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@dydxprotocol/v4-client-js",
"version": "1.3.5",
"version": "1.3.6",
"description": "General client library for the new dYdX system (v4 decentralized)",
"main": "build/src/index.js",
"scripts": {
Expand Down
3 changes: 3 additions & 0 deletions v4-client-js/src/clients/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,20 +220,23 @@ export class ValidatorConfig {
public denoms: DenomConfig;
public broadcastOptions?: BroadcastOptions;
public defaultClientMemo?: string;
public useTimestampNonce?: boolean;

constructor(
restEndpoint: string,
chainId: string,
denoms: DenomConfig,
broadcastOptions?: BroadcastOptions,
defaultClientMemo?: string,
useTimestampNonce?: boolean,
) {
this.restEndpoint = restEndpoint?.endsWith('/') ? restEndpoint.slice(0, -1) : restEndpoint;
this.chainId = chainId;

this.denoms = denoms;
this.broadcastOptions = broadcastOptions;
this.defaultClientMemo = defaultClientMemo;
this.useTimestampNonce = useTimestampNonce;
}
}

Expand Down
34 changes: 24 additions & 10 deletions v4-client-js/src/clients/modules/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,10 @@ export class Post {
public readonly defaultGasPrice: GasPrice;
public readonly defaultDydxGasPrice: GasPrice;

public useTimestampNonce: boolean = false;
private accountNumberCache: Map<string, Account> = new Map();

constructor(get: Get, chainId: string, denoms: DenomConfig, defaultClientMemo?: string) {
constructor(get: Get, chainId: string, denoms: DenomConfig, defaultClientMemo?: string, useTimestampNonce?: boolean) {
this.get = get;
this.chainId = chainId;
this.registry = generateRegistry();
Expand All @@ -74,6 +75,7 @@ export class Post {
: denoms.CHAINTOKEN_DENOM
}`,
);
if (useTimestampNonce === true) this.useTimestampNonce = useTimestampNonce;
}

/**
Expand Down Expand Up @@ -113,14 +115,23 @@ export class Post {
memo?: string,
account?: () => Promise<Account>,
): Promise<StdFee> {
const msgsPromise = messaging();
const accountPromise = account ? await account() : this.account(wallet.address!);
const msgsAndAccount = await Promise.all([msgsPromise, accountPromise]);
const msgs = msgsAndAccount[0];
let msgs: EncodeObject[];
// protocol expects timestamp nonce in UTC milliseconds, which is the unit returned by Date.now()
let sequence = Date.now();

if (this.useTimestampNonce) {
msgs = await messaging();
} else {
const msgsPromise = messaging();
const accountPromise = account ? await account() : this.account(wallet.address!);
const msgsAndAccount = await Promise.all([msgsPromise, accountPromise]);
msgs = msgsAndAccount[0];
sequence = msgsAndAccount[1].sequence;
}

return this.simulateTransaction(
wallet.pubKey!,
msgsAndAccount[1].sequence,
sequence,
msgs,
gasPrice,
memo,
Expand Down Expand Up @@ -225,16 +236,18 @@ export class Post {
gasPrice: GasPrice = this.getGasPrice(),
memo?: string,
): Promise<Uint8Array> {
// protocol expects timestamp nonce in UTC milliseconds, which is the unit returned by Date.now()
const sequence = this.useTimestampNonce ? Date.now() : account.sequence;
// Simulate transaction if no fee is specified.
const fee: StdFee = zeroFee
? {
amount: [],
gas: '1000000',
}
: await this.simulateTransaction(wallet.pubKey!, account.sequence, messages, gasPrice, memo);
: await this.simulateTransaction(wallet.pubKey!, sequence, messages, gasPrice, memo);

const txOptions: TransactionOptions = {
sequence: account.sequence,
sequence,
accountNumber: account.accountNumber,
chainId: this.chainId,
};
Expand All @@ -246,11 +259,12 @@ export class Post {
* @description Retrieve an account structure for transactions.
* For short term orders, the sequence doesn't matter. Use cached if available.
* For long term and conditional orders, a round trip to validator must be made.
* when timestamp nonce is supported, no need to fetch account sequence number
*/
public async account(address: string, orderFlags?: OrderFlags): Promise<Account> {
if (orderFlags === OrderFlags.SHORT_TERM) {
if (orderFlags === OrderFlags.SHORT_TERM || this.useTimestampNonce) {
if (this.accountNumberCache.has(address)) {
// For SHORT_TERM orders, the sequence doesn't matter
// If order is SHORT_TERM or if timestamp nonce is enabled, the sequence doesn't matter
return this.accountNumberCache.get(address)!;
}
}
Expand Down
1 change: 1 addition & 0 deletions v4-client-js/src/clients/validator-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export class ValidatorClient {
this.config.chainId,
this.config.denoms,
this.config.defaultClientMemo,
this.config.useTimestampNonce,
);
}
}

0 comments on commit dcdd233

Please sign in to comment.