Skip to content

Commit

Permalink
Moved bare ABI named functions and events from Interface into Contrac…
Browse files Browse the repository at this point in the history
…ts to simplify other consumers of Interface.
  • Loading branch information
ricmoo committed Nov 19, 2019
1 parent 1ec5804 commit da8ca2e
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 16 deletions.
57 changes: 48 additions & 9 deletions packages/abi/src.ts/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export class Interface {
});

// Add any fragments with a unique name by its name (sans signature parameters)
/*
[this.events, this.functions].forEach((bucket) => {
let count = getNameCount(bucket);
Object.keys(bucket).forEach((signature) => {
Expand All @@ -122,6 +123,7 @@ export class Interface {
bucket[fragment.name] = fragment;
});
});
*/

// If we do not have a constructor use the default "constructor() payable"
if (!this.deploy) {
Expand Down Expand Up @@ -149,32 +151,67 @@ export class Interface {

getFunction(nameOrSignatureOrSighash: string): FunctionFragment {
if (isHexString(nameOrSignatureOrSighash)) {
return <FunctionFragment>getFragment(nameOrSignatureOrSighash, this.getSighash.bind(this), this.functions);
for (const name in this.functions) {
if (nameOrSignatureOrSighash === this.getSighash(name)) {
return this.functions[name];
}
}
logger.throwArgumentError("no matching function", "sighash", nameOrSignatureOrSighash);
}

// It is a bare name, look up the function (will return null if ambiguous)
if (nameOrSignatureOrSighash.indexOf("(") === -1) {
return (this.functions[nameOrSignatureOrSighash.trim()] || null);
const name = nameOrSignatureOrSighash.trim();
const matching = Object.keys(this.functions).filter((f) => (f.split("("/* fix:) */)[0] === name));
if (matching.length === 0) {
logger.throwArgumentError("no matching function", "name", name);
} else if (matching.length > 1) {
logger.throwArgumentError("multiple matching functions", "name", name);
}

return this.functions[matching[0]];
}

// Normlize the signature and lookup the function
return this.functions[FunctionFragment.fromString(nameOrSignatureOrSighash).format()];
const result = this.functions[FunctionFragment.fromString(nameOrSignatureOrSighash).format()];
if (!result) {
logger.throwArgumentError("no matching function", "signature", nameOrSignatureOrSighash);
}
return result;
}

getEvent(nameOrSignatureOrTopic: string): EventFragment {
if (isHexString(nameOrSignatureOrTopic)) {
return <EventFragment>getFragment(nameOrSignatureOrTopic, this.getEventTopic.bind(this), this.events);
const topichash = nameOrSignatureOrTopic.toLowerCase();
for (const name in this.events) {
if (topichash === this.getEventTopic(name)) {
return this.events[name];
}
}
logger.throwArgumentError("no matching event", "topichash", topichash);
}

// It is a bare name, look up the function (will return null if ambiguous)
if (nameOrSignatureOrTopic.indexOf("(") === -1) {
return this.events[nameOrSignatureOrTopic];
const name = nameOrSignatureOrTopic.trim();
const matching = Object.keys(this.events).filter((f) => (f.split("("/* fix:) */)[0] === name));
if (matching.length === 0) {
logger.throwArgumentError("no matching event", "name", name);
} else if (matching.length > 1) {
logger.throwArgumentError("multiple matching events", "name", name);
}

return this.events[matching[0]];
}

return this.events[EventFragment.fromString(nameOrSignatureOrTopic).format()];
// Normlize the signature and lookup the function
const result = this.events[EventFragment.fromString(nameOrSignatureOrTopic).format()];
if (!result) {
logger.throwArgumentError("no matching event", "signature", nameOrSignatureOrTopic);
}
return result;
}


getSighash(functionFragment: FunctionFragment | string): string {
if (typeof(functionFragment) === "string") {
functionFragment = this.getFunction(functionFragment);
Expand Down Expand Up @@ -425,7 +462,7 @@ export class Interface {
return !!(value && value._isInterface);
}
}

/*
function getFragment(hash: string, calcFunc: (f: Fragment) => string, items: { [ sig: string ]: Fragment } ) {
for (let signature in items) {
if (signature.indexOf("(") === -1) { continue; }
Expand All @@ -434,7 +471,8 @@ function getFragment(hash: string, calcFunc: (f: Fragment) => string, items: { [
}
return null;
}

*/
/*
function getNameCount(fragments: { [ signature: string ]: Fragment }): { [ name: string ]: number } {
let unique: { [ name: string ]: number } = { };
Expand All @@ -447,3 +485,4 @@ function getNameCount(fragments: { [ signature: string ]: Fragment }): { [ name:
return unique;
}
*/
62 changes: 55 additions & 7 deletions packages/contracts/src.ts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,16 @@ type RunOptions = {
transaction?: boolean;
};

/*
export function _populateTransaction(func: FunctionFragment, args: Array<any>, overrides?: any): Promise<Transaction> {
return null;
}
export function _sendTransaction(func: FunctionFragment, args: Array<any>, overrides?: any): Promise<Transaction> {
return null;
}
*/

function runMethod(contract: Contract, functionName: string, options: RunOptions): RunFunction {
let method = contract.interface.functions[functionName];
return function(...params): Promise<any> {
Expand Down Expand Up @@ -463,15 +473,29 @@ export class Contract {

defineReadOnly(this, "filters", { });

Object.keys(this.interface.events).forEach((eventName) => {
let event = this.interface.events[eventName];
defineReadOnly(this.filters, eventName, (...args: Array<any>) => {
return {
address: this.address,
topics: this.interface.encodeFilterTopics(event, args)
{
const uniqueFilters: { [ name: string ]: Array<string> } = { };
Object.keys(this.interface.events).forEach((eventSignature) => {
let event = this.interface.events[eventSignature];
defineReadOnly(this.filters, eventSignature, (...args: Array<any>) => {
return {
address: this.address,
topics: this.interface.encodeFilterTopics(event, args)
}
});
if (!uniqueFilters[event.name]) { uniqueFilters[event.name] = [ ]; }
uniqueFilters[event.name].push(eventSignature);
});

Object.keys(uniqueFilters).forEach((name) => {
const filters = uniqueFilters[name];
if (filters.length === 1) {
defineReadOnly(this.filters, name, this.filters[filters[0]]);
} else {
logger.warn(`Duplicate definition of ${ name } (${ filters.join(", ")})`);
}
});
});
}

defineReadOnly(this, "_runningEvents", { });
defineReadOnly(this, "_wrappedEmits", { });
Expand All @@ -494,7 +518,11 @@ export class Contract {
}
}

const uniqueFunctions: { [ name: string ]: Array<string> } = { };
Object.keys(this.interface.functions).forEach((name) => {
const fragment = this.interface.functions[name];
// @TODO: This should take in fragment

let run = runMethod(this, name, { });

if (this[name] == null) {
Expand All @@ -516,6 +544,26 @@ export class Contract {
if (this.estimate[name] == null) {
defineReadOnly(this.estimate, name, runMethod(this, name, { estimate: true }));
}

if (!uniqueFunctions[fragment.name]) { uniqueFunctions[fragment.name] = [ ]; }
uniqueFunctions[fragment.name].push(name);
});

Object.keys(uniqueFunctions).forEach((name) => {
const signatures = uniqueFunctions[name];
if (signatures.length > 1) {
logger.warn(`Duplicate definition of ${ name } (${ signatures.join(", ")})`);
return;
}

if (this[name] == null) {
defineReadOnly(this, name, this[signatures[0]]);
}

defineReadOnly(this.functions, name, this.functions[signatures[0]]);
defineReadOnly(this.callStatic, name, this.callStatic[signatures[0]]);
defineReadOnly(this.populateTransaction, name, this.populateTransaction[signatures[0]]);
defineReadOnly(this.estimate, name, this.estimate[signatures[0]]);
});
}

Expand Down

0 comments on commit da8ca2e

Please sign in to comment.