Update signer-noncemanager.ts

This commit is contained in:
KunalOfficial 2023-10-06 13:29:23 +05:30 committed by GitHub
parent b10f19be4a
commit 18e29429b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -5,10 +5,11 @@ import type {
BlockTag, Provider, TransactionRequest, TransactionResponse
} from "./provider.js";
import type { Signer } from "./signer.js";
/**
* A **NonceManager** wraps another [[Signer]] and automatically manages
* the nonce, ensuring serialized and sequential nonces are used during
* transaction.
* transactions.
*/
export class NonceManager extends AbstractSigner {
/**
@ -17,8 +18,11 @@ export class NonceManager extends AbstractSigner {
private signer: Signer;
private redis: Redis.Redis;
private delta: number;
/**
* Creates a new **NonceManager** to manage %%signer%%.
* Creates a new **NonceManager** to manage the specified `signer`.
* @param signer The Signer to be managed.
* @param redisUrl The Redis connection URL.
*/
constructor(signer: Signer, redisUrl: string) {
super(signer.provider);
@ -27,17 +31,35 @@ export class NonceManager extends AbstractSigner {
this.delta = 0;
}
/**
* Get the address of the signer.
* @returns The address of the signer.
*/
async getAddress(): Promise<string> {
return this.signer.getAddress();
}
/**
* Connect the NonceManager to a new provider.
* @param provider The provider to connect to.
* @param redisUrl The Redis connection URL.
* @returns A new NonceManager instance with the updated provider.
*/
connect(provider: null | Provider, redisUrl: string): NonceManager {
return new NonceManager(this.signer.connect(provider), redisUrl);
}
/**
* Get the nonce for the signer.
* @param blockTag The block tag to specify the block from which to fetch the nonce.
* @returns The nonce value.
*/
async getNonce(blockTag?: BlockTag): Promise<number> {
const signerAddress = await this.signer.getAddress(); // Get the signer's address
const nonceKey = `nonce:${signerAddress}`; // Use signer's address as part of the key
if (blockTag === "pending") {
const cachedNonce = await this.redis.get('cached-nonce'); // Retrieve the cached nonce from Redis
const cachedNonce = await this.redis.get(nonceKey); // Retrieve the cached nonce from Redis
if (cachedNonce !== null) {
return parseInt(cachedNonce) + this.delta;
@ -45,29 +67,44 @@ export class NonceManager extends AbstractSigner {
// If nonce is not cached, fetch it from the provider
const nonce = await super.getNonce("pending");
await this.redis.set('cached-nonce', nonce.toString()); // Cache the nonce in Redis
await this.redis.set(nonceKey, nonce.toString()); // Cache the nonce in Redis
return nonce + this.delta;
}
return super.getNonce(blockTag);
}
/**
* Manually increment the nonce. This may be useful when managng
* Manually increment the nonce. This may be useful when managing
* offline transactions.
*/
increment(): void {
this.delta++;
}
/**
* Manually decrement the nonce. Useful for rolling back failed transactions.
*/
decrement(): void {
this.delta--;
}
/**
* Resets the nonce, causing the NonceManager to reload the current nonce
* from the blockchain on the next transaction.
*/
reset(): void {
this.delta = 0;
this.redis.del('cached-nonce'); // Clear the cached nonce in Redis
const signerAddress = this.signer.getAddress(); // Get the signer's address
const nonceKey = `nonce:${signerAddress}`; // Use signer's address as part of the key
this.redis.del(nonceKey); // Clear the cached nonce in Redis
}
/**
* Send a transaction using the managed signer.
* @param tx The transaction request.
* @returns The transaction response.
*/
async sendTransaction(tx: TransactionRequest): Promise<TransactionResponse> {
const nonce = await this.getNonce("pending");
this.increment();
@ -95,14 +132,31 @@ export class NonceManager extends AbstractSigner {
}
}
/**
* Sign a transaction using the managed signer.
* @param tx The transaction request.
* @returns The transaction signature.
*/
async signTransaction(tx: TransactionRequest): Promise<string> {
return this.signer.signTransaction(tx);
}
/**
* Sign a message using the managed signer.
* @param message The message to sign.
* @returns The message signature.
*/
async signMessage(message: string | Uint8Array): Promise<string> {
return this.signer.signMessage(message);
}
/**
* Sign typed data using the managed signer.
* @param domain The typed data domain.
* @param types The typed data types.
* @param value The typed data value.
* @returns The typed data signature.
*/
async signTypedData(domain: TypedDataDomain, types: Record<string, Array<TypedDataField>>, value: Record<string, any>): Promise<string> {
return this.signer.signTypedData(domain, types, value);
}