@0x/contracts-utils: Move LibERC20Token out.

`@0x/contracts-erc20`: Move `LibERC20Token` in.
`@0x/contracts-erc20`: Use `LibBytes` and `LibRichErrors` in `LibERC20Token`.
`@0x/contracts-erc20`: Use `verifyEventsFromLogs` in `LibERC20Token` unit tests.
This commit is contained in:
Lawrence Forman 2019-11-01 13:54:58 -04:00
parent 30c72daed5
commit 8ba7b95e86
17 changed files with 40 additions and 60 deletions

View File

@ -20,8 +20,8 @@ pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
import "@0x/contracts-utils/contracts/src/LibERC20Token.sol";
import "../interfaces/IERC20Bridge.sol"; import "../interfaces/IERC20Bridge.sol";
import "../interfaces/IEth2Dai.sol"; import "../interfaces/IEth2Dai.sol";

View File

@ -21,8 +21,8 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol"; import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol"; import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
import "@0x/contracts-utils/contracts/src/LibERC20Token.sol";
import "../interfaces/IUniswapExchangeFactory.sol"; import "../interfaces/IUniswapExchangeFactory.sol";
import "../interfaces/IUniswapExchange.sol"; import "../interfaces/IUniswapExchange.sol";
import "../interfaces/IERC20Bridge.sol"; import "../interfaces/IERC20Bridge.sol";

View File

