Consider the following sample Truffle project:
.
├── contracts
│ ├── Foo.sol
│ └── Migrations.sol
├── migrations
│ ├── 1_initial_migration.js
│ └── 2_foo.js
├── test
│ └── Foo.test.js
└── truffle.js
Contents of contracts/Foo.sol
:
pragma solidity ^0.4.21;
contract Foo {
enum Bar {zero, one, two, three}
function getOne() public pure returns (Bar) {
return Bar.one;
}
}
Contents of test/Foo.test.js
:
let Foo = artifacts.require("./Foo.sol");
contract("", async (accounts) => {
it("", async () => {
let instance = await Foo.deployed();
let one = await instance.getOne();
assert.equal(one, 1);
});
});
Let's test our project:
$ truffle test
Compiling ./contracts/Foo.sol...
Compiling ./contracts/Migrations.sol...
Contract:
✓
1 passing (27ms)
As you can see, everything is perfect. Now, just for the sake of science, let's turn our contract into a library in contracts/Foo.sol
:
pragma solidity ^0.4.21;
library Foo {
enum Bar {zero, one, two, three}
function getOne() public pure returns (Bar) {
return Bar.one;
}
}
And let's run the test again:
$ truffle test
Compiling ./contracts/Foo.sol...
Compiling ./contracts/Migrations.sol...
Contract:
1)
> No events were emitted
0 passing (32ms)
1 failing
1) Contract: :
Error: invalid solidity type!: Foo.Bar
at SolidityCoder._requireType (/home/emilio/.nvm/versions/node/v9.8.0/lib/node_modules/truffle/build/webpack:/~/web3/lib/solidity/coder.js:61:1)
at /home/emilio/.nvm/versions/node/v9.8.0/lib/node_modules/truffle/build/webpack:/~/web3/lib/solidity/coder.js:231:1
at Array.map (<anonymous>)
at SolidityCoder.getSolidityTypes (/home/emilio/.nvm/versions/node/v9.8.0/lib/node_modules/truffle/build/webpack:/~/web3/lib/solidity/coder.js:230:1)
at SolidityCoder.decodeParams (/home/emilio/.nvm/versions/node/v9.8.0/lib/node_modules/truffle/build/webpack:/~/web3/lib/solidity/coder.js:203:1)
at SolidityFunction.unpackOutput (/home/emilio/.nvm/versions/node/v9.8.0/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/function.js:113:1)
at Object.callback (/home/emilio/.nvm/versions/node/v9.8.0/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/function.js:145:1)
at /home/emilio/.nvm/versions/node/v9.8.0/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/method.js:142:1
at /home/emilio/.nvm/versions/node/v9.8.0/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/requestmanager.js:89:1
at /home/emilio/.nvm/versions/node/v9.8.0/lib/node_modules/truffle/build/webpack:/~/truffle-provider/wrapper.js:134:1
at XMLHttpRequest.request.onreadystatechange (/home/emilio/.nvm/versions/node/v9.8.0/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/httpprovider.js:128:1)
at XMLHttpRequestEventTarget.dispatchEvent (/home/emilio/.nvm/versions/node/v9.8.0/lib/node_modules/truffle/build/webpack:/~/xhr2/lib/xhr2.js:64:1)
at XMLHttpRequest._setReadyState (/home/emilio/.nvm/versions/node/v9.8.0/lib/node_modules/truffle/build/webpack:/~/xhr2/lib/xhr2.js:354:1)
at XMLHttpRequest._onHttpResponseEnd (/home/emilio/.nvm/versions/node/v9.8.0/lib/node_modules/truffle/build/webpack:/~/xhr2/lib/xhr2.js:509:1)
at IncomingMessage.<anonymous> (/home/emilio/.nvm/versions/node/v9.8.0/lib/node_modules/truffle/build/webpack:/~/xhr2/lib/xhr2.js:469:1)
at endReadableNT (_stream_readable.js:1101:12)
at process._tickCallback (internal/process/next_tick.js:114:19)
Why?
First I said to myself: sure, it's because libraries can't have state variables. But then I realized an enum
is not a state variable; it's a type definition. The documentation uses struct
s extensively, which I would say are similar in nature to enum
s. Also, although not shown in this example, when referencing the library enum from a contract, it compiles well, which might suggest it's a web3js issue.
So what's going on? Is this by design? What's the best practice here? Define the enum
in every contract that uses the library? Turn the enum
into a struct
? What am I missing?
Reproducibility info
For the sake of reproducibility I include the (rather trivial) contents of migrations/2_foo.js
:
let Foo = artifacts.require("./Foo.sol");
module.exports = (deployer) => {
deployer.deploy(Foo);
};
And truffle.js
:
module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 8545,
network_id: "*" // Match any network id
}
}
};
The remaining files, as you know, are created by truffle init
.
I also run ganache-cli
in a separate terminal as my testnet.
Here are the versions of the development tools I'm using:
$ truffle version
Truffle v4.1.5 (core: 4.1.5)
Solidity v0.4.21 (solc-js)
$ ganache-cli version
Ganache CLI v6.1.0 (ganache-core: 2.1.0)