Skip to content

Commit

Permalink
Preserve contract prototypes when extending, add cache property to …
Browse files Browse the repository at this point in the history
…cached contracts (#42)

* Add clarifying comment

* Add cache propoerty to cached contract

* Preserve prototypes when extending

* Add changeset

* typo
  • Loading branch information
ryangoree authored Feb 22, 2024
1 parent 23ae786 commit eb6575b
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 12 deletions.
5 changes: 5 additions & 0 deletions .changeset/lazy-scissors-teach.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@delvtech/evm-client": patch
---

Added a `cache` property to the `CachedReadContract` type and ensured the factories preserve the prototypes of the contract's they're given.
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,16 @@ export function createCachedReadContract<TAbi extends Abi = Abi>({
cache = createLruSimpleCache({ max: DEFAULT_CACHE_SIZE }),
namespace,
}: CreateCachedReadContractOptions<TAbi>): CachedReadContract<TAbi> {
return {
...contract,
// Because this is part of the public API, we won't know if the original
// contract is a plain object or a class instance, so we use Object.create to
// preserve the original contract's prototype chain when extending, ensuring
// the new contract includes all the original contract's methods and
// instanceof checks will still work.
const contractPrototype = Object.getPrototypeOf(contract);
const newContract = Object.create(contractPrototype);

const overrides: Partial<CachedReadContract<TAbi>> = {
cache,

/**
* Reads data from the contract. First checks the cache, and if not present,
Expand Down Expand Up @@ -111,6 +119,8 @@ export function createCachedReadContract<TAbi extends Abi = Abi>({
cache.clear();
},
};

return Object.assign(newContract, contract, overrides);
}

async function getOrSet<TValue>({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { ReadWriteContract } from 'src/contract/types/Contract';

export interface CreateCachedReadWriteContractOptions<TAbi extends Abi = Abi>
extends CreateCachedReadContractOptions<TAbi> {
contract: ReadWriteContract<TAbi> | CachedReadWriteContract<TAbi>;
contract: ReadWriteContract<TAbi>;
}

/**
Expand All @@ -22,18 +22,25 @@ export function createCachedReadWriteContract<TAbi extends Abi = Abi>({
cache,
namespace,
}: CreateCachedReadWriteContractOptions<TAbi>): CachedReadWriteContract<TAbi> {
const cachedReadContract = isCached(contract)
? contract
: createCachedReadContract({ contract, cache, namespace });

return {
...contract,
...cachedReadContract,
};
// Avoid double-caching if given a contract that already has a cache.
if (isCached(contract)) {
return contract;
}
// Because this is part of the public API, we won't know if the original
// contract is a plain object or a class instance, so we use Object.create to
// preserve the original contract's prototype chain when extending, ensuring
// the new contract includes all the original contract's methods and
// instanceof checks will still work.
const contractPrototype = Object.getPrototypeOf(contract);
const newContract = Object.create(contractPrototype);
return Object.assign(
newContract,
createCachedReadContract({ contract, cache, namespace }),
);
}

function isCached<TAbi extends Abi>(
contract: ReadWriteContract<TAbi> | CachedReadWriteContract<TAbi>,
contract: ReadWriteContract<TAbi>,
): contract is CachedReadWriteContract<TAbi> {
return 'clearCache' in contract;
}
2 changes: 2 additions & 0 deletions packages/evm-client/src/contract/types/CachedContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import {
ReadWriteContract,
} from 'src/contract/types/Contract';
import { FunctionName } from 'src/contract/types/Function';
import { SimpleCache } from 'src/exports';

export interface CachedReadContract<TAbi extends Abi = Abi>
extends ReadContract<TAbi> {
cache: SimpleCache;
namespace?: string;
clearCache(): void;
deleteRead<TFunctionName extends FunctionName<TAbi>>(
Expand Down

0 comments on commit eb6575b

Please sign in to comment.