-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Contract with function overloading #407
Comments
If you are using function overloading, the first definition gets the "bare" name. You will need to specify the specific function you wish to call, for example: // initialize(string _name, string _symbol);
contract.initialize(name, symbol).then( ... );
contract["initialize(string,string)"](name, symbol).then( ... );
// initialize(string _name, string _symbol, address _registry);
contract["initialize(string,string,address)"](name, symbol, address).then( ... );
// initialize(string _sender);
contract["initialize(string)"](sender).then( ... );
// initialize();
contract["initialize()"]().then( ... ); You should be able to print This is more of a limitation of un-typed languages (well, any language which doesn't have at least the subset of types that Solidity has). Make sense? :) |
Hi @ricmoo thanks for response,
I've written a sample contract with some test cases: SampleContract.sol pragma solidity ^0.5.0;
contract SampleContract {
function overloading() public pure returns(uint) {
return 1;
}
function overloading(string memory a) public pure returns(uint) {
return 2;
}
function overloading(string memory a, string memory b) public pure returns(uint) {
return 3;
}
} SampleContrat.test.js describe.only("", () => {
// OK
it("should call overloading functions - web3js", async function() {
const sampleContractWeb3 = new web3.eth.Contract(abi, address);
const f1 = await sampleContractWeb3.methods.overloading().call();
const f2 = await sampleContractWeb3.methods.overloading("a").call();
const f3 = await sampleContractWeb3.methods.overloading("a", "b").call();
expect(f1).to.equal("1");
expect(f2).to.equal("2");
expect(f3).to.equal("3");
});
// OK
it("should call overloading functions - ethers", async function() {
const provider = new ethers.providers.JsonRpcProvider();
const sampleContractEthers = new ethers.Contract(address, abi, provider);
const f1 = await sampleContractEthers["overloading()"]();
const f2 = await sampleContractEthers["overloading(string)"]("a");
const f3 = await sampleContractEthers["overloading(string,string)"](
"a",
"b"
);
expect(f1.toNumber()).to.equal(1);
expect(f2.toNumber()).to.equal(2);
expect(f3.toNumber()).to.equal(3);
});
// FAIL
it("should call overloading functions - ethers", async function() {
const provider = new ethers.providers.JsonRpcProvider();
const sampleContractEthers = new ethers.Contract(address, abi, provider);
const f1 = await sampleContractEthers.overloading(); // Error: incorrect number of arguments
const f2 = await sampleContractEthers.overloading("a");
const f3 = await sampleContractEthers.overloading("a", "b");
expect(f1.toNumber()).to.equal(1);
expect(f2.toNumber()).to.equal(2);
expect(f3.toNumber()).to.equal(3);
});
}); Tests Output
"ethers": "^4.0.23", |
So, there are certain cases which can be unambiguous, but that is mores the exception than the rule. A bigger problem comes when you wish to start passing overrides in, for example: let overrides = {
gasLimit: 100000
};
let response = contract.overloading(someValue, overrides); In this case, it becomes more difficult to detect whether this is the 2-parameter signature with no overrides, or the 1-parameter signature with overrides. Type inspection can give you some additional non-ambiguous abilities, however, in the case that the second parameter to So, rather than trying to guess, and sometimes being able to and other times not being able to, which would confuse the developer even more, I error on the side of non-ambiguity. In v5, overloaded operations will not be exposed. (correction: this only applies to ambiguous bare named overloaded operations; see below). You can imagine things get more confusing when you have:
This is another area Web3 and I have disagreed on though. Guessing has often led to either significantly more code, or unexpected dapp security exploits though. :) |
Oh, thanks for the explanation! |
@ricmoo I don't really feel as though the example you give in The example that @marcelomorgado gives in FYI.. For a while now, I've noticed problems with the way Thanks! Just want to add...
as I mentioned above, I actually believe this to be the opposite, based on all the open-source solidity code I've read.
This seems to be the issue. Is there anyway to solve this with type casting, ie with TypeScript? I'm fairly new to TS, so I'm really not sure how that would work. |
@d14na I have seen a few contracts that use overloading to accept different types of parameters during code audits. I agree it isn't common, but it is done, and would need to be handled. It is very confusing why something works in a bunch of cases, but in others it "just doesn't", and its because of an unrelated method to what you are dealing with having a name collision. Oh! Totally sorry, I should have used a semi-colon in that sentence , it should read: "I error on the side of non-ambiguity; in v5, [ambiguous bare named] overloaded operations will not be exposed", i.e. only in the case of ambiguity. If there is only Make sense? Sorry for the confusion. :) There are ways to solve it, but they are all terrible, and some would fail for people using the JavaScript library directly without using TypeScript. I think this is the least terrible solution. One suggestion being put forward is to expose "type indicator wrappers"... You could for example use I'm always open to discussion though. :) |
I agree. I'm always annoyed when software fails "silently", because it leads to inconsistencies that are extremely hard to diagnose for the uninitiated. I have 4 WARNINGS that appear each time I load a new (rather complex) contract i'm working on (which is what brought me here); but they couldn't bother me any less, I just wanted to make sure that Ethers would remain a viable option for such uses past v4, which you've confirmed. Thanks so much for creating an amazing alternative to Web3js. Keep up the great work! |
Thanks! Glad you enjoy it. :) As a quick note, |
|
Oh yes. Each library has its own logger in v5 and I haven’t added the global flag yet. I’ll be adding it soon. |
How would one use
|
You must pass in the fully qualified signature. e.g. If using the contract, the fully qualified signature must be normalized, but if using the |
Any chance that a TypeScript approach may provide a better solution ? |
@SvenMeyer Can you tell what version of Anyways you can still be able to use following in your codebase. await this.stake.connect(this.signers.admin)['getStakedAmount()'](); |
@zemse Actually I just created my project 7 days ago from Paul Bergs' template
I tried the "alternative function call", it works, but ideally I would not confuse front end dev with another notation ... |
You can try upgrading Also, do you get type suggestions in like this? The name collision functions do not have a short name entry ( |
@zemse I created a new project based on @PaulRBerg template https://github.com/paulrberg/solidity-template https://github.com/SvenMeyer/paulrberg-solidity_template created a second version of function greet() public view returns (string memory) {
return greeting;
}
function greet(string memory message) public pure returns (string memory) {
return (message);
} Test looks like this expect(await this.greeter.greet()).to.equal("Hello, world!");
expect(await this.greeter.greet("New Message")).to.equal("New Message"); ... and I still I get an error
|
Ethers.js does not create a The reason is available in an earlier comment. |
@zemse thanks for clarifying (again). I thought that with the update, ethers would just provide all the "right" functions in the standard call format. |
No worries.. I thought you were looking for a typescript solution which does tells you that a |
The problem is there is no “right” function; either could be what you wanted. :s |
@ricmoo we have generic code below where it just takes methodName does it make sense to always use methodName+(++) ? Is there a better way? |
I'm not completely following this thread, but my tests (using Hardhat) of a strings library are failing for failure to discriminate between two same name functions which differ in number of parameters. I have been using this method to supply sensible default values in functions where appropriate, for example the findChar function which finds the 1-based position in a string of the occurrence of a character, optionally starting after a specified position. I use this function signature for the "primary version"
This works as expected in truffle and remix, but fails in hardhat I'm guessing cause of the difference between ethers and web3, I get a type error ("is not a function") no matter how I call it, which I can't get to go away except by deleting the convenience version (with only two params). Is really the intention? Seems a shame to lose the ability to test overloaded functions which is one of the relatively few convenience features of solidity that makes life easier. |
I'm also getting issues in Hardhat's Waffle with ethers on an overloaded function ( await expect(contract.function(args).to.emit(contract, 'EventName') which puts an await contract.function(args); I don't know why that should make a difference, but figured I'd mention it just in case it does. |
* feat: extend from multicall3 in redstoneMulticall3 * fix: redeclaration of type * fix: use only single aggregate3 function - ethers-io/ethers.js#407
* feat: extend from multicall3 in redstoneMulticall3 * fix: redeclaration of type * fix: use only single aggregate3 function - ethers-io/ethers.js#407
* feat: extend from multicall3 in redstoneMulticall3 * fix: redeclaration of type * fix: use only single aggregate3 function - ethers-io/ethers.js#407
Hi,
A contract that I'm testing has different interfaces for same function name:
I'm getting the error:
Error: incorrect number of arguments
when I'm trying call the second function.Seems that when
Contract
is reading the ABI and it's only considering the first interface and ignoring the others.ethers.js/src.ts/utils/interface.ts
Line 328 in c2ce59f
ethers.js/src.ts/contract.ts
Line 431 in 4425536
Notes:
web3js
I can call all of interfaces.Thanks!
The text was updated successfully, but these errors were encountered: