Add _in_ operator support for contract and contract.filters (#3901).
This commit is contained in:
parent
9060dede49
commit
c58ab3a976
@ -177,6 +177,44 @@ describe("Test Contract", function() {
|
||||
await specificEvent;
|
||||
await allEvents;
|
||||
});
|
||||
|
||||
it("tests the _in_ operator for functions", function() {
|
||||
const contract = new Contract(addr, abi);
|
||||
|
||||
assert.equal("testCallAdd" in contract, true, "has(testCallAdd)");
|
||||
assert.equal("nonExist" in contract, false, "has(nonExist)");
|
||||
|
||||
{
|
||||
const sig = "function testCallAdd(uint256 a, uint256 b) pure returns (uint256 result)";
|
||||
assert.equal(sig in contract, true, `has(${ sig })`);
|
||||
assert.equal("function nonExist()" in contract, false, "has(function nonExist())");
|
||||
}
|
||||
|
||||
assert.equal("0xf24684e5" in contract, true, "has(0xf24684e5)");
|
||||
assert.equal("0xbad01234" in contract, false, "has(0xbad01234)");
|
||||
});
|
||||
|
||||
it("tests the _in_ operator for events", function() {
|
||||
const contract = new Contract(addr, abi);
|
||||
|
||||
assert.equal("EventUint256" in contract.filters, true, "has(EventUint256)");
|
||||
assert.equal("NonExist" in contract.filters, false, "has(NonExist)");
|
||||
|
||||
{
|
||||
const sig = "event EventUint256(uint256 indexed value)";
|
||||
assert.equal(sig in contract.filters, true, `has(${ sig })`);
|
||||
assert.equal("event NonExist()" in contract.filters, false, "has(event NonExist())");
|
||||
}
|
||||
|
||||
{
|
||||
const hash = "0x85c55bbb820e6d71c71f4894e57751de334b38c421f9c170b0e66d32eafea337";
|
||||
const badHash = "0xbad01234567890ffbad01234567890ffbad01234567890ffbad01234567890ff";
|
||||
assert.equal(hash in contract.filters, true, `has(${ hash })`);
|
||||
assert.equal(badHash in contract.filters, false, `has(${ badHash })`);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("Test Typed Contract Interaction", function() {
|
||||
@ -464,3 +502,4 @@ describe("Test Contract Fallback", function() {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -417,6 +417,17 @@ export class Interface {
|
||||
return fragment.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if %%key%% (a function selector, function name or
|
||||
* function signature) is present in the ABI.
|
||||
*
|
||||
* In the case of a function name, the name may be ambiguous, so
|
||||
* accessing the [[FunctionFragment]] may require refinement.
|
||||
*/
|
||||
hasFunction(key: string): boolean {
|
||||
return !!this.#getFunction(key, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the [[FunctionFragment]] for %%key%%, which may be a function
|
||||
* selector, function name or function signature that belongs to the ABI.
|
||||
@ -515,6 +526,17 @@ export class Interface {
|
||||
return fragment.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if %%key%% (an event topic hash, event name or
|
||||
* event signature) is present in the ABI.
|
||||
*
|
||||
* In the case of an event name, the name may be ambiguous, so
|
||||
* accessing the [[EventFragment]] may require refinement.
|
||||
*/
|
||||
hasEvent(key: string): boolean {
|
||||
return !!this.#getEvent(key, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the [[EventFragment]] for %%key%%, which may be a topic hash,
|
||||
* event name or event signature that belongs to the ABI.
|
||||
|
@ -236,81 +236,6 @@ function buildWrappedFallback(contract: BaseContract): WrappedFallback {
|
||||
return <WrappedFallback>method;
|
||||
}
|
||||
|
||||
/*
|
||||
class WrappedFallback {
|
||||
|
||||
constructor (contract: BaseContract) {
|
||||
defineProperties<WrappedFallback>(this, { _contract: contract });
|
||||
|
||||
const proxy = new Proxy(this, {
|
||||
// Perform send when called
|
||||
apply: async (target, thisArg, args: Array<any>) => {
|
||||
return await target.send(...args);
|
||||
},
|
||||
});
|
||||
|
||||
return proxy;
|
||||
}
|
||||
|
||||
async populateTransaction(overrides?: Omit<TransactionRequest, "to">): Promise<ContractTransaction> {
|
||||
// If an overrides was passed in, copy it and normalize the values
|
||||
|
||||
const tx: ContractTransaction = <any>(await copyOverrides<"data">(overrides, [ "data" ]));
|
||||
tx.to = await this._contract.getAddress();
|
||||
|
||||
const iface = this._contract.interface;
|
||||
|
||||
// Only allow payable contracts to set non-zero value
|
||||
const payable = iface.receive || (iface.fallback && iface.fallback.payable);
|
||||
assertArgument(payable || (tx.value || BN_0) === BN_0,
|
||||
"cannot send value to non-payable contract", "overrides.value", tx.value);
|
||||
|
||||
// Only allow fallback contracts to set non-empty data
|
||||
assertArgument(iface.fallback || (tx.data || "0x") === "0x",
|
||||
"cannot send data to receive-only contract", "overrides.data", tx.data);
|
||||
|
||||
return tx;
|
||||
}
|
||||
|
||||
async staticCall(overrides?: Omit<TransactionRequest, "to">): Promise<string> {
|
||||
const runner = getRunner(this._contract.runner, "call");
|
||||
assert(canCall(runner), "contract runner does not support calling",
|
||||
"UNSUPPORTED_OPERATION", { operation: "call" });
|
||||
|
||||
const tx = await this.populateTransaction(overrides);
|
||||
|
||||
try {
|
||||
return await runner.call(tx);
|
||||
} catch (error: any) {
|
||||
if (isCallException(error) && error.data) {
|
||||
throw this._contract.interface.makeError(error.data, tx);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async send(overrides?: Omit<TransactionRequest, "to">): Promise<ContractTransactionResponse> {
|
||||
const runner = this._contract.runner;
|
||||
assert(canSend(runner), "contract runner does not support sending transactions",
|
||||
"UNSUPPORTED_OPERATION", { operation: "sendTransaction" });
|
||||
|
||||
const tx = await runner.sendTransaction(await this.populateTransaction(overrides));
|
||||
const provider = getProvider(this._contract.runner);
|
||||
// @TODO: the provider can be null; make a custom dummy provider that will throw a
|
||||
// meaningful error
|
||||
return new ContractTransactionResponse(this._contract.interface, <Provider>provider, tx);
|
||||
}
|
||||
|
||||
async estimateGas(overrides?: Omit<TransactionRequest, "to">): Promise<bigint> {
|
||||
const runner = getRunner(this._contract.runner, "estimateGas");
|
||||
assert(canEstimate(runner), "contract runner does not support gas estimation",
|
||||
"UNSUPPORTED_OPERATION", { operation: "estimateGas" });
|
||||
|
||||
return await runner.estimateGas(await this.populateTransaction(overrides));
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
function buildWrappedMethod<A extends Array<any> = Array<any>, R = any, D extends R | ContractTransactionResponse = ContractTransactionResponse>(contract: BaseContract, key: string): BaseContractMethod<A, R, D> {
|
||||
|
||||
const getFragment = function(...args: ContractMethodArgs<A>): FunctionFragment {
|
||||
@ -748,6 +673,14 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
|
||||
if (result) { return result; }
|
||||
|
||||
throw new Error(`unknown contract event: ${ prop }`);
|
||||
},
|
||||
has: (target, prop) => {
|
||||
// Pass important checks (like `then` for Promise) through
|
||||
if (passProperties.indexOf(<string>prop) >= 0) {
|
||||
return Reflect.has(target, prop);
|
||||
}
|
||||
|
||||
return Reflect.has(target, prop) || this.interface.hasEvent(String(prop));
|
||||
}
|
||||
});
|
||||
defineProperties<BaseContract>(this, { filters });
|
||||
@ -769,6 +702,13 @@ export class BaseContract implements Addressable, EventEmitterable<ContractEvent
|
||||
if (result) { return result; }
|
||||
|
||||
throw new Error(`unknown contract method: ${ prop }`);
|
||||
},
|
||||
has: (target, prop) => {
|
||||
if (prop in target || passProperties.indexOf(<string>prop) >= 0) {
|
||||
return Reflect.has(target, prop);
|
||||
}
|
||||
|
||||
return target.interface.hasFunction(String(prop));
|
||||
}
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user