@ -1,4 +1,13 @@
[ [
{
"version": "2.3.0-beta.1",
"changes": [
{
"note": "Create `LibERC20Token`",
"pr": 2309
}
]
},
{ {
"version": "2.3.0-beta.0", "version": "2.3.0-beta.0",
"changes": [ "changes": [

View File

@ -18,6 +18,10 @@
pragma solidity ^0.5.9; pragma solidity ^0.5.9;
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "../src/interfaces/IERC20Token.sol";
library LibERC20Token { library LibERC20Token {
@ -35,7 +39,7 @@ library LibERC20Token {
internal internal
{ {
bytes memory callData = abi.encodeWithSelector( bytes memory callData = abi.encodeWithSelector(
0x095ea7b3, IERC20Token(0).approve.selector,
spender, spender,
allowance allowance
); );
@ -56,7 +60,7 @@ library LibERC20Token {
internal internal
{ {
bytes memory callData = abi.encodeWithSelector( bytes memory callData = abi.encodeWithSelector(
0xa9059cbb, IERC20Token(0).transfer.selector,
to, to,
amount amount
); );
@ -79,7 +83,7 @@ library LibERC20Token {
internal internal
{ {
bytes memory callData = abi.encodeWithSelector( bytes memory callData = abi.encodeWithSelector(
0x23b872dd, IERC20Token(0).transferFrom.selector,
from, from,
to, to,
amount amount
@ -104,13 +108,12 @@ library LibERC20Token {
return; return;
} }
if (resultData.length == 32) { if (resultData.length == 32) {
uint256 result; uint256 result = LibBytes.readUint256(resultData, 0);
assembly { result := mload(add(resultData, 0x20)) }
if (result == 1) { if (result == 1) {
return; return;
} }
} }
} }
assembly { revert(add(resultData, 0x20), mload(resultData)) } LibRichErrors.rrevert(resultData);
} }
} }

View File

@ -34,7 +34,7 @@
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol" "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
}, },
"config": { "config": {
"abis": "./generated-artifacts/@(DummyERC20Token|DummyMultipleReturnERC20Token|DummyNoReturnERC20Token|ERC20Token|IERC20Token|IEtherToken|MintableERC20Token|UnlimitedAllowanceERC20Token|UntransferrableDummyERC20Token|WETH9|ZRXToken).json", "abis": "./generated-artifacts/@(DummyERC20Token|DummyMultipleReturnERC20Token|DummyNoReturnERC20Token|ERC20Token|IERC20Token|IEtherToken|LibERC20Token|MintableERC20Token|TestLibERC20Token|TestLibERC20TokenTarget|UnlimitedAllowanceERC20Token|UntransferrableDummyERC20Token|WETH9|ZRXToken).json",
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
}, },
"repository": { "repository": {

View File

@ -11,13 +11,17 @@ import * as DummyNoReturnERC20Token from '../generated-artifacts/DummyNoReturnER
import * as ERC20Token from '../generated-artifacts/ERC20Token.json'; import * as ERC20Token from '../generated-artifacts/ERC20Token.json';
import * as IERC20Token from '../generated-artifacts/IERC20Token.json'; import * as IERC20Token from '../generated-artifacts/IERC20Token.json';
import * as IEtherToken from '../generated-artifacts/IEtherToken.json'; import * as IEtherToken from '../generated-artifacts/IEtherToken.json';
import * as LibERC20Token from '../generated-artifacts/LibERC20Token.json';
import * as MintableERC20Token from '../generated-artifacts/MintableERC20Token.json'; import * as MintableERC20Token from '../generated-artifacts/MintableERC20Token.json';
import * as TestLibERC20Token from '../generated-artifacts/TestLibERC20Token.json';
import * as TestLibERC20TokenTarget from '../generated-artifacts/TestLibERC20TokenTarget.json';
import * as UnlimitedAllowanceERC20Token from '../generated-artifacts/UnlimitedAllowanceERC20Token.json'; import * as UnlimitedAllowanceERC20Token from '../generated-artifacts/UnlimitedAllowanceERC20Token.json';
import * as UntransferrableDummyERC20Token from '../generated-artifacts/UntransferrableDummyERC20Token.json'; import * as UntransferrableDummyERC20Token from '../generated-artifacts/UntransferrableDummyERC20Token.json';
import * as WETH9 from '../generated-artifacts/WETH9.json'; import * as WETH9 from '../generated-artifacts/WETH9.json';
import * as ZRXToken from '../generated-artifacts/ZRXToken.json'; import * as ZRXToken from '../generated-artifacts/ZRXToken.json';
export const artifacts = { export const artifacts = {
ERC20Token: ERC20Token as ContractArtifact, ERC20Token: ERC20Token as ContractArtifact,
LibERC20Token: LibERC20Token as ContractArtifact,
MintableERC20Token: MintableERC20Token as ContractArtifact, MintableERC20Token: MintableERC20Token as ContractArtifact,
UnlimitedAllowanceERC20Token: UnlimitedAllowanceERC20Token as ContractArtifact, UnlimitedAllowanceERC20Token: UnlimitedAllowanceERC20Token as ContractArtifact,
WETH9: WETH9 as ContractArtifact, WETH9: WETH9 as ContractArtifact,
@ -27,5 +31,7 @@ export const artifacts = {
DummyERC20Token: DummyERC20Token as ContractArtifact, DummyERC20Token: DummyERC20Token as ContractArtifact,
DummyMultipleReturnERC20Token: DummyMultipleReturnERC20Token as ContractArtifact, DummyMultipleReturnERC20Token: DummyMultipleReturnERC20Token as ContractArtifact,
DummyNoReturnERC20Token: DummyNoReturnERC20Token as ContractArtifact, DummyNoReturnERC20Token: DummyNoReturnERC20Token as ContractArtifact,
TestLibERC20Token: TestLibERC20Token as ContractArtifact,
TestLibERC20TokenTarget: TestLibERC20TokenTarget as ContractArtifact,
UntransferrableDummyERC20Token: UntransferrableDummyERC20Token as ContractArtifact, UntransferrableDummyERC20Token: UntransferrableDummyERC20Token as ContractArtifact,
}; };

View File

@ -9,7 +9,10 @@ export * from '../generated-wrappers/dummy_no_return_erc20_token';
export * from '../generated-wrappers/erc20_token'; export * from '../generated-wrappers/erc20_token';
export * from '../generated-wrappers/i_erc20_token'; export * from '../generated-wrappers/i_erc20_token';
export * from '../generated-wrappers/i_ether_token'; export * from '../generated-wrappers/i_ether_token';
export * from '../generated-wrappers/lib_erc20_token';
export * from '../generated-wrappers/mintable_erc20_token'; export * from '../generated-wrappers/mintable_erc20_token';
export * from '../generated-wrappers/test_lib_erc20_token';
export * from '../generated-wrappers/test_lib_erc20_token_target';
export * from '../generated-wrappers/unlimited_allowance_erc20_token'; export * from '../generated-wrappers/unlimited_allowance_erc20_token';
export * from '../generated-wrappers/untransferrable_dummy_erc20_token'; export * from '../generated-wrappers/untransferrable_dummy_erc20_token';
export * from '../generated-wrappers/weth9'; export * from '../generated-wrappers/weth9';

View File

@ -2,21 +2,14 @@ import {
blockchainTests, blockchainTests,
constants, constants,
expect, expect,
filterLogsToArguments,
getRandomInteger, getRandomInteger,
hexLeftPad, hexLeftPad,
randomAddress, randomAddress,
verifyEventsFromLogs,
} from '@0x/contracts-test-utils'; } from '@0x/contracts-test-utils';
import { RawRevertError, StringRevertError } from '@0x/utils'; import { RawRevertError, StringRevertError } from '@0x/utils';
import { import { artifacts, TestLibERC20TokenContract, TestLibERC20TokenTargetEvents } from '../src';
artifacts,
TestLibERC20TokenContract,
TestLibERC20TokenTargetApproveCalledEventArgs as ApproveCalled,
TestLibERC20TokenTargetEvents,
TestLibERC20TokenTargetTransferCalledEventArgs as TransferCalled,
TestLibERC20TokenTargetTransferFromCalledEventArgs as TransferFromCalled,
} from '../src';
blockchainTests('LibERC20Token', env => { blockchainTests('LibERC20Token', env => {
let testContract: TestLibERC20TokenContract; let testContract: TestLibERC20TokenContract;
@ -52,11 +45,7 @@ blockchainTests('LibERC20Token', env => {
allowance, allowance,
); );
expect(logs).to.be.length(1); expect(logs).to.be.length(1);
const [event] = filterLogsToArguments<ApproveCalled>(logs, TestLibERC20TokenTargetEvents.ApproveCalled); verifyEventsFromLogs(logs, [{ spender, allowance }], TestLibERC20TokenTargetEvents.ApproveCalled);
expect(event).to.deep.eq({
spender,
allowance,
});
}); });
it('succeeds if the target returns true', async () => { it('succeeds if the target returns true', async () => {
@ -178,11 +167,7 @@ blockchainTests('LibERC20Token', env => {
amount, amount,
); );
expect(logs).to.be.length(1); expect(logs).to.be.length(1);
const [event] = filterLogsToArguments<TransferCalled>(logs, TestLibERC20TokenTargetEvents.TransferCalled); verifyEventsFromLogs(logs, [{ to, amount }], TestLibERC20TokenTargetEvents.TransferCalled);
expect(event).to.deep.eq({
to,
amount,
});
}); });
it('succeeds if the target returns true', async () => { it('succeeds if the target returns true', async () => {
@ -306,15 +291,7 @@ blockchainTests('LibERC20Token', env => {
amount, amount,
); );
expect(logs).to.be.length(1); expect(logs).to.be.length(1);
const [event] = filterLogsToArguments<TransferFromCalled>( verifyEventsFromLogs(logs, [{ from: owner, to, amount }], TestLibERC20TokenTargetEvents.TransferFromCalled);
logs,
TestLibERC20TokenTargetEvents.TransferFromCalled,
);
expect(event).to.deep.eq({
from: owner,
to,
amount,
});
}); });
it('succeeds if the target returns true', async () => { it('succeeds if the target returns true', async () => {

View File

@ -9,7 +9,10 @@
"generated-artifacts/ERC20Token.json", "generated-artifacts/ERC20Token.json",
"generated-artifacts/IERC20Token.json", "generated-artifacts/IERC20Token.json",
"generated-artifacts/IEtherToken.json", "generated-artifacts/IEtherToken.json",
"generated-artifacts/LibERC20Token.json",
"generated-artifacts/MintableERC20Token.json", "generated-artifacts/MintableERC20Token.json",
"generated-artifacts/TestLibERC20Token.json",
"generated-artifacts/TestLibERC20TokenTarget.json",
"generated-artifacts/UnlimitedAllowanceERC20Token.json", "generated-artifacts/UnlimitedAllowanceERC20Token.json",
"generated-artifacts/UntransferrableDummyERC20Token.json", "generated-artifacts/UntransferrableDummyERC20Token.json",
"generated-artifacts/WETH9.json", "generated-artifacts/WETH9.json",

View File

@ -19,10 +19,10 @@
pragma solidity ^0.5.9; pragma solidity ^0.5.9;
import "@0x/contracts-utils/contracts/src/LibBytes.sol"; import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "@0x/contracts-utils/contracts/src/LibERC20Token.sol";
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
import "@0x/contracts-utils/contracts/src/Ownable.sol"; import "@0x/contracts-utils/contracts/src/Ownable.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol"; import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol"; import "@0x/contracts-erc721/contracts/src/interfaces/IERC721Token.sol";
import "./libs/LibConstants.sol"; import "./libs/LibConstants.sol";
import "./libs/LibForwarderRichErrors.sol"; import "./libs/LibForwarderRichErrors.sol";

View File

@ -1,13 +1,4 @@
[ [
{
"version": "3.3.0-beta.1",
"changes": [
{
"note": "Create `LibERC20Token`",
"pr": 2309
}
]
},
{ {
"version": "3.3.0-beta.0", "version": "3.3.0-beta.0",
"changes": [ "changes": [

View File

@ -36,7 +36,7 @@
}, },
"config": { "config": {
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./generated-artifacts/@(Authorizable|IAuthorizable|IOwnable|LibAddress|LibAddressArray|LibAddressArrayRichErrors|LibAuthorizableRichErrors|LibBytes|LibBytesRichErrors|LibEIP1271|LibEIP712|LibERC20Token|LibFractions|LibOwnableRichErrors|LibReentrancyGuardRichErrors|LibRichErrors|LibSafeMath|LibSafeMathRichErrors|Ownable|ReentrancyGuard|Refundable|TestLibAddress|TestLibAddressArray|TestLibBytes|TestLibEIP712|TestLibERC20Token|TestLibERC20TokenTarget|TestLibRichErrors|TestLibSafeMath|TestLogDecoding|TestLogDecodingDownstream|TestOwnable|TestReentrancyGuard|TestRefundable|TestRefundableReceiver).json" "abis": "./generated-artifacts/@(Authorizable|IAuthorizable|IOwnable|LibAddress|LibAddressArray|LibAddressArrayRichErrors|LibAuthorizableRichErrors|LibBytes|LibBytesRichErrors|LibEIP1271|LibEIP712|LibFractions|LibOwnableRichErrors|LibReentrancyGuardRichErrors|LibRichErrors|LibSafeMath|LibSafeMathRichErrors|Ownable|ReentrancyGuard|Refundable|TestLibAddress|TestLibAddressArray|TestLibBytes|TestLibEIP712|TestLibRichErrors|TestLibSafeMath|TestLogDecoding|TestLogDecodingDownstream|TestOwnable|TestReentrancyGuard|TestRefundable|TestRefundableReceiver).json"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -16,7 +16,6 @@ import * as LibBytes from '../generated-artifacts/LibBytes.json';
import * as LibBytesRichErrors from '../generated-artifacts/LibBytesRichErrors.json'; import * as LibBytesRichErrors from '../generated-artifacts/LibBytesRichErrors.json';
import * as LibEIP1271 from '../generated-artifacts/LibEIP1271.json'; import * as LibEIP1271 from '../generated-artifacts/LibEIP1271.json';
import * as LibEIP712 from '../generated-artifacts/LibEIP712.json'; import * as LibEIP712 from '../generated-artifacts/LibEIP712.json';
import * as LibERC20Token from '../generated-artifacts/LibERC20Token.json';
import * as LibFractions from '../generated-artifacts/LibFractions.json'; import * as LibFractions from '../generated-artifacts/LibFractions.json';
import * as LibOwnableRichErrors from '../generated-artifacts/LibOwnableRichErrors.json'; import * as LibOwnableRichErrors from '../generated-artifacts/LibOwnableRichErrors.json';
import * as LibReentrancyGuardRichErrors from '../generated-artifacts/LibReentrancyGuardRichErrors.json'; import * as LibReentrancyGuardRichErrors from '../generated-artifacts/LibReentrancyGuardRichErrors.json';
@ -30,8 +29,6 @@ import * as TestLibAddress from '../generated-artifacts/TestLibAddress.json';
import * as TestLibAddressArray from '../generated-artifacts/TestLibAddressArray.json'; import * as TestLibAddressArray from '../generated-artifacts/TestLibAddressArray.json';
import * as TestLibBytes from '../generated-artifacts/TestLibBytes.json'; import * as TestLibBytes from '../generated-artifacts/TestLibBytes.json';
import * as TestLibEIP712 from '../generated-artifacts/TestLibEIP712.json'; import * as TestLibEIP712 from '../generated-artifacts/TestLibEIP712.json';
import * as TestLibERC20Token from '../generated-artifacts/TestLibERC20Token.json';
import * as TestLibERC20TokenTarget from '../generated-artifacts/TestLibERC20TokenTarget.json';
import * as TestLibRichErrors from '../generated-artifacts/TestLibRichErrors.json'; import * as TestLibRichErrors from '../generated-artifacts/TestLibRichErrors.json';
import * as TestLibSafeMath from '../generated-artifacts/TestLibSafeMath.json'; import * as TestLibSafeMath from '../generated-artifacts/TestLibSafeMath.json';
import * as TestLogDecoding from '../generated-artifacts/TestLogDecoding.json'; import * as TestLogDecoding from '../generated-artifacts/TestLogDecoding.json';
@ -50,7 +47,6 @@ export const artifacts = {
LibBytesRichErrors: LibBytesRichErrors as ContractArtifact, LibBytesRichErrors: LibBytesRichErrors as ContractArtifact,
LibEIP1271: LibEIP1271 as ContractArtifact, LibEIP1271: LibEIP1271 as ContractArtifact,
LibEIP712: LibEIP712 as ContractArtifact, LibEIP712: LibEIP712 as ContractArtifact,
LibERC20Token: LibERC20Token as ContractArtifact,
LibFractions: LibFractions as ContractArtifact, LibFractions: LibFractions as ContractArtifact,
LibOwnableRichErrors: LibOwnableRichErrors as ContractArtifact, LibOwnableRichErrors: LibOwnableRichErrors as ContractArtifact,
LibReentrancyGuardRichErrors: LibReentrancyGuardRichErrors as ContractArtifact, LibReentrancyGuardRichErrors: LibReentrancyGuardRichErrors as ContractArtifact,
@ -66,8 +62,6 @@ export const artifacts = {
TestLibAddressArray: TestLibAddressArray as ContractArtifact, TestLibAddressArray: TestLibAddressArray as ContractArtifact,
TestLibBytes: TestLibBytes as ContractArtifact, TestLibBytes: TestLibBytes as ContractArtifact,
TestLibEIP712: TestLibEIP712 as ContractArtifact, TestLibEIP712: TestLibEIP712 as ContractArtifact,
TestLibERC20Token: TestLibERC20Token as ContractArtifact,
TestLibERC20TokenTarget: TestLibERC20TokenTarget as ContractArtifact,
TestLibRichErrors: TestLibRichErrors as ContractArtifact, TestLibRichErrors: TestLibRichErrors as ContractArtifact,
TestLibSafeMath: TestLibSafeMath as ContractArtifact, TestLibSafeMath: TestLibSafeMath as ContractArtifact,
TestLogDecoding: TestLogDecoding as ContractArtifact, TestLogDecoding: TestLogDecoding as ContractArtifact,

View File

@ -14,7 +14,6 @@ export * from '../generated-wrappers/lib_bytes';
export * from '../generated-wrappers/lib_bytes_rich_errors'; export * from '../generated-wrappers/lib_bytes_rich_errors';
export * from '../generated-wrappers/lib_e_i_p1271'; export * from '../generated-wrappers/lib_e_i_p1271';
export * from '../generated-wrappers/lib_e_i_p712'; export * from '../generated-wrappers/lib_e_i_p712';
export * from '../generated-wrappers/lib_erc20_token';
export * from '../generated-wrappers/lib_fractions'; export * from '../generated-wrappers/lib_fractions';
export * from '../generated-wrappers/lib_ownable_rich_errors'; export * from '../generated-wrappers/lib_ownable_rich_errors';
export * from '../generated-wrappers/lib_reentrancy_guard_rich_errors'; export * from '../generated-wrappers/lib_reentrancy_guard_rich_errors';
@ -28,8 +27,6 @@ export * from '../generated-wrappers/test_lib_address';
export * from '../generated-wrappers/test_lib_address_array'; export * from '../generated-wrappers/test_lib_address_array';
export * from '../generated-wrappers/test_lib_bytes'; export * from '../generated-wrappers/test_lib_bytes';
export * from '../generated-wrappers/test_lib_e_i_p712'; export * from '../generated-wrappers/test_lib_e_i_p712';
export * from '../generated-wrappers/test_lib_erc20_token';
export * from '../generated-wrappers/test_lib_erc20_token_target';
export * from '../generated-wrappers/test_lib_rich_errors'; export * from '../generated-wrappers/test_lib_rich_errors';
export * from '../generated-wrappers/test_lib_safe_math'; export * from '../generated-wrappers/test_lib_safe_math';
export * from '../generated-wrappers/test_log_decoding'; export * from '../generated-wrappers/test_log_decoding';

View File

@ -14,7 +14,6 @@
"generated-artifacts/LibBytesRichErrors.json", "generated-artifacts/LibBytesRichErrors.json",
"generated-artifacts/LibEIP1271.json", "generated-artifacts/LibEIP1271.json",
"generated-artifacts/LibEIP712.json", "generated-artifacts/LibEIP712.json",
"generated-artifacts/LibERC20Token.json",
"generated-artifacts/LibFractions.json", "generated-artifacts/LibFractions.json",
"generated-artifacts/LibOwnableRichErrors.json", "generated-artifacts/LibOwnableRichErrors.json",
"generated-artifacts/LibReentrancyGuardRichErrors.json", "generated-artifacts/LibReentrancyGuardRichErrors.json",
@ -28,8 +27,6 @@
"generated-artifacts/TestLibAddressArray.json", "generated-artifacts/TestLibAddressArray.json",
"generated-artifacts/TestLibBytes.json", "generated-artifacts/TestLibBytes.json",
"generated-artifacts/TestLibEIP712.json", "generated-artifacts/TestLibEIP712.json",
"generated-artifacts/TestLibERC20Token.json",
"generated-artifacts/TestLibERC20TokenTarget.json",
"generated-artifacts/TestLibRichErrors.json", "generated-artifacts/TestLibRichErrors.json",
"generated-artifacts/TestLibSafeMath.json", "generated-artifacts/TestLibSafeMath.json",
"generated-artifacts/TestLogDecoding.json", "generated-artifacts/TestLogDecoding.json",