├── .github ├── CODEOWNERS ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── feature_report.md │ ├── issue_report.md │ └── bug_report.md ├── PULL_REQUEST_TEMPLATE.md ├── stale.yml └── workflows │ └── build.yml ├── settings.gradle ├── gradle ├── javadoc │ └── build.gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── repositories │ └── build.gradle ├── java │ └── build.gradle ├── junit │ └── build.gradle ├── spotless │ ├── java.license │ ├── formatter.properties │ └── build.gradle └── jacoco │ └── build.gradle ├── .gitignore ├── funding.json ├── gradle.properties ├── src ├── test │ ├── resources │ │ └── solidity │ │ │ ├── openzeppelin │ │ │ ├── MyCollectible.sol │ │ │ └── MyOFT.sol │ │ │ ├── common │ │ │ └── Mortal.sol │ │ │ ├── different_versions │ │ │ ├── Mortal.sol │ │ │ ├── Greeter.sol │ │ │ └── HelloWorld.sol │ │ │ ├── greeter │ │ │ └── Greeter.sol │ │ │ ├── minimal_forwarder │ │ │ ├── IERC5267.sol │ │ │ ├── SignedMath.sol │ │ │ ├── MinimalForwarder.sol │ │ │ ├── Strings.sol │ │ │ ├── ShortStrings.sol │ │ │ ├── StorageSlot.sol │ │ │ ├── EIP712.sol │ │ │ ├── ECDSA.sol │ │ │ └── Math.sol │ │ │ ├── sol5 │ │ │ └── Greeter.sol │ │ │ └── eip │ │ │ ├── EIP20Interface.sol │ │ │ └── EIP20.sol │ └── groovy │ │ └── org │ │ └── web3j │ │ └── solidity │ │ └── gradle │ │ └── plugin │ │ └── SolidityPluginTest.groovy └── main │ └── groovy │ └── org │ └── web3j │ └── solidity │ └── gradle │ └── plugin │ ├── OutputComponent.groovy │ ├── CombinedOutputComponent.groovy │ ├── EVMVersion.groovy │ ├── SoliditySourceSet.groovy │ ├── SolidityResolve.groovy │ ├── SolidityExtractImports.groovy │ ├── DefaultSoliditySourceSet.groovy │ ├── SolidityExtension.groovy │ ├── ImportsResolver.groovy │ ├── SolidityPlugin.groovy │ └── SolidityCompile.groovy ├── MAINTAINERS.md ├── SECURITY.md ├── CONTRIBUTING.md ├── gradlew.bat ├── CHANGELOG.md ├── README.md ├── CODE_OF_CONDUCT.md ├── gradlew └── LICENSE /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @conor10 @gtebrean @NickSneo -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'solidity-gradle-plugin' 2 | -------------------------------------------------------------------------------- /gradle/javadoc/build.gradle: -------------------------------------------------------------------------------- 1 | javadoc { options.encoding = 'UTF-8' } 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [web3j] 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /.idea 3 | /.gradle 4 | /out 5 | /lib 6 | *.iml 7 | gradle.properties 8 | /lib -------------------------------------------------------------------------------- /funding.json: -------------------------------------------------------------------------------- 1 | { 2 | "opRetro": { 3 | "projectId": "0x4dd10ba330a4a21459e2ba72f15fb5da2a63f7492e2b1567e6669c3d47fe6308" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LFDT-web3j/web3j-solidity-gradle-plugin/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | group=org.web3j.solidity 2 | version=0.6.0 3 | 4 | # Use Local Build Cache: https://docs.gradle.org/current/userguide/build_cache.html 5 | org.gradle.caching=true 6 | -------------------------------------------------------------------------------- /gradle/repositories/build.gradle: -------------------------------------------------------------------------------- 1 | repositories { 2 | mavenCentral() 3 | maven { url = 'https://oss.sonatype.org/content/repositories/releases/' } 4 | maven { url = 'https://oss.sonatype.org/content/repositories/snapshots/' } 5 | } 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature report 3 | about: Create a report to help us improve 4 | title: "" 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | ## Feature description_ 12 | _A clear and concise description of what the feature would be._ 13 | 14 | 15 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /src/test/resources/solidity/openzeppelin/MyCollectible.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity ^0.8.0; 3 | 4 | import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 5 | 6 | 7 | contract MyCollectible is ERC721 { 8 | constructor() ERC721("MyCollectible", "MCO") public { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### What does this PR do? 2 | *required* 3 | 4 | ### Where should the reviewer start? 5 | *required* 6 | 7 | ### Why is it needed? 8 | *required* 9 | 10 | ## Checklist 11 | 12 | - [ ] I've read the contribution guidelines. 13 | - [ ] I've added tests (if applicable). 14 | - [ ] I've added a changelog entry if necessary. -------------------------------------------------------------------------------- /gradle/java/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | 3 | 4 | java { 5 | toolchain { 6 | languageVersion.set(JavaLanguageVersion.of(21)) 7 | } 8 | } 9 | 10 | compileJava { 11 | options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" 12 | } 13 | 14 | compileTestJava { 15 | options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" 16 | } 17 | -------------------------------------------------------------------------------- /src/test/resources/solidity/common/Mortal.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.4; 2 | 3 | contract Mortal { 4 | /* Define variable owner of the type address*/ 5 | address payable owner; 6 | 7 | /* this function is executed at initialization and sets the owner of the contract */ 8 | constructor () {owner = payable(msg.sender);} 9 | 10 | /* Function to recover the funds on the contract */ 11 | function kill() public {if (msg.sender == owner) selfdestruct(owner);} 12 | } 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Issue report 3 | about: Create a report to help us improve 4 | title: "" 5 | labels: needs-review 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | # _Issue_title_ 12 | _A clear and concise description of what the issue is._ 13 | 14 | 15 | ## _Issue_description_ 16 | _Please describe what are you trying to do and why it doesn't work_ 17 | 18 | 19 | ## _Issue_context_ 20 | _Please provide additional information that might be helpful_ 21 | 22 | -------------------------------------------------------------------------------- /src/test/resources/solidity/different_versions/Mortal.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.6.0; 2 | 3 | contract Mortal { 4 | /* Define variable owner of the type address*/ 5 | address payable owner; 6 | 7 | /* this function is executed at initialization and sets the owner of the contract */ 8 | constructor() public {owner = msg.sender;} 9 | 10 | /* Function to recover the funds on the contract */ 11 | function kill() public {if (msg.sender == owner) selfdestruct(payable(owner));} 12 | } 13 | -------------------------------------------------------------------------------- /gradle/junit/build.gradle: -------------------------------------------------------------------------------- 1 | ext { 2 | junitVersion = '5.9.3' 3 | } 4 | 5 | dependencies { 6 | testImplementation "org.junit.jupiter:junit-jupiter-engine:$junitVersion", 7 | "org.junit.jupiter:junit-jupiter-api:$junitVersion", 8 | "org.junit.jupiter:junit-jupiter-params:$junitVersion", 9 | "org.junit.platform:junit-platform-launcher" 10 | } 11 | 12 | test { 13 | useJUnitPlatform() 14 | 15 | testLogging { 16 | events "passed", "skipped", "failed" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/resources/solidity/openzeppelin/MyOFT.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity ^0.8.22; 3 | 4 | import { OFT } from "@layerzerolabs/oft-evm/contracts/OFT.sol"; 5 | import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; 6 | 7 | contract MyOFT is OFT { 8 | constructor( 9 | string memory _name, 10 | string memory _symbol, 11 | address _lzEndpoint, 12 | address _delegate 13 | ) OFT(_name, _symbol, _lzEndpoint, _delegate) Ownable(_delegate) {} 14 | } 15 | -------------------------------------------------------------------------------- /gradle/spotless/java.license: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright $YEAR Web3 Labs Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | Maintainers 2 | =========== 3 | 4 | **Active Maintainers** 5 | 6 | | Name | GitHub | Chat | 7 | |----------------|--------|-----| 8 | | Conor Svensson | [conor10][conor10] | conor10 | 9 | | George Ţebrean | [gtebrean][gtebrean] | gdev#2230 | 10 | | Nischal Sharma | [NickSneo][NickSneo] | nicks1106 | 11 | 12 | 13 | 14 | [conor10]: https://github.com/conor10 15 | [gtebrean]: https://github.com/gtebrean 16 | [NickSneo]: https://github.com/NickSneo 17 | 18 | 19 | 20 | **Emeritus Maintainers** 21 | 22 | | Name | GitHub | Chat | 23 | |------|------------------|------| 24 | |Christian Felde | [cfelde][cfelde] | cfelde | 25 | | Andrii | [andrii-kl][andrii-kl] | andrii-kl | 26 | 27 | [cfelde]: https://github.com/cfelde 28 | [andrii-kl]: https://github.com/andrii-kl -------------------------------------------------------------------------------- /src/test/resources/solidity/greeter/Greeter.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.8.4; 2 | 3 | // Example taken from https://www.ethereum.org/greeter, also used in 4 | // https://github.com/ethereum/go-ethereum/wiki/Contract-Tutorial#your-first-citizen-the-greeter 5 | 6 | import "../common/Mortal.sol"; 7 | 8 | contract Greeter is Mortal { 9 | /* define variable greeting of the type string */ 10 | string greeting; 11 | 12 | /* this runs when the contract is executed */ 13 | constructor(string memory _greeting) { 14 | greeting = _greeting; 15 | } 16 | 17 | function newGreeting(string memory _greeting) public { 18 | greeting = _greeting; 19 | } 20 | 21 | /* main function */ 22 | function greet() public view returns (string memory) { 23 | return greeting; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/resources/solidity/minimal_forwarder/IERC5267.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.12; 4 | 5 | interface IERC5267 { 6 | /** 7 | * @dev MAY be emitted to signal that the domain could have changed. 8 | */ 9 | event EIP712DomainChanged(); 10 | 11 | /** 12 | * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712 13 | * signature. 14 | */ 15 | function eip712Domain() 16 | external 17 | view 18 | returns ( 19 | bytes1 fields, 20 | string memory name, 21 | string memory version, 22 | uint256 chainId, 23 | address verifyingContract, 24 | bytes32 salt, 25 | uint256[] memory extensions 26 | ); 27 | } -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Hyperledger Security Policy 2 | 3 | ## Reporting a Security Bug 4 | 5 | If you think you have discovered a security issue in any of the Hyperledger projects, we'd love to hear from you. We will take all security bugs seriously and if confirmed upon investigation we will patch it within a reasonable amount of time and release a public security bulletin discussing the impact and credit the discoverer. 6 | 7 | In order to report a security bug please email a description of the flaw and any related information (e.g. reproduction steps, version) to [security at hyperledger dot org](mailto:security@hyperledger.org). 8 | 9 | The process by which the Hyperledger Security Team handles security bugs is documented further in our [Defect Response page](https://wiki.hyperledger.org/display/SEC/Defect+Response) on our [wiki](https://wiki.hyperledger.org). -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | # _Bug_title_ 11 | _A clear and concise description of what the issue is._ 12 | 13 | ## Steps To Reproduce 14 | _Describe the exact steps or scenario to reproduce the issue._ 15 | 16 | ### Expected behavior 17 | _A clear and concise description of what you expected to happen._ 18 | 19 | ### Actual behavior 20 | _A description of the actual behavior occurring._ 21 | 22 | ## Environment 23 | _Describe the environment in which the issue occurs_ 24 | - Plugin version 25 | - Java version 26 | - Operating System 27 | 28 | 29 | ## Additional context 30 | _Add any other context about the problem here._ 31 | - Logs 32 | - Sample code and/or code snippets 33 | - Unit/integration tests to highlight the issue 34 | 35 | 36 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 21 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - enhancement 8 | - funded 9 | - help wanted 10 | - mini-project 11 | - needs-review 12 | - bug 13 | - awaiting-pr 14 | - downstream-issue 15 | - wip 16 | # Label to use when marking an issue as stale 17 | staleLabel: stale 18 | # Comment to post when marking an issue as stale. Set to `false` to disable 19 | markComment: > 20 | This issue has been automatically marked as stale because it has not had 21 | recent activity. It will be closed if no further activity occurs. Thank you 22 | for your contributions. 23 | # Comment to post when closing a stale issue. Set to `false` to disable 24 | closeComment: false 25 | -------------------------------------------------------------------------------- /src/test/resources/solidity/different_versions/Greeter.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.7.0 <0.8.0; 2 | 3 | contract Mortal { 4 | /* Define variable owner of the type address */ 5 | address owner; 6 | 7 | /* This constructor is executed at initialization and sets the owner of the contract */ 8 | constructor() { owner = msg.sender; } 9 | 10 | /* Function to recover the funds on the contract */ 11 | function kill() public { if (msg.sender == owner) selfdestruct(msg.sender); } 12 | } 13 | 14 | contract Greeter is Mortal { 15 | /* Define variable greeting of the type string */ 16 | string greeting; 17 | 18 | /* This runs when the contract is executed */ 19 | constructor(string memory _greeting) { 20 | greeting = _greeting; 21 | } 22 | 23 | /* Main function */ 24 | function greet() public view returns (string memory) { 25 | return greeting; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/resources/solidity/sol5/Greeter.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.8.0 <0.9.0; 2 | 3 | contract Mortal { 4 | /* Define variable owner of the type address */ 5 | address payable owner; 6 | 7 | /* This constructor is executed at initialization and sets the owner of the contract */ 8 | constructor() { owner = payable(msg.sender); } 9 | 10 | /* Function to recover the funds on the contract */ 11 | function kill() public { if (msg.sender == owner) selfdestruct(payable(msg.sender)); } 12 | } 13 | 14 | contract Greeter is Mortal { 15 | /* Define variable greeting of the type string */ 16 | string greeting; 17 | 18 | /* This runs when the contract is executed */ 19 | constructor(string memory _greeting) { 20 | greeting = _greeting; 21 | } 22 | 23 | /* Main function */ 24 | function greet() public view returns (string memory) { 25 | return greeting; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: Set up JDK 21 16 | uses: actions/setup-java@v1 17 | with: 18 | java-version: 21 19 | - name: Cache Gradle packages 20 | uses: actions/cache@v4 21 | with: 22 | path: ~/.gradle/caches 23 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} 24 | restore-keys: ${{ runner.os }}-gradle 25 | - name: Grant execute permission for gradlew 26 | run: chmod +x gradlew 27 | - name: Build 28 | run: ./gradlew check jacocoTestReport 29 | - name: After success 30 | run: bash <(curl -s https://codecov.io/bash) 31 | if: ${{ success() }} 32 | -------------------------------------------------------------------------------- /gradle/jacoco/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'jacoco' 2 | 3 | tasks.register('jacocoRootTestReport', JacocoReport) { 4 | dependsOn = subprojects.test 5 | getSourceDirectories().from(subprojects.sourceSets.main.allSource.srcDirs) 6 | getAdditionalSourceDirs().from(subprojects.sourceSets.main.allSource.srcDirs) 7 | getClassDirectories().from(subprojects.sourceSets.main.output) 8 | getExecutionData().from(subprojects.jacocoTestReport.executionData) 9 | reports { 10 | xml.required.set(true) 11 | } 12 | 13 | doFirst { 14 | getExecutionData().from(executionData.findAll { it.exists() }) 15 | } 16 | 17 | afterEvaluate { 18 | getClassDirectories().from(files(classDirectories.files.collect { 19 | fileTree(dir: it, 20 | exclude: [ 21 | 'org/web3j/abi/datatypes/generated/**', 22 | 'org/web3j/tuples/generated/**', 23 | 'org/web3j/ens/contracts/generated/**', 24 | 'org/gradle/**' 25 | ]) 26 | })) 27 | } 28 | } 29 | 30 | jacoco { 31 | toolVersion = "0.8.10" 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/main/groovy/org/web3j/solidity/gradle/plugin/OutputComponent.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Web3 Labs Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package org.web3j.solidity.gradle.plugin 14 | 15 | import groovy.transform.CompileStatic 16 | 17 | @CompileStatic 18 | enum OutputComponent { 19 | 20 | AST, 21 | AST_JSON, 22 | AST_COMPACT_JSON, 23 | ASM, 24 | ASM_JSON, 25 | OPCODES, 26 | BIN, 27 | BIN_RUNTIME, 28 | CLONE_BIN, 29 | ABI, 30 | HASHES, 31 | USERDOC, 32 | DEVDOC, 33 | METADATA 34 | 35 | @Override 36 | String toString() { 37 | return name().replaceAll('_', '-').toLowerCase() 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /src/main/groovy/org/web3j/solidity/gradle/plugin/CombinedOutputComponent.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Web3 Labs Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package org.web3j.solidity.gradle.plugin 14 | 15 | import groovy.transform.CompileStatic 16 | 17 | @CompileStatic 18 | enum CombinedOutputComponent { 19 | ABI, 20 | ASM, 21 | AST, 22 | BIN, 23 | BIN_RUNTIME, 24 | CLONE_BIN, 25 | COMPACT_FORMAT, 26 | DEVDOC, 27 | HASHES, 28 | INTERFACE, 29 | METADATA, 30 | OPCODES, 31 | SRCMAP, 32 | SRCMAP_RUNTIME, 33 | USERDOC 34 | 35 | @Override 36 | String toString() { 37 | return name().replaceAll('_', '-').toLowerCase() 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /src/main/groovy/org/web3j/solidity/gradle/plugin/EVMVersion.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Web3 Labs Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package org.web3j.solidity.gradle.plugin 14 | 15 | import groovy.transform.CompileStatic 16 | 17 | @CompileStatic 18 | enum EVMVersion { 19 | HOMESTEAD('homestead'), 20 | TANGERINE_WHISTLE('tangerineWhistle'), 21 | SPURIOUS_DRAGON('spuriousDragon'), 22 | BYZANTIUM('byzantium'), 23 | CONSTANTINOPLE('constantinople'), 24 | PETERSBURG('petersburg'), 25 | ISTANBUL('istanbul'), 26 | BERLIN('berlin'), 27 | LONDON('london'), 28 | PARIS('paris'), 29 | SHANGHAI('shanghai'), 30 | CANCUN('cancun') 31 | 32 | private String value 33 | 34 | EVMVersion(String value) { 35 | this.value = value 36 | } 37 | 38 | String getValue() { 39 | return value 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/test/resources/solidity/minimal_forwarder/SignedMath.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) 3 | 4 | pragma solidity 0.8.12; 5 | 6 | /** 7 | * @dev Standard signed math utilities missing in the Solidity language. 8 | */ 9 | library SignedMath { 10 | /** 11 | * @dev Returns the largest of two signed numbers. 12 | */ 13 | function max(int256 a, int256 b) internal pure returns (int256) { 14 | return a > b ? a : b; 15 | } 16 | 17 | /** 18 | * @dev Returns the smallest of two signed numbers. 19 | */ 20 | function min(int256 a, int256 b) internal pure returns (int256) { 21 | return a < b ? a : b; 22 | } 23 | 24 | /** 25 | * @dev Returns the average of two signed numbers without overflow. 26 | * The result is rounded towards zero. 27 | */ 28 | function average(int256 a, int256 b) internal pure returns (int256) { 29 | // Formula from the book "Hacker's Delight" 30 | int256 x = (a & b) + ((a ^ b) >> 1); 31 | return x + (int256(uint256(x) >> 255) & (a ^ b)); 32 | } 33 | 34 | /** 35 | * @dev Returns the absolute unsigned value of a signed value. 36 | */ 37 | function abs(int256 n) internal pure returns (uint256) { 38 | unchecked { 39 | // must be unchecked in order to support `n = type(int256).min` 40 | return uint256(n >= 0 ? n : -n); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/main/groovy/org/web3j/solidity/gradle/plugin/SoliditySourceSet.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Web3 Labs Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package org.web3j.solidity.gradle.plugin 14 | 15 | import groovy.transform.CompileStatic 16 | import org.gradle.api.file.SourceDirectorySet 17 | import org.gradle.api.provider.Property 18 | 19 | /** 20 | * Source set for Solidity classes in a Gradle project. 21 | */ 22 | @CompileStatic 23 | interface SoliditySourceSet extends SourceDirectorySet { 24 | /** 25 | * All Solidity source for this source set. 26 | * 27 | * @return the Solidity source. Never returns null. 28 | */ 29 | SourceDirectorySet getAllSolidity() 30 | 31 | String NAME = "solidity" 32 | 33 | Property getEvmVersion() 34 | 35 | Property getVersion() 36 | 37 | Property getOptimize() 38 | 39 | Property getOptimizeRuns() 40 | 41 | Property getIgnoreMissing() 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/test/resources/solidity/different_versions/HelloWorld.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity ^0.8.0; 3 | 4 | // Modified Greeter contract. Based on example at https://www.ethereum.org/greeter. 5 | 6 | contract Mortal { 7 | /* Define variable owner of the type address*/ 8 | address payable owner; 9 | 10 | /* this function is executed at initialization and sets the owner of the contract */ 11 | constructor () {owner = payable(msg.sender);} 12 | 13 | modifier onlyOwner { 14 | require( 15 | msg.sender == owner, 16 | "Only owner can call this function." 17 | ); 18 | _; 19 | } 20 | 21 | /* Function to recover the funds on the contract */ 22 | function kill() onlyOwner public {selfdestruct(payable(msg.sender));} 23 | } 24 | 25 | contract HelloWorld is Mortal { 26 | /* define variable greeting of the type string */ 27 | string greet; 28 | 29 | /* this runs when the contract is executed */ 30 | constructor (string memory _greet) { 31 | greet = _greet; 32 | } 33 | 34 | function newGreeting(string memory _greet) onlyOwner public { 35 | emit Modified(greet, _greet, greet, _greet); 36 | greet = _greet; 37 | } 38 | 39 | /* main function */ 40 | function greeting() public view returns (string memory) { 41 | return greet; 42 | } 43 | 44 | event Modified( 45 | string indexed oldGreetingIdx, string indexed newGreetingIdx, 46 | string oldGreeting, string newGreeting); 47 | } -------------------------------------------------------------------------------- /src/main/groovy/org/web3j/solidity/gradle/plugin/SolidityResolve.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Web3 Labs Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package org.web3j.solidity.gradle.plugin 14 | 15 | import groovy.json.JsonSlurper 16 | import groovy.transform.CompileStatic 17 | import org.gradle.api.DefaultTask 18 | import org.gradle.api.file.DirectoryProperty 19 | import org.gradle.api.file.RegularFileProperty 20 | import org.gradle.api.tasks.* 21 | 22 | @CompileStatic 23 | @CacheableTask 24 | abstract class SolidityResolve extends DefaultTask { 25 | 26 | @InputFile 27 | @PathSensitive(value = PathSensitivity.NAME_ONLY) 28 | abstract RegularFileProperty getPackageJson() 29 | 30 | @InputDirectory 31 | @PathSensitive(value = PathSensitivity.RELATIVE) 32 | abstract DirectoryProperty getNodeModules() 33 | 34 | @OutputFile 35 | abstract RegularFileProperty getAllImports() 36 | 37 | @TaskAction 38 | void resolveSolidity() { 39 | final imports = new JsonSlurper().parse(getPackageJson().get().asFile)['dependencies'] as Map 40 | 41 | final all = ImportsResolver.resolveTransitive(imports.keySet(), getNodeModules().get().asFile) 42 | 43 | allImports.get().asFile.text = all.join('\n') 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## How to contribute to web3j 2 | 3 | Thank you for reading this! If you'd like to report a bug or join in the buidl-ing of web3j, then here are some notes on how to do that. 4 | 5 | #### **Did you find a bug?** 6 | 7 | * **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/web3j/web3j/issues). If there is then please add any more information that you have, or give it a :+1:. This will help us prioritize work. 8 | 9 | * If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/web3j/web3j/issues/new). Be sure to include a **title and clear description**, as much relevant information as possible, and a **code sample** or event better an **executable test case** demonstrating the expected behavior that is not occurring. 10 | 11 | #### **Did you write a patch that fixes a bug?** 12 | 13 | * Open a new pull request with the patch. 14 | 15 | * Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable. 16 | 17 | * Make sure that the code is formatted with Spotless by executing `./gradlew spotlessApply` otherwise the build will fail. 18 | 19 | #### **Do you intend to add a new feature or change an existing one?** 20 | 21 | * Suggest your change [Discord**](https://discord.com/channels/905194001349627914/1195062053682032700) then start writing code. 22 | 23 | * Do not open an issue on GitHub until you have collected positive feedback about the change. GitHub issues are primarily intended for bug reports and fixes. 24 | 25 | #### **Do you have questions about the source code?** 26 | 27 | * Ask any question about how to use web3j should be directed to the [discord channel**](https://discord.com/channels/905194001349627914/1195062053682032700) 28 | 29 | ### Note 30 | ** If you are unable to open the Web3j discord channel then first join the [Hyperledger Server](https://discord.gg/hyperledger) and then go the [#web3-general](https://discord.com/channels/905194001349627914/1195062053682032700) 31 | 32 | ## :heart: BUIDL :heart: 33 | 34 | team web3j 35 | -------------------------------------------------------------------------------- /src/test/resources/solidity/eip/EIP20Interface.sol: -------------------------------------------------------------------------------- 1 | // Abstract contract for the full ERC 20 Token standard 2 | // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md 3 | // SPDX-License-Identifier: Apache-2.0 4 | pragma solidity ^0.8.4; 5 | 6 | 7 | interface EIP20Interface { 8 | 9 | /// @param _owner The address from which the balance will be retrieved 10 | /// @return balance 11 | function balanceOf(address _owner) external view returns (uint256 balance); 12 | 13 | /// @notice send `_value` token to `_to` from `msg.sender` 14 | /// @param _to The address of the recipient 15 | /// @param _value The amount of token to be transferred 16 | /// @return success Whether the transfer was successful or not 17 | function transfer(address _to, uint256 _value) external returns (bool success); 18 | 19 | /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from` 20 | /// @param _from The address of the sender 21 | /// @param _to The address of the recipient 22 | /// @param _value The amount of token to be transferred 23 | /// @return success Whether the transfer was successful or not 24 | function transferFrom(address _from, address _to, uint256 _value) external returns (bool success); 25 | 26 | /// @notice `msg.sender` approves `_spender` to spend `_value` tokens 27 | /// @param _spender The address of the account able to transfer the tokens 28 | /// @param _value The amount of tokens to be approved for transfer 29 | /// @return success Whether the approval was successful or not 30 | function approve(address _spender, uint256 _value) external returns (bool success); 31 | 32 | /// @param _owner The address of the account owning tokens 33 | /// @param _spender The address of the account able to transfer the tokens 34 | /// @return remaining Amount of remaining tokens allowed to spent 35 | function allowance(address _owner, address _spender) external view returns (uint256 remaining); 36 | 37 | // solhint-disable-next-line no-simple-event-func-name 38 | event Transfer(address indexed _from, address indexed _to, uint256 _value); 39 | event Approval(address indexed _owner, address indexed _spender, uint256 _value); 40 | } -------------------------------------------------------------------------------- /gradle/spotless/formatter.properties: -------------------------------------------------------------------------------- 1 | #Whether to use 'space', 'tab' or 'mixed' (both) characters for indentation. 2 | #The default value is 'tab'. 3 | org.eclipse.jdt.core.formatter.tabulation.char=space 4 | 5 | #Whether or not indentation characters are inserted into empty lines. 6 | #The default value is 'true'. 7 | org.eclipse.jdt.core.formatter.indent_empty_lines=false 8 | 9 | #Length after which list are considered too long. These will be wrapped. 10 | #The default value is 30. 11 | groovy.formatter.longListLength=30 12 | 13 | #Whether opening braces position shall be the next line. 14 | #The default value is 'same'. 15 | groovy.formatter.braces.start=same 16 | 17 | #Whether closing braces position shall be the next line. 18 | #The default value is 'next'. 19 | groovy.formatter.braces.end=next 20 | 21 | #Remove unnecessary semicolons. The default value is 'false'. 22 | groovy.formatter.remove.unnecessary.semicolons=false 23 | 24 | org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line 25 | org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line 26 | org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line 27 | org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line 28 | org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line 29 | org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert 30 | org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line 31 | org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line 32 | org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line 33 | org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line 34 | org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert 35 | org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line 36 | org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line 37 | org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line 38 | 39 | org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert 40 | 41 | # Formatter can be buggy in CI 42 | ignoreFormatterProblems=true 43 | -------------------------------------------------------------------------------- /src/main/groovy/org/web3j/solidity/gradle/plugin/SolidityExtractImports.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 Web3 Labs Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package org.web3j.solidity.gradle.plugin 14 | 15 | import groovy.json.JsonBuilder 16 | import groovy.transform.CompileStatic 17 | import org.gradle.api.DefaultTask 18 | import org.gradle.api.file.ConfigurableFileCollection 19 | import org.gradle.api.file.RegularFileProperty 20 | import org.gradle.api.provider.Property 21 | import org.gradle.api.tasks.* 22 | 23 | @CacheableTask 24 | @CompileStatic 25 | abstract class SolidityExtractImports extends DefaultTask { 26 | 27 | @Input 28 | abstract Property getProjectName() 29 | 30 | @InputFiles 31 | @PathSensitive(value = PathSensitivity.RELATIVE) 32 | @SkipWhenEmpty 33 | abstract ConfigurableFileCollection getSources() 34 | 35 | @OutputFile 36 | abstract RegularFileProperty getPackageJson() 37 | 38 | SolidityExtractImports() { 39 | projectName.convention(project.name) 40 | } 41 | 42 | @TaskAction 43 | void resolveSolidity() { 44 | final Set packages = new TreeSet<>() 45 | 46 | sources.each { contract -> 47 | packages.addAll(ImportsResolver.extractImports(contract)) 48 | } 49 | 50 | final jsonMap = [ 51 | "name" : projectName.get(), 52 | "description" : "", 53 | "repository" : "", 54 | "license" : "UNLICENSED", 55 | "dependencies": packages.collectEntries { 56 | [(it): "latest"] 57 | } 58 | ] 59 | 60 | packageJson.get().asFile.text = new JsonBuilder(jsonMap).toPrettyString() 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /gradle/spotless/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | apply plugin: 'com.diffplug.spotless' 3 | apply plugin: 'de.undercouch.download' 4 | 5 | tasks.register('downloadJavaLicense', Download) { 6 | src 'https://raw.githubusercontent.com/LFDT-web3j/web3j-build-tools/main/gradle/spotless/java.license' 7 | dest new File("$rootDir/gradle/spotless",'java.license') 8 | quiet true 9 | //Download only if the file does not already exist 10 | onlyIf { 11 | !dest.exists() 12 | } 13 | onlyIfModified true 14 | } 15 | 16 | tasks.register('downloadFormatterProperties', Download) { 17 | src 'https://raw.githubusercontent.com/LFDT-web3j/web3j-build-tools/main/gradle/spotless/formatter.properties' 18 | dest new File("$rootDir/gradle/spotless",'formatter.properties') 19 | quiet true 20 | onlyIf { 21 | !dest.exists() 22 | } 23 | onlyIfModified true 24 | } 25 | 26 | spotless { 27 | java { 28 | // This path needs to be relative to each project 29 | target fileTree('.') { 30 | include '**/src/*/java/**/*.java' 31 | exclude '**/.gradle/**' 32 | exclude '**/generated/**' 33 | exclude '**/build/**' 34 | } 35 | removeUnusedImports() 36 | googleJavaFormat("1.17.0").aosp() 37 | importOrder 'java', '', 'org.web3j', '\\#' 38 | trimTrailingWhitespace() 39 | endWithNewline() 40 | licenseHeaderFile "$rootDir/gradle/spotless/java.license" 41 | } 42 | kotlin { 43 | // This path needs to be relative to each project 44 | target fileTree('.') { 45 | include '**/*.kt' 46 | exclude '**/.gradle/**' 47 | exclude '**/build/**' 48 | } 49 | ktlint('0.49.1') 50 | trimTrailingWhitespace() 51 | endWithNewline() 52 | licenseHeaderFile "$rootDir/gradle/spotless/java.license" 53 | } 54 | groovyGradle { 55 | target '*.gradle' 56 | greclipse().configFile("$rootDir/gradle/spotless/formatter.properties") 57 | endWithNewline() 58 | leadingTabsToSpaces(4) 59 | } 60 | } 61 | 62 | tasks.spotlessJava { 63 | dependsOn(tasks.compileGroovy, tasks.pluginDescriptors, tasks.processResources, tasks.spotlessGroovyGradle, 'spotlessGroovy') 64 | } 65 | 66 | tasks.spotlessKotlin { 67 | dependsOn(tasks.spotlessJava) 68 | } 69 | 70 | spotlessCheck.dependsOn('downloadJavaLicense', 'downloadFormatterProperties') 71 | -------------------------------------------------------------------------------- /src/main/groovy/org/web3j/solidity/gradle/plugin/DefaultSoliditySourceSet.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Web3 Labs Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package org.web3j.solidity.gradle.plugin 14 | 15 | import groovy.transform.CompileStatic 16 | import org.gradle.api.file.SourceDirectorySet 17 | import org.gradle.api.internal.file.DefaultSourceDirectorySet 18 | import org.gradle.api.internal.tasks.TaskDependencyFactory 19 | import org.gradle.api.model.ObjectFactory 20 | import org.gradle.api.reflect.HasPublicType 21 | import org.gradle.api.reflect.TypeOf 22 | 23 | import javax.inject.Inject 24 | 25 | /** 26 | * SoliditySourceSet default implementation. 27 | */ 28 | @CompileStatic 29 | abstract class DefaultSoliditySourceSet extends DefaultSourceDirectorySet implements SoliditySourceSet, HasPublicType { 30 | 31 | private final SourceDirectorySet allSolidity 32 | 33 | @Inject 34 | DefaultSoliditySourceSet( 35 | final SourceDirectorySet sourceDirectorySet, 36 | final SolidityExtension solidity, 37 | final ObjectFactory objectFactory, 38 | final TaskDependencyFactory taskDependencyFactory) { 39 | super(sourceDirectorySet, taskDependencyFactory); 40 | getFilter().include("**/*.sol") 41 | allSolidity = objectFactory.sourceDirectorySet("allSolidity", displayName) 42 | allSolidity.getFilter().include("**/*.sol") 43 | allSolidity.source(this) 44 | 45 | evmVersion.convention(solidity.evmVersion) 46 | version.convention(solidity.version) 47 | optimize.convention(solidity.optimize) 48 | optimizeRuns.convention(solidity.optimizeRuns) 49 | ignoreMissing.convention(solidity.ignoreMissing) 50 | } 51 | 52 | @Override 53 | SourceDirectorySet getAllSolidity() { 54 | return allSolidity 55 | } 56 | 57 | @Override 58 | TypeOf getPublicType() { 59 | return TypeOf.typeOf(SoliditySourceSet.class) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/groovy/org/web3j/solidity/gradle/plugin/SolidityExtension.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Web3 Labs Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package org.web3j.solidity.gradle.plugin 14 | 15 | import groovy.transform.CompileStatic 16 | import org.gradle.api.Project 17 | import org.gradle.api.provider.ListProperty 18 | import org.gradle.api.provider.MapProperty 19 | import org.gradle.api.provider.Property 20 | import org.gradle.api.provider.SetProperty 21 | 22 | import javax.inject.Inject 23 | 24 | /** 25 | * Extension for Solidity compilation options. 26 | */ 27 | @CompileStatic 28 | abstract class SolidityExtension { 29 | static final NAME = 'solidity' 30 | 31 | @Inject 32 | SolidityExtension() { 33 | optimize.convention(true) 34 | resolvePackages.convention(true) 35 | overwrite.convention(true) 36 | optimizeRuns.convention(0) 37 | prettyJson.convention(false) 38 | ignoreMissing.convention(false) 39 | outputComponents.convention([ 40 | OutputComponent.BIN, 41 | OutputComponent.ABI, 42 | OutputComponent.METADATA 43 | ]) 44 | combinedOutputComponents.convention([ 45 | CombinedOutputComponent.BIN, 46 | CombinedOutputComponent.BIN_RUNTIME, 47 | CombinedOutputComponent.SRCMAP, 48 | CombinedOutputComponent.SRCMAP_RUNTIME 49 | ]) 50 | } 51 | 52 | abstract Property getVersion() 53 | 54 | abstract Property getExecutable() 55 | 56 | abstract Property getOptimize() 57 | 58 | abstract Property getResolvePackages() 59 | 60 | abstract Property getOptimizeRuns() 61 | 62 | abstract Property getPrettyJson() 63 | 64 | abstract Property getOverwrite() 65 | 66 | abstract Property getIgnoreMissing() 67 | 68 | abstract SetProperty getAllowPaths() 69 | 70 | abstract MapProperty getPathRemappings() 71 | 72 | abstract Property getEvmVersion() 73 | 74 | abstract ListProperty getOutputComponents() 75 | 76 | abstract ListProperty getCombinedOutputComponents() 77 | } 78 | -------------------------------------------------------------------------------- /src/test/resources/solidity/minimal_forwarder/MinimalForwarder.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts (last updated v4.8.0) (metatx/MinimalForwarder.sol) 3 | 4 | pragma solidity 0.8.12; 5 | 6 | import "./ECDSA.sol"; 7 | import "./EIP712.sol"; 8 | 9 | /** 10 | * @dev Simple minimal forwarder to be used together with an ERC2771 compatible contract. See {ERC2771Context}. 11 | * 12 | * MinimalForwarder is mainly meant for testing, as it is missing features to be a good production-ready forwarder. This 13 | * contract does not intend to have all the properties that are needed for a sound forwarding system. A fully 14 | * functioning forwarding system with good properties requires more complexity. We suggest you look at other projects 15 | * such as the GSN which do have the goal of building a system like that. 16 | */ 17 | contract MinimalForwarder is EIP712 { 18 | using ECDSA for bytes32; 19 | 20 | struct ForwardRequest { 21 | address from; 22 | address to; 23 | uint256 value; 24 | uint256 gas; 25 | uint256 nonce; 26 | bytes data; 27 | } 28 | 29 | bytes32 private constant _TYPEHASH = 30 | keccak256("ForwardRequest(address from,address to,uint256 value,uint256 gas,uint256 nonce,bytes data)"); 31 | 32 | mapping(address => uint256) private _nonces; 33 | 34 | constructor() EIP712("MinimalForwarder", "0.0.1") {} 35 | 36 | function getNonce(address from) public view returns (uint256) { 37 | return _nonces[from]; 38 | } 39 | 40 | function verify(ForwardRequest calldata req, bytes calldata signature) public view returns (bool) { 41 | address signer = _hashTypedDataV4( 42 | keccak256(abi.encode(_TYPEHASH, req.from, req.to, req.value, req.gas, req.nonce, keccak256(req.data))) 43 | ).recover(signature); 44 | return _nonces[req.from] == req.nonce && signer == req.from; 45 | } 46 | 47 | function execute( 48 | ForwardRequest calldata req, 49 | bytes calldata signature 50 | ) public payable returns (bool, bytes memory) { 51 | require(verify(req, signature), "MinimalForwarder: signature does not match request"); 52 | _nonces[req.from] = req.nonce + 1; 53 | 54 | (bool success, bytes memory returndata) = req.to.call{gas: req.gas, value: req.value}( 55 | abi.encodePacked(req.data, req.from) 56 | ); 57 | 58 | // Validate that the relayer has sent enough gas for the call. 59 | // See https://ronan.eth.limo/blog/ethereum-gas-dangers/ 60 | if (gasleft() <= req.gas / 63) { 61 | // We explicitly trigger invalid opcode to consume all gas and bubble-up the effects, since 62 | // neither revert or assert consume all gas since Solidity 0.8.0 63 | // https://docs.soliditylang.org/en/v0.8.0/control-structures.html#panic-via-assert-and-error-via-require 64 | /// @solidity memory-safe-assembly 65 | assembly { 66 | invalid() 67 | } 68 | } 69 | 70 | return (success, returndata); 71 | } 72 | } -------------------------------------------------------------------------------- /src/test/resources/solidity/minimal_forwarder/Strings.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) 3 | 4 | pragma solidity 0.8.12; 5 | 6 | import "./Math.sol"; 7 | import "./SignedMath.sol"; 8 | 9 | /** 10 | * @dev String operations. 11 | */ 12 | library Strings { 13 | bytes16 private constant _SYMBOLS = "0123456789abcdef"; 14 | uint8 private constant _ADDRESS_LENGTH = 20; 15 | 16 | /** 17 | * @dev Converts a `uint256` to its ASCII `string` decimal representation. 18 | */ 19 | function toString(uint256 value) internal pure returns (string memory) { 20 | unchecked { 21 | uint256 length = Math.log10(value) + 1; 22 | string memory buffer = new string(length); 23 | uint256 ptr; 24 | /// @solidity memory-safe-assembly 25 | assembly { 26 | ptr := add(buffer, add(32, length)) 27 | } 28 | while (true) { 29 | ptr--; 30 | /// @solidity memory-safe-assembly 31 | assembly { 32 | mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) 33 | } 34 | value /= 10; 35 | if (value == 0) break; 36 | } 37 | return buffer; 38 | } 39 | } 40 | 41 | /** 42 | * @dev Converts a `int256` to its ASCII `string` decimal representation. 43 | */ 44 | function toString(int256 value) internal pure returns (string memory) { 45 | return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); 46 | } 47 | 48 | /** 49 | * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. 50 | */ 51 | function toHexString(uint256 value) internal pure returns (string memory) { 52 | unchecked { 53 | return toHexString(value, Math.log256(value) + 1); 54 | } 55 | } 56 | 57 | /** 58 | * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. 59 | */ 60 | function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { 61 | bytes memory buffer = new bytes(2 * length + 2); 62 | buffer[0] = "0"; 63 | buffer[1] = "x"; 64 | for (uint256 i = 2 * length + 1; i > 1; --i) { 65 | buffer[i] = _SYMBOLS[value & 0xf]; 66 | value >>= 4; 67 | } 68 | require(value == 0, "Strings: hex length insufficient"); 69 | return string(buffer); 70 | } 71 | 72 | /** 73 | * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. 74 | */ 75 | function toHexString(address addr) internal pure returns (string memory) { 76 | return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); 77 | } 78 | 79 | /** 80 | * @dev Returns true if the two strings are equal. 81 | */ 82 | function equal(string memory a, string memory b) internal pure returns (bool) { 83 | return keccak256(bytes(a)) == keccak256(bytes(b)); 84 | } 85 | } -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH= 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | # [0.7.0](https://github.com/LFDT-web3j/web3j-solidity-gradle-plugin/releases/tag/v0.7.0) (Upcoming) 7 | 8 | ### Bug Fixes 9 | 10 | * 11 | 12 | ### Features 13 | 14 | * Full Gradle 9 compatibility [#86](https://github.com/hyperledger/web3j-solidity-gradle-plugin/pull/86) 15 | * Full Gradle Configuration Cache compatibility [#86](https://github.com/hyperledger/web3j-solidity-gradle-plugin/pull/86) 16 | 17 | ### BREAKING CHANGES 18 | 19 | * The `solidity` DSL now uses [Gradle Properties/Providers](https://docs.gradle.org/current/userguide/properties_providers.html) for lazy configuration [#86](https://github.com/hyperledger/web3j-solidity-gradle-plugin/pull/86) 20 | 21 | # [0.6.0](https://github.com/LFDT-web3j/web3j-solidity-gradle-plugin/releases/tag/v0.6.0) (2025-04-09) 22 | 23 | ### Bug Fixes 24 | 25 | * 26 | 27 | ### Features 28 | 29 | * 30 | 31 | ### BREAKING CHANGES 32 | 33 | * Upgrade to java 21 and web3j-sockt 0.5.0 [#81](https://github.com/hyperledger-web3j/web3j-solidity-gradle-plugin/pull/81) 34 | 35 | # [0.5.2](https://github.com/hyperledger-web3j/web3j-solidity-gradle-plugin/releases/tag/v0.5.2) (2024-12-18) 36 | 37 | ### Bug Fixes 38 | 39 | * 40 | 41 | ### Features 42 | 43 | * allow Solidity imports from arbitrary npm packages [#78](https://github.com/hyperledger-web3j/web3j-solidity-gradle-plugin/pull/78) 44 | 45 | ### BREAKING CHANGES 46 | 47 | * 48 | 49 | # [0.5.1](https://github.com/web3j/solidity-gradle-plugin/releases/tag/v0.5.1) (2024-08-12) 50 | 51 | ### Bug Fixes 52 | 53 | * Fix `prettyJson = true` option [#75](https://github.com/hyperledger/web3j-solidity-gradle-plugin/pull/75) 54 | 55 | ### Features 56 | 57 | * 58 | 59 | ### BREAKING CHANGES 60 | 61 | * 62 | 63 | # [0.5.0](https://github.com/web3j/solidity-gradle-plugin/releases/tag/v0.5.0) (2024-05-23) 64 | 65 | ### Bug Fixes 66 | 67 | * NIL 68 | 69 | ### Features 70 | 71 | * Different solidity compile config for different sourceSets [#69](https://github.com/hyperledger/web3j-solidity-gradle-plugin/pull/69) 72 | * Added CANCUN evmVersion [#71](https://github.com/hyperledger/web3j-solidity-gradle-plugin/pull/71) 73 | 74 | ### BREAKING CHANGES 75 | 76 | * Upgrade to gradle 8.7 [#70](https://github.com/hyperledger/web3j-solidity-gradle-plugin/pull/70) 77 | 78 | # [0.4.1](https://github.com/web3j/solidity-gradle-plugin/releases/tag/v0.4.1) (2024-05-02) 79 | 80 | ### Bug Fixes 81 | 82 | * Gradle 8 compatibility [#67](https://github.com/hyperledger/web3j-solidity-gradle-plugin/pull/67) 83 | 84 | ### Features 85 | 86 | * Repo Migration required files [#66](https://github.com/hyperledger/web3j-solidity-gradle-plugin/pull/66) 87 | * Release version 0.4.1 and updated web3j-sokt to 0.3.0 [#68](https://github.com/web3j/solidity-gradle-plugin/pull/68) 88 | 89 | ### BREAKING CHANGES 90 | 91 | * NIL 92 | 93 | # [0.4.0](https://github.com/web3j/solidity-gradle-plugin/releases/tag/v0.4.0) (2023-06-16) 94 | 95 | ### Bug Fixes 96 | 97 | * NIL 98 | 99 | ### Features 100 | 101 | * Added shanghai evmVersion [#61](https://github.com/web3j/solidity-gradle-plugin/pull/61) 102 | * Bump version to 0.4.1-SNAPSHOT [#63](https://github.com/web3j/solidity-gradle-plugin/pull/63) 103 | 104 | ### BREAKING CHANGES 105 | 106 | * NIL -------------------------------------------------------------------------------- /src/test/resources/solidity/eip/EIP20.sol: -------------------------------------------------------------------------------- 1 | /* 2 | Implements EIP20 token standard: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md 3 | .*/ 4 | 5 | // SPDX-License-Identifier: Apache-2.0 6 | pragma solidity ^0.8.4; 7 | 8 | import "./EIP20Interface.sol"; 9 | 10 | 11 | contract EIP20 is EIP20Interface { 12 | 13 | /* This is a slight change to the ERC20 base standard. 14 | function totalSupply() constant returns (uint256 supply); 15 | is replaced with: 16 | uint256 public totalSupply; 17 | This automatically creates a getter function for the totalSupply. 18 | This is moved to the base contract since public getter functions are not 19 | currently recognised as an implementation of the matching abstract 20 | function by the compiler. 21 | */ 22 | uint256 public totalSupply; 23 | uint256 constant private MAX_UINT256 = 2**256 - 1; 24 | mapping (address => uint256) public balances; 25 | mapping (address => mapping (address => uint256)) public allowed; 26 | /* 27 | NOTE: 28 | The following variables are OPTIONAL vanities. One does not have to include them. 29 | They allow one to customise the token contract & in no way influences the core functionality. 30 | Some wallets/interfaces might not even bother to look at this information. 31 | */ 32 | 33 | string public name; //fancy name: eg Simon Bucks 34 | uint8 public decimals; //How many decimals to show. 35 | string public symbol; //An identifier: eg SBX 36 | 37 | constructor( 38 | uint256 _initialAmount, 39 | string memory _tokenName, 40 | uint8 _decimalUnits, 41 | string memory _tokenSymbol 42 | ) public { 43 | balances[msg.sender] = _initialAmount; // Give the creator all initial tokens 44 | totalSupply = _initialAmount; // Update total supply 45 | name = _tokenName; // Set the name for display purposes 46 | decimals = _decimalUnits; // Amount of decimals for display purposes 47 | symbol = _tokenSymbol; // Set the symbol for display purposes 48 | } 49 | 50 | function transfer(address _to, uint256 _value) external override returns (bool success) { 51 | require(balances[msg.sender] >= _value); 52 | balances[msg.sender] -= _value; 53 | balances[_to] += _value; 54 | emit Transfer(msg.sender, _to, _value); //solhint-disable-line indent, no-unused-vars 55 | return true; 56 | } 57 | 58 | function transferFrom(address _from, address _to, uint256 _value) external override returns (bool success) { 59 | uint256 allowance = allowed[_from][msg.sender]; 60 | require(balances[_from] >= _value && allowance >= _value); 61 | balances[_to] += _value; 62 | balances[_from] -= _value; 63 | if (allowance < MAX_UINT256) { 64 | allowed[_from][msg.sender] -= _value; 65 | } 66 | emit Transfer(_from, _to, _value); //solhint-disable-line indent, no-unused-vars 67 | return true; 68 | } 69 | 70 | function balanceOf(address _owner) external view override returns (uint256 balance) { 71 | return balances[_owner]; 72 | } 73 | 74 | function approve(address _spender, uint256 _value) external override returns (bool success) { 75 | allowed[msg.sender][_spender] = _value; 76 | emit Approval(msg.sender, _spender, _value); //solhint-disable-line indent, no-unused-vars 77 | return true; 78 | } 79 | 80 | function allowance(address _owner, address _spender) external view override returns (uint256 remaining) { 81 | return allowed[_owner][_spender]; 82 | } 83 | } -------------------------------------------------------------------------------- /src/main/groovy/org/web3j/solidity/gradle/plugin/ImportsResolver.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Web3 Labs Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package org.web3j.solidity.gradle.plugin 14 | 15 | import groovy.io.FileType 16 | 17 | import java.util.regex.Pattern 18 | 19 | /** 20 | * Helper class to resolve the external imports from a Solidity file. 21 | * 22 | * The import resolving is done in three steps: 23 | *
    24 | *
  • 25 | * First, all packages needed for direct imports are extracted from sol files to generate a package.json. 26 | * This is done in a separate Gradle task, so that the next steps are only performed when direct imports change. 27 | *
  • 28 | *
  • 29 | * Second, required packages are downloaded by npm. 30 | *
  • 31 | *
  • 32 | * Third, sol files that were downloaded are analyzed as well and all packages required are collected. 33 | * This information is used in compileSolidity for the allowed paths and the path remappings. 34 | *
  • 35 | *
36 | */ 37 | class ImportsResolver { 38 | 39 | private static final IMPORT_PROVIDER_PATTERN = Pattern.compile(".*import.*['\"](@[^/]+/[^/]+).*"); 40 | 41 | /** 42 | * Looks for external imports in Solidity files, eg: 43 | *
44 | *

45 | * 46 | * import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 47 | * 48 | *

49 | * 50 | * @param solFile where to search external imports 51 | * @param nodeProjectDir the Node.js project directory 52 | * @return 53 | */ 54 | static Set extractImports(final File solFile) { 55 | final Set imports = new TreeSet<>() 56 | 57 | solFile.readLines().each { String line -> 58 | final importProviderMatcher = IMPORT_PROVIDER_PATTERN.matcher(line) 59 | final importFound = importProviderMatcher.matches() 60 | if (importFound) { 61 | final provider = importProviderMatcher.group(1) 62 | imports.add(provider) 63 | } 64 | } 65 | 66 | return imports 67 | } 68 | 69 | static Set resolveTransitive(Set directImports, File nodeModulesDir) { 70 | final Set allImports = new TreeSet<>() 71 | if (directImports.isEmpty()) { 72 | return allImports 73 | } 74 | 75 | def transitiveResolved = 0 76 | allImports.addAll(directImports) 77 | 78 | while (transitiveResolved != allImports.size()) { 79 | transitiveResolved = allImports.size() 80 | allImports.collect().each { nodeModule -> 81 | final packageFolder = new File(nodeModulesDir, nodeModule) 82 | if (packageFolder.exists()) { // this may be a dev dependency from a test that we do not need 83 | packageFolder.eachFileRecurse(FileType.FILES) { dependencyFile -> 84 | if (dependencyFile.name.endsWith('.sol')) { 85 | allImports.addAll(extractImports(dependencyFile)) 86 | } 87 | } 88 | } 89 | } 90 | } 91 | 92 | return allImports 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/test/resources/solidity/minimal_forwarder/ShortStrings.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity 0.8.12; 4 | 5 | import "./StorageSlot.sol"; 6 | 7 | type ShortString is bytes32; 8 | 9 | /** 10 | * @dev This library provides functions to convert short memory strings 11 | * into a `ShortString` type that can be used as an immutable variable. 12 | * Strings of arbitrary length can be optimized if they are short enough by 13 | * the addition of a storage variable used as fallback. 14 | * 15 | * Usage example: 16 | * 17 | * ```solidity 18 | * contract Named { 19 | * using ShortStrings for *; 20 | * 21 | * ShortString private immutable _name; 22 | * string private _nameFallback; 23 | * 24 | * constructor(string memory contractName) { 25 | * _name = contractName.toShortStringWithFallback(_nameFallback); 26 | * } 27 | * 28 | * function name() external view returns (string memory) { 29 | * return _name.toStringWithFallback(_nameFallback); 30 | * } 31 | * } 32 | * ``` 33 | */ 34 | library ShortStrings { 35 | bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF; 36 | 37 | error StringTooLong(string str); 38 | error InvalidShortString(); 39 | 40 | /** 41 | * @dev Encode a string of at most 31 chars into a `ShortString`. 42 | * 43 | * This will trigger a `StringTooLong` error is the input string is too long. 44 | */ 45 | function toShortString(string memory str) internal pure returns (ShortString) { 46 | bytes memory bstr = bytes(str); 47 | if (bstr.length > 31) { 48 | revert StringTooLong(str); 49 | } 50 | return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length)); 51 | } 52 | 53 | /** 54 | * @dev Decode a `ShortString` back to a "normal" string. 55 | */ 56 | function toString(ShortString sstr) internal pure returns (string memory) { 57 | uint256 len = byteLength(sstr); 58 | // using `new string(len)` would work locally but is not memory safe. 59 | string memory str = new string(32); 60 | /// @solidity memory-safe-assembly 61 | assembly { 62 | mstore(str, len) 63 | mstore(add(str, 0x20), sstr) 64 | } 65 | return str; 66 | } 67 | 68 | /** 69 | * @dev Return the length of a `ShortString`. 70 | */ 71 | function byteLength(ShortString sstr) internal pure returns (uint256) { 72 | uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF; 73 | if (result > 31) { 74 | revert InvalidShortString(); 75 | } 76 | return result; 77 | } 78 | 79 | /** 80 | * @dev Encode a string into a `ShortString`, or write it to storage if it is too long. 81 | */ 82 | function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) { 83 | if (bytes(value).length < 32) { 84 | return toShortString(value); 85 | } else { 86 | StorageSlot.getStringSlot(store).value = value; 87 | return ShortString.wrap(_FALLBACK_SENTINEL); 88 | } 89 | } 90 | 91 | /** 92 | * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}. 93 | */ 94 | function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) { 95 | if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) { 96 | return toString(value); 97 | } else { 98 | return store; 99 | } 100 | } 101 | 102 | /** 103 | * @dev Return the length of a string that was encoded to `ShortString` or written to storage using {setWithFallback}. 104 | * 105 | * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of 106 | * actual characters as the UTF-8 encoding of a single character can span over multiple bytes. 107 | */ 108 | function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) { 109 | if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) { 110 | return byteLength(value); 111 | } else { 112 | return bytes(store).length; 113 | } 114 | } 115 | } -------------------------------------------------------------------------------- /src/test/resources/solidity/minimal_forwarder/StorageSlot.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol) 3 | // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. 4 | 5 | pragma solidity 0.8.12; 6 | 7 | /** 8 | * @dev Library for reading and writing primitive types to specific storage slots. 9 | * 10 | * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. 11 | * This library helps with reading and writing to such slots without the need for inline assembly. 12 | * 13 | * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. 14 | * 15 | * Example usage to set ERC1967 implementation slot: 16 | * ```solidity 17 | * contract ERC1967 { 18 | * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; 19 | * 20 | * function _getImplementation() internal view returns (address) { 21 | * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; 22 | * } 23 | * 24 | * function _setImplementation(address newImplementation) internal { 25 | * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); 26 | * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; 27 | * } 28 | * } 29 | * ``` 30 | * 31 | * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._ 32 | * _Available since v4.9 for `string`, `bytes`._ 33 | */ 34 | library StorageSlot { 35 | struct AddressSlot { 36 | address value; 37 | } 38 | 39 | struct BooleanSlot { 40 | bool value; 41 | } 42 | 43 | struct Bytes32Slot { 44 | bytes32 value; 45 | } 46 | 47 | struct Uint256Slot { 48 | uint256 value; 49 | } 50 | 51 | struct StringSlot { 52 | string value; 53 | } 54 | 55 | struct BytesSlot { 56 | bytes value; 57 | } 58 | 59 | /** 60 | * @dev Returns an `AddressSlot` with member `value` located at `slot`. 61 | */ 62 | function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { 63 | /// @solidity memory-safe-assembly 64 | assembly { 65 | r.slot := slot 66 | } 67 | } 68 | 69 | /** 70 | * @dev Returns an `BooleanSlot` with member `value` located at `slot`. 71 | */ 72 | function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { 73 | /// @solidity memory-safe-assembly 74 | assembly { 75 | r.slot := slot 76 | } 77 | } 78 | 79 | /** 80 | * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. 81 | */ 82 | function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { 83 | /// @solidity memory-safe-assembly 84 | assembly { 85 | r.slot := slot 86 | } 87 | } 88 | 89 | /** 90 | * @dev Returns an `Uint256Slot` with member `value` located at `slot`. 91 | */ 92 | function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { 93 | /// @solidity memory-safe-assembly 94 | assembly { 95 | r.slot := slot 96 | } 97 | } 98 | 99 | /** 100 | * @dev Returns an `StringSlot` with member `value` located at `slot`. 101 | */ 102 | function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { 103 | /// @solidity memory-safe-assembly 104 | assembly { 105 | r.slot := slot 106 | } 107 | } 108 | 109 | /** 110 | * @dev Returns an `StringSlot` representation of the string storage pointer `store`. 111 | */ 112 | function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { 113 | /// @solidity memory-safe-assembly 114 | assembly { 115 | r.slot := store.slot 116 | } 117 | } 118 | 119 | /** 120 | * @dev Returns an `BytesSlot` with member `value` located at `slot`. 121 | */ 122 | function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { 123 | /// @solidity memory-safe-assembly 124 | assembly { 125 | r.slot := slot 126 | } 127 | } 128 | 129 | /** 130 | * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. 131 | */ 132 | function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { 133 | /// @solidity memory-safe-assembly 134 | assembly { 135 | r.slot := store.slot 136 | } 137 | } 138 | } -------------------------------------------------------------------------------- /src/test/resources/solidity/minimal_forwarder/EIP712.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol) 3 | 4 | pragma solidity 0.8.12; 5 | 6 | import "./ECDSA.sol"; 7 | import "./ShortStrings.sol"; 8 | import "./IERC5267.sol"; 9 | 10 | /** 11 | * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. 12 | * 13 | * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, 14 | * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding 15 | * they need in their contracts using a combination of `abi.encode` and `keccak256`. 16 | * 17 | * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding 18 | * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA 19 | * ({_hashTypedDataV4}). 20 | * 21 | * The implementation of the domain separator was designed to be as efficient as possible while still properly updating 22 | * the chain id to protect against replay attacks on an eventual fork of the chain. 23 | * 24 | * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method 25 | * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. 26 | * 27 | * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain 28 | * separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the 29 | * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. 30 | * 31 | * _Available since v3.4._ 32 | * 33 | * @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment 34 | */ 35 | abstract contract EIP712 is IERC5267 { 36 | using ShortStrings for *; 37 | 38 | bytes32 private constant _TYPE_HASH = 39 | keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); 40 | 41 | // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to 42 | // invalidate the cached domain separator if the chain id changes. 43 | bytes32 private immutable _cachedDomainSeparator; 44 | uint256 private immutable _cachedChainId; 45 | address private immutable _cachedThis; 46 | 47 | ShortString private immutable _name; 48 | ShortString private immutable _version; 49 | string private _nameFallback; 50 | string private _versionFallback; 51 | 52 | bytes32 private immutable _hashedName; 53 | bytes32 private immutable _hashedVersion; 54 | 55 | /** 56 | * @dev Initializes the domain separator and parameter caches. 57 | * 58 | * The meaning of `name` and `version` is specified in 59 | * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: 60 | * 61 | * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. 62 | * - `version`: the current major version of the signing domain. 63 | * 64 | * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart 65 | * contract upgrade]. 66 | */ 67 | constructor(string memory name, string memory version) { 68 | _name = name.toShortStringWithFallback(_nameFallback); 69 | _version = version.toShortStringWithFallback(_versionFallback); 70 | _hashedName = keccak256(bytes(name)); 71 | _hashedVersion = keccak256(bytes(version)); 72 | 73 | _cachedChainId = block.chainid; 74 | _cachedDomainSeparator = _buildDomainSeparator(); 75 | _cachedThis = address(this); 76 | } 77 | 78 | /** 79 | * @dev Returns the domain separator for the current chain. 80 | */ 81 | function _domainSeparatorV4() internal view returns (bytes32) { 82 | if (address(this) == _cachedThis && block.chainid == _cachedChainId) { 83 | return _cachedDomainSeparator; 84 | } else { 85 | return _buildDomainSeparator(); 86 | } 87 | } 88 | 89 | function _buildDomainSeparator() private view returns (bytes32) { 90 | return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this))); 91 | } 92 | 93 | /** 94 | * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this 95 | * function returns the hash of the fully encoded EIP712 message for this domain. 96 | * 97 | * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: 98 | * 99 | * ```solidity 100 | * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( 101 | * keccak256("Mail(address to,string contents)"), 102 | * mailTo, 103 | * keccak256(bytes(mailContents)) 104 | * ))); 105 | * address signer = ECDSA.recover(digest, signature); 106 | * ``` 107 | */ 108 | function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { 109 | return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash); 110 | } 111 | 112 | /** 113 | * @dev See {EIP-5267}. 114 | */ 115 | function eip712Domain() 116 | public 117 | view 118 | virtual 119 | override 120 | returns ( 121 | bytes1 fields, 122 | string memory name, 123 | string memory version, 124 | uint256 chainId, 125 | address verifyingContract, 126 | bytes32 salt, 127 | uint256[] memory extensions 128 | ) 129 | { 130 | return ( 131 | hex"0f", // 01111 132 | _name.toStringWithFallback(_nameFallback), 133 | _version.toStringWithFallback(_versionFallback), 134 | block.chainid, 135 | address(this), 136 | bytes32(0), 137 | new uint256[](0) 138 | ); 139 | } 140 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Web3j Solidity Gradle Plugin 2 | ====================== 3 | 4 | Simple Gradle plugin used by the [Web3j plugin](https://github.com/web3j/web3j-gradle-plugin) 5 | to compile Solidity contracts, but it can be used in any standalone project for this purpose. 6 | 7 | ## Plugin configuration 8 | 9 | To configure the Solidity Gradle Plugin using the plugins DSL or the legacy plugin application, 10 | check the [plugin page](https://plugins.gradle.org/plugin/org.web3j.solidity). 11 | The minimum Gradle version to run the plugin is `7.+`. 12 | 13 | Then run this command from your project containing Solidity contracts: 14 | 15 | ``` 16 | ./gradlew build 17 | ``` 18 | 19 | After the task execution, the base directory for compiled code (by default 20 | `$buildDir/resources/solidity`) will contain a directory for each source set 21 | (by default `main` and `test`), and each of those a directory with the compiled code. 22 | 23 | 24 | ## Code generation 25 | 26 | The `solidity` DSL allows to configure the generated code, e.g.: 27 | 28 | ```groovy 29 | solidity { 30 | outputComponents = [BIN, ABI, ASM_JSON] 31 | optimizeRuns = 500 32 | } 33 | ``` 34 | 35 | The properties accepted by the DSL are listed in the following table: 36 | 37 | | Name | Type | Default value | Description | 38 | |----------------------------|:---------------------------:|:-------------------------------------------------:|-----------------------------------------------------------------| 39 | | `executable` | `String` | `null` (bundled with the plugin) | Solidity compiler path. | 40 | | `version` | `String` | `null` (defined by contract's pragma) | Solidity compiler version. | 41 | | `overwrite` | `Boolean` | `true` | Overwrite existing files. | 42 | | `resolvePackages` | `Boolean` | `true` | Resolve third-party contract packages. | 43 | | `optimize` | `Boolean` | `true` | Enable byte code optimizer. | 44 | | `optimizeRuns` | `Integer` | `200` | Set for how many contract runs to optimize. | 45 | | `prettyJson` | `Boolean` | `false` | Output JSON in pretty format. Enables the combined JSON output. | 46 | | `ignoreMissing` | `Boolean` | `false` | Ignore missing files. | 47 | | `allowPaths` | `List` | `['src/main/solidity', 'src/test/solidity', ...]` | Allow a given path for imports. | 48 | | `pathRemappings` | `Map` | `[ : ]` | Remaps contract imports to target path. | 49 | | `evmVersion` | `EVMVersion` | `BYZANTIUM` | Select desired EVM version. | 50 | | `outputComponents` | `OutputComponent[]` | `[BIN, ABI]` | List of output components to produce. | 51 | | `combinedOutputComponents` | `CombinedOutputComponent[]` | `[BIN, BIN_RUNTIME, SRCMAP, SRCMAP_RUNTIME]` | List of output components in combined JSON output. | 52 | 53 | **Notes:** 54 | 55 | * Setting the `executable` property will disable the bundled `solc` and use your local or containerized executable: 56 | 57 | ```groovy 58 | solidity { 59 | executable = "docker run --rm -v $projectDir/src:/src -v $projectDir/build:/build ethereum/solc:0.6.4-alpine" 60 | version = '0.4.15' 61 | } 62 | ``` 63 | 64 | * Use `version` to change the bundled Solidity version. 65 | Check the [Solidity releases](https://github.com/ethereum/solidity/releases) 66 | for all available versions. 67 | * `allowPaths` contains all project's Solidity source sets by default. 68 | 69 | ## Source sets 70 | 71 | By default, all `.sol` files in `$projectDir/src/main/solidity` and `$projectDir/src/test/solidity` will be processed by 72 | the plugin. To specify and add different source sets, use the `sourceSets` DSL. You can also set your preferred output 73 | directory for compiled code. 74 | 75 | ```groovy 76 | sourceSets { 77 | main { 78 | solidity { 79 | srcDir { 80 | "my/custom/path/to/solidity" 81 | } 82 | output.resourcesDir = file('out/bin/compiledSol') 83 | } 84 | } 85 | } 86 | ``` 87 | 88 | Now with solidity gradle plugin version 0.4.2, you can set different solidity versions, evmVersions, optimize flag, optimizeRuns and ignoreMissing 89 | flag values for different sourceSets. 90 | 91 | ```groovy 92 | sourceSets { 93 | main { 94 | solidity { 95 | srcDir { 96 | "my/custom/path/to/solidity" 97 | } 98 | output.resourcesDir = file('out/bin/compiledSol') 99 | evmVersion = 'ISTANBUL' 100 | optimize = true 101 | optimizeRuns = 200 102 | version = '0.8.12' 103 | } 104 | } 105 | } 106 | ``` 107 | 108 | ## Gradle Node Plugin 109 | 110 | The plugin makes use of the [Node plugin](https://github.com/node-gradle/gradle-node-plugin) to resolve third-party 111 | contract dependencies. It currently supports [Open Zeppelin](https://www.npmjs.com/package/@openzeppelin/contracts) 112 | and [Uniswap](https://www.npmjs.com/package/@uniswap/lib). 113 | 114 | When importing libraries from `@openzeppelin/contracts` in your Solidity contract, the plugin will use the 115 | task `resolveSolidity` to generate a `package.json` file required by 116 | the [Node plugin](https://github.com/node-gradle/gradle-node-plugin). 117 | 118 | By default, `package.json` will be generated under the `build/` directory. If you wish to change the directory for the 119 | Node plugin, add the following snippet to your `build.gradle` file: 120 | 121 | ``` 122 | node { 123 | nodeProjectDir = file("my/custom/node/directory") 124 | } 125 | ``` 126 | 127 | If it already exists, the plugin will keep the `package.json` file in that directory and will also download the node 128 | modules under the same directory. 129 | 130 | **Note:** In case of problems with the `package.json` file, you can delete it, and it will be regenerated with the 131 | latest versions. 132 | 133 | ## Plugin tasks 134 | 135 | The [Java Plugin](https://docs.gradle.org/current/userguide/java_plugin.html) 136 | adds tasks to your project build using a naming convention on a per source set basis 137 | (i.e. `compileJava`, `compileTestJava`). 138 | 139 | Similarly, the Solidity plugin will add the tasks: 140 | 141 | * `resolveSolidity` task for all project Solidity sources. 142 | * `compileSolidity` task for the project `main` source set. 143 | * `compileSolidity` for each remaining source set. (e.g. `compileTestSolidity` for the `test` source set, 144 | etc.). 145 | 146 | To obtain a list and description of all added tasks, run the command: 147 | 148 | ``` 149 | ./gradlew tasks --all 150 | ``` 151 | -------------------------------------------------------------------------------- /src/main/groovy/org/web3j/solidity/gradle/plugin/SolidityPlugin.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Web3 Labs Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package org.web3j.solidity.gradle.plugin 14 | 15 | import com.github.gradle.node.NodeExtension 16 | import com.github.gradle.node.NodePlugin 17 | import com.github.gradle.node.npm.task.NpmInstallTask 18 | import org.gradle.api.Plugin 19 | import org.gradle.api.Project 20 | import org.gradle.api.file.DirectoryProperty 21 | import org.gradle.api.file.RegularFile 22 | import org.gradle.api.plugins.JavaPlugin 23 | import org.gradle.api.provider.Provider 24 | import org.gradle.api.tasks.SourceSet 25 | import org.gradle.api.tasks.SourceSetContainer 26 | import org.gradle.language.jvm.tasks.ProcessResources 27 | 28 | import static org.codehaus.groovy.runtime.StringGroovyMethods.capitalize 29 | import static org.web3j.solidity.gradle.plugin.SoliditySourceSet.NAME 30 | 31 | /** 32 | * Gradle plugin for Solidity compile automation. 33 | */ 34 | class SolidityPlugin implements Plugin { 35 | 36 | @Override 37 | void apply(final Project project) { 38 | project.pluginManager.apply(JavaPlugin.class) 39 | project.pluginManager.apply(NodePlugin.class) 40 | project.extensions.create(SolidityExtension.NAME, SolidityExtension) 41 | 42 | // Set nodeProjectDir to 'build' before the node plugin evaluation 43 | def nodeExtension = project.extensions.getByName(NodeExtension.NAME) as NodeExtension 44 | nodeExtension.nodeProjectDir.set(project.layout.buildDirectory) 45 | nodeExtension.download.set(true) 46 | 47 | final sourceSets = project.extensions.getByType(SourceSetContainer.class) 48 | 49 | configureSolidityResolve(project, nodeExtension.nodeProjectDir) 50 | 51 | sourceSets.configureEach { SourceSet sourceSet -> 52 | configureAllowPath(project, sourceSet) 53 | configureSourceSet(project, sourceSet) 54 | configureSolidityCompile(project, sourceSet, nodeExtension.nodeProjectDir) 55 | } 56 | } 57 | 58 | private static void configureAllowPath(final Project project, final SourceSet sourceSet) { 59 | def solidity = project.extensions.getByType(SolidityExtension) 60 | def allowPath = project.layout.projectDirectory.dir("src/$sourceSet.name/$NAME") 61 | solidity.allowPaths.add(project.relativePath(allowPath.asFile)) 62 | } 63 | 64 | private static void configureSolidityResolve(Project project, DirectoryProperty nodeProjectDir) { 65 | def extractSolidityImports = project.tasks.register("extractSolidityImports", SolidityExtractImports) { 66 | it.description = "Extracts imports of external Solidity contract modules." 67 | it.packageJson.set(nodeProjectDir.file("package.json")) 68 | } 69 | def npmInstall = project.tasks.named(NpmInstallTask.NAME) { 70 | it.dependsOn(extractSolidityImports) 71 | } 72 | project.tasks.register("resolveSolidity", SolidityResolve) { 73 | it.description = "Resolve external Solidity contract modules." 74 | 75 | it.dependsOn(npmInstall) 76 | it.packageJson.set(nodeProjectDir.file("package.json")) 77 | it.nodeModules.set(nodeProjectDir.dir("node_modules")) 78 | 79 | it.allImports.set(project.layout.buildDirectory.file("sol-imports-all.txt")) 80 | } 81 | } 82 | 83 | /** 84 | * Add default source set for Solidity. 85 | */ 86 | private static void configureSourceSet(final Project project, final SourceSet sourceSet) { 87 | def solidity = project.extensions.getByType(SolidityExtension) 88 | 89 | def srcSetName = capitalize((CharSequence) sourceSet.name) 90 | def soliditySourceSet = project.objects.newInstance(DefaultSoliditySourceSet, 91 | project.objects.sourceDirectorySet(NAME, srcSetName + " Solidity Sources"), 92 | solidity) 93 | 94 | sourceSet.extensions.add(NAME, soliditySourceSet) 95 | 96 | def defaultSrcDir = project.layout.projectDirectory.dir("src/$sourceSet.name/$NAME") 97 | def defaultOutputDir = project.layout.buildDirectory.dir("solidity/$sourceSet.name/$NAME") 98 | 99 | soliditySourceSet.srcDir(defaultSrcDir) 100 | soliditySourceSet.destinationDirectory.set(defaultOutputDir) 101 | 102 | sourceSet.allJava.source(soliditySourceSet) 103 | sourceSet.allSource.source(soliditySourceSet) 104 | 105 | project.tasks.named("extractSolidityImports", SolidityExtractImports) { 106 | it.sources.from(soliditySourceSet) 107 | } 108 | } 109 | 110 | /** 111 | * Configures code compilation tasks for the Solidity source sets defined in the project 112 | * (e.g. main, test). 113 | *

114 | * By default the generated task name for the main source set 115 | * is compileSolidity and for test 116 | * compileTestSolidity. 117 | */ 118 | private static void configureSolidityCompile(final Project project, final SourceSet sourceSet, final DirectoryProperty nodeProjectDir) { 119 | def solidity = project.extensions.getByType(SolidityExtension) 120 | def soliditySourceSet = sourceSet.extensions.getByType(SoliditySourceSet) 121 | def resolveSolidity = project.tasks.named('resolveSolidity', SolidityResolve) 122 | 123 | def compileTask = project.tasks.register(sourceSet.getTaskName("compile", "Solidity"), SolidityCompile) { 124 | it.description = "Compiles $sourceSet.name Solidity source." 125 | 126 | it.source = soliditySourceSet 127 | it.destinationDirectory.convention(soliditySourceSet.destinationDirectory) 128 | it.destinationSubDirectory.convention("solidity") 129 | it.nodeModulesDir.convention(nodeProjectDir.dir("node_modules")) 130 | 131 | it.executable.convention(solidity.executable) 132 | it.pathRemappings.convention(solidity.pathRemappings) 133 | it.outputComponents.convention(solidity.outputComponents) 134 | it.combinedOutputComponents.convention(solidity.combinedOutputComponents) 135 | it.optimize.convention(solidity.optimize) 136 | it.overwrite.convention(solidity.overwrite) 137 | it.prettyJson.convention(solidity.prettyJson) 138 | it.allowPaths.convention(solidity.allowPaths) 139 | 140 | it.version.convention(soliditySourceSet.version) 141 | it.optimize.convention(soliditySourceSet.optimize) 142 | it.optimizeRuns.convention(soliditySourceSet.optimizeRuns) 143 | it.evmVersion.convention(soliditySourceSet.evmVersion) 144 | it.ignoreMissing.convention(soliditySourceSet.ignoreMissing) 145 | 146 | it.resolvedImports.set(solidity.resolvePackages.flatMap { 147 | it ? resolveSolidity.flatMap { it.allImports } : emptyImports(project) 148 | }) 149 | } 150 | 151 | project.tasks.named('processResources', ProcessResources) { 152 | it.from(compileTask) 153 | } 154 | } 155 | 156 | private static Provider emptyImports(Project project) { 157 | return project.provider { 158 | // Optional file input workaround: https://github.com/gradle/gradle/issues/2016 159 | // This is a provider that is only triggered when solidity.resolvePackages = false. 160 | def emptyImportsFile = project.layout.buildDirectory.file("sol-imports-empty.txt").get() 161 | emptyImportsFile.asFile.parentFile.mkdirs() 162 | emptyImportsFile.asFile.createNewFile() 163 | return emptyImportsFile 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/main/groovy/org/web3j/solidity/gradle/plugin/SolidityCompile.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Web3 Labs Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package org.web3j.solidity.gradle.plugin 14 | 15 | import groovy.transform.CompileStatic 16 | import org.gradle.api.file.DirectoryProperty 17 | import org.gradle.api.file.RegularFileProperty 18 | import org.gradle.api.provider.ListProperty 19 | import org.gradle.api.provider.MapProperty 20 | import org.gradle.api.provider.Property 21 | import org.gradle.api.provider.SetProperty 22 | import org.gradle.api.tasks.* 23 | import org.gradle.process.ExecOperations 24 | import org.web3j.sokt.SolcInstance 25 | import org.web3j.sokt.SolidityFile 26 | import org.web3j.sokt.VersionResolver 27 | 28 | import javax.inject.Inject 29 | import java.nio.file.Paths 30 | 31 | @CacheableTask 32 | @CompileStatic 33 | abstract class SolidityCompile extends SourceTask { 34 | 35 | @Input 36 | @Optional 37 | abstract Property getExecutable() 38 | 39 | @Input 40 | @Optional 41 | abstract Property getVersion() 42 | 43 | @Input 44 | abstract Property getOverwrite() 45 | 46 | @Input 47 | abstract Property getOptimize() 48 | 49 | @Input 50 | abstract Property getOptimizeRuns() 51 | 52 | @Input 53 | abstract Property getPrettyJson() 54 | 55 | @Input 56 | abstract Property getIgnoreMissing() 57 | 58 | @Input 59 | abstract SetProperty getAllowPaths() 60 | 61 | @Input 62 | abstract MapProperty getPathRemappings() 63 | 64 | @Input 65 | @Optional 66 | abstract Property getEvmVersion() 67 | 68 | @Input 69 | abstract ListProperty getOutputComponents() 70 | 71 | @Input 72 | abstract ListProperty getCombinedOutputComponents() 73 | 74 | @InputFile 75 | @PathSensitive(PathSensitivity.NONE) 76 | abstract RegularFileProperty getResolvedImports() 77 | 78 | @Input 79 | abstract Property getDestinationSubDirectory(); 80 | 81 | @OutputDirectory 82 | abstract DirectoryProperty getDestinationDirectory(); 83 | 84 | @Internal 85 | abstract DirectoryProperty getNodeModulesDir() 86 | 87 | @Inject 88 | protected abstract ExecOperations getExec(); 89 | 90 | @TaskAction 91 | void compileSolidity() { 92 | final imports = resolvedImports.get().asFile.readLines().findAll { !it.isEmpty() } 93 | 94 | for (def contract in source) { 95 | List options = [] 96 | 97 | for (output in outputComponents.get()) { 98 | options.add("--$output".toString()) 99 | } 100 | 101 | if (combinedOutputComponents.get().size() > 0) { 102 | options.add("--combined-json") 103 | options.add(combinedOutputComponents.get().join(",")) 104 | } 105 | 106 | if (optimize.get()) { 107 | options.add('--optimize') 108 | 109 | if (0 < optimizeRuns.get()) { 110 | options.add('--optimize-runs') 111 | options.add(optimizeRuns.get().toString()) 112 | } 113 | } 114 | 115 | if (overwrite.get()) { 116 | options.add('--overwrite') 117 | } 118 | 119 | if (prettyJson.get()) { 120 | options.add('--pretty-json') 121 | } 122 | 123 | if (ignoreMissing.get()) { 124 | options.add('--ignore-missing') 125 | } 126 | 127 | if (!allowPaths.get().isEmpty() || !imports.isEmpty()) { 128 | options.add("--allow-paths") 129 | options.add((allowPaths.get() + imports.collect { new File(nodeModulesDir.get().asFile, it).absolutePath }).join(',')) 130 | } 131 | 132 | pathRemappings.get().each { key, value -> 133 | options.add("$key=$value".toString()) 134 | } 135 | 136 | imports.each { provider -> 137 | options.add("$provider=${nodeModulesDir.get().asFile}/$provider".toString()) 138 | } 139 | 140 | options.add('--output-dir') 141 | if (destinationSubDirectory.isPresent()) { 142 | options.add(new File(destinationDirectory.get().asFile, destinationSubDirectory.get()).absolutePath) 143 | } else { 144 | options.add(destinationDirectory.get().asFile.absolutePath) 145 | } 146 | options.add(contract.absolutePath) 147 | 148 | def compilerVersion = version.getOrNull() 149 | def solidityFile = new SolidityFile(contract.absolutePath) 150 | String compilerExecutable = executable.getOrNull() 151 | SolcInstance compilerInstance 152 | 153 | if (compilerExecutable == null) { 154 | if (compilerVersion != null) { 155 | def resolvedVersion = new VersionResolver(".web3j").getSolcReleases().stream().filter { 156 | it.version == version.get() && it.isCompatibleWithOs() 157 | }.findAny().orElseThrow { 158 | return new Exception("Failed to resolve Solidity version $version from available versions. " + 159 | "You may need to use a custom executable instead.") 160 | } 161 | compilerInstance = new SolcInstance(resolvedVersion, ".web3j", false) 162 | } else { 163 | compilerInstance = solidityFile.getCompilerInstance(".web3j", true) 164 | compilerVersion = compilerInstance.solcRelease.version 165 | } 166 | 167 | if (compilerInstance.installed() || !compilerInstance.installed() && compilerInstance.install()) { 168 | compilerExecutable = compilerInstance.solcFile.getAbsolutePath() 169 | } 170 | } 171 | 172 | if (evmVersion.isPresent() && supportsEvmVersionOption(compilerVersion)) { 173 | options.add("--evm-version") 174 | options.add(evmVersion.get().value) 175 | } 176 | 177 | if (Paths.get(compilerExecutable).toFile().exists()) { 178 | // if the executable string is a file which exists, it may be a direct reference 179 | // to the solc executable with a space in the path (Windows) 180 | exec.exec { 181 | it.executable = compilerExecutable 182 | it.args = options 183 | } 184 | } else { 185 | // otherwise we assume it's a normal reference to solidity or docker, possibly with args 186 | def executableParts = compilerExecutable.split(' ') 187 | options.addAll(0, executableParts.drop(1)) 188 | exec.exec { 189 | // Use first part as executable 190 | it.executable = executableParts[0] 191 | // Use other parts and options as args 192 | it.args = options 193 | } 194 | } 195 | 196 | if (combinedOutputComponents.get().size() > 0) { 197 | def metajsonFile = new File(outputs.files.singleFile, "combined.json") 198 | def contractName = contract.getName() 199 | def newMetaName = contractName.substring(0, contractName.length() - 4) + ".json" 200 | 201 | metajsonFile.renameTo(new File(metajsonFile.getParentFile(), newMetaName)) 202 | } 203 | } 204 | } 205 | 206 | private static boolean supportsEvmVersionOption(String version) { 207 | return version.split('\\.').last().toInteger() >= 24 || version.split('\\.')[1].toInteger() > 4 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # [Hyperledger Code of Conduct](https://wiki.hyperledger.org/community/hyperledger-project-code-of-conduct) 2 | 3 | Hyperledger is a collaborative project at The Linux Foundation. It is an open-source and open 4 | community project where participants choose to work together, and in that process experience 5 | differences in language, location, nationality, and experience. In such a diverse environment, 6 | misunderstandings and disagreements happen, which in most cases can be resolved informally. In rare 7 | cases, however, behavior can intimidate, harass, or otherwise disrupt one or more people in the 8 | community, which Hyperledger will not tolerate. 9 | 10 | A **Code of Conduct** is useful to define accepted and acceptable behaviors and to promote high 11 | standards of professional practice. It also provides a benchmark for self evaluation and acts as a 12 | vehicle for better identity of the organization. 13 | 14 | This code (**CoC**) applies to any member of the Hyperledger community – developers, participants in 15 | meetings, teleconferences, mailing lists, conferences or functions, etc. Note that this code 16 | complements rather than replaces legal rights and obligations pertaining to any particular 17 | situation. 18 | 19 | ## Statement of Intent 20 | 21 | Hyperledger is committed to maintain a **positive** [work environment](#work-environment). This 22 | commitment calls for a workplace where [participants](#participant) at all levels behave according 23 | to the rules of the following code. A foundational concept of this code is that we all share 24 | responsibility for our work environment. 25 | 26 | ## Code 27 | 28 | 1. Treat each other with [respect](#respect), professionalism, fairness, and sensitivity to our many 29 | differences and strengths, including in situations of high pressure and urgency. 30 | 31 | 2. Never [harass](#harassment) or [bully](#workplace-bullying) anyone verbally, physically or 32 | [sexually](#sexual-harassment). 33 | 34 | 3. Never [discriminate](#discrimination) on the basis of personal characteristics or group 35 | membership. 36 | 37 | 4. Communicate constructively and avoid [demeaning](#demeaning-behavior) or 38 | [insulting](#insulting-behavior) behavior or language. 39 | 40 | 5. Seek, accept, and offer objective work criticism, and [acknowledge](#acknowledgement) properly 41 | the contributions of others. 42 | 43 | 6. Be honest about your own qualifications, and about any circumstances that might lead to conflicts 44 | of interest. 45 | 46 | 7. Respect the privacy of others and the confidentiality of data you access. 47 | 48 | 8. With respect to cultural differences, be conservative in what you do and liberal in what you 49 | accept from others, but not to the point of accepting disrespectful, unprofessional or unfair or 50 | [unwelcome behavior](#unwelcome-behavior) or [advances](#unwelcome-sexual-advance). 51 | 52 | 9. Promote the rules of this Code and take action (especially if you are in a 53 | [leadership position](#leadership-position)) to bring the discussion back to a more civil level 54 | whenever inappropriate behaviors are observed. 55 | 56 | 10. Stay on topic: Make sure that you are posting to the correct channel and avoid off-topic 57 | discussions. Remember when you update an issue or respond to an email you are potentially 58 | sending to a large number of people. 59 | 60 | 11. Step down considerately: Members of every project come and go, and the Hyperledger is no 61 | different. When you leave or disengage from the project, in whole or in part, we ask that you do 62 | so in a way that minimizes disruption to the project. This means you should tell people you are 63 | leaving and take the proper steps to ensure that others can pick up where you left off. 64 | 65 | ## Glossary 66 | 67 | ### Demeaning Behavior 68 | 69 | is acting in a way that reduces another person's dignity, sense of self-worth or respect within the 70 | community. 71 | 72 | ### Discrimination 73 | 74 | is the prejudicial treatment of an individual based on criteria such as: physical appearance, race, 75 | ethnic origin, genetic differences, national or social origin, name, religion, gender, sexual 76 | orientation, family or health situation, pregnancy, disability, age, education, wealth, domicile, 77 | political view, morals, employment, or union activity. 78 | 79 | ### Insulting Behavior 80 | 81 | is treating another person with scorn or disrespect. 82 | 83 | ### Acknowledgement 84 | 85 | is a record of the origin(s) and author(s) of a contribution. 86 | 87 | ### Harassment 88 | 89 | is any conduct, verbal or physical, that has the intent or effect of interfering with an individual, 90 | or that creates an intimidating, hostile, or offensive environment. 91 | 92 | ### Leadership Position 93 | 94 | includes group Chairs, project maintainers, staff members, and Board members. 95 | 96 | ### Participant 97 | 98 | includes the following persons: 99 | 100 | - Developers 101 | - Member representatives 102 | - Staff members 103 | - Anyone from the Public partaking in the Hyperledger work environment (e.g. contribute code, 104 | comment on our code or specs, email us, attend our conferences, functions, etc) 105 | 106 | ### Respect 107 | 108 | is the genuine consideration you have for someone (if only because of their status as participant in 109 | Hyperledger, like yourself), and that you show by treating them in a polite and kind way. 110 | 111 | ### Sexual Harassment 112 | 113 | includes visual displays of degrading sexual images, sexually suggestive conduct, offensive remarks 114 | of a sexual nature, requests for sexual favors, unwelcome physical contact, and sexual assault. 115 | 116 | ### Unwelcome Behavior 117 | 118 | Hard to define? Some questions to ask yourself are: 119 | 120 | - how would I feel if I were in the position of the recipient? 121 | - would my spouse, parent, child, sibling or friend like to be treated this way? 122 | - would I like an account of my behavior published in the organization's newsletter? 123 | - could my behavior offend or hurt other members of the work group? 124 | - could someone misinterpret my behavior as intentionally harmful or harassing? 125 | - would I treat my boss or a person I admire at work like that ? 126 | - Summary: if you are unsure whether something might be welcome or unwelcome, don't do it. 127 | 128 | ### Unwelcome Sexual Advance 129 | 130 | includes requests for sexual favors, and other verbal or physical conduct of a sexual nature, where: 131 | 132 | - submission to such conduct is made either explicitly or implicitly a term or condition of an 133 | individual's employment, 134 | - submission to or rejection of such conduct by an individual is used as a basis for employment 135 | decisions affecting the individual, 136 | - such conduct has the purpose or effect of unreasonably interfering with an individual's work 137 | performance or creating an intimidating hostile or offensive working environment. 138 | 139 | ### Workplace Bullying 140 | 141 | is a tendency of individuals or groups to use persistent aggressive or unreasonable behavior (e.g. 142 | verbal or written abuse, offensive conduct or any interference which undermines or impedes work) 143 | against a co-worker or any professional relations. 144 | 145 | ### Work Environment 146 | 147 | is the set of all available means of collaboration, including, but not limited to messages to 148 | mailing lists, private correspondence, Web pages, chat channels, phone and video teleconferences, 149 | and any kind of face-to-face meetings or discussions. 150 | 151 | ## Incident Procedure 152 | 153 | To report incidents or to appeal reports of incidents, send email to Mike Dolan 154 | (mdolan@linuxfoundation.org) or Angela Brown (angela@linuxfoundation.org). Please include any 155 | available relevant information, including links to any publicly accessible material relating to the 156 | matter. Every effort will be taken to ensure a safe and collegial environment in which to 157 | collaborate on matters relating to the Project. In order to protect the community, the Project 158 | reserves the right to take appropriate action, potentially including the removal of an individual 159 | from any and all participation in the project. The Project will work towards an equitable resolution 160 | in the event of a misunderstanding. 161 | 162 | ## Credits 163 | 164 | This code is based on the 165 | [W3C’s Code of Ethics and Professional Conduct](https://www.w3.org/Consortium/cepc) with some 166 | additions from the [Cloud Foundry](https://www.cloudfoundry.org/)‘s Code of Conduct. 167 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH="\\\"\\\"" 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | if ! command -v java >/dev/null 2>&1 137 | then 138 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 139 | 140 | Please set the JAVA_HOME variable in your environment to match the 141 | location of your Java installation." 142 | fi 143 | fi 144 | 145 | # Increase the maximum file descriptors if we can. 146 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 147 | case $MAX_FD in #( 148 | max*) 149 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 150 | # shellcheck disable=SC2039,SC3045 151 | MAX_FD=$( ulimit -H -n ) || 152 | warn "Could not query maximum file descriptor limit" 153 | esac 154 | case $MAX_FD in #( 155 | '' | soft) :;; #( 156 | *) 157 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 158 | # shellcheck disable=SC2039,SC3045 159 | ulimit -n "$MAX_FD" || 160 | warn "Could not set maximum file descriptor limit to $MAX_FD" 161 | esac 162 | fi 163 | 164 | # Collect all arguments for the java command, stacking in reverse order: 165 | # * args from the command line 166 | # * the main class name 167 | # * -classpath 168 | # * -D...appname settings 169 | # * --module-path (only if needed) 170 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 171 | 172 | # For Cygwin or MSYS, switch paths to Windows format before running java 173 | if "$cygwin" || "$msys" ; then 174 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 175 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 176 | 177 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 178 | 179 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 180 | for arg do 181 | if 182 | case $arg in #( 183 | -*) false ;; # don't mess with options #( 184 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 185 | [ -e "$t" ] ;; #( 186 | *) false ;; 187 | esac 188 | then 189 | arg=$( cygpath --path --ignore --mixed "$arg" ) 190 | fi 191 | # Roll the args list around exactly as many times as the number of 192 | # args, so each arg winds up back in the position where it started, but 193 | # possibly modified. 194 | # 195 | # NB: a `for` loop captures its iteration list before it begins, so 196 | # changing the positional parameters here affects neither the number of 197 | # iterations, nor the values presented in `arg`. 198 | shift # remove old arg 199 | set -- "$@" "$arg" # push replacement arg 200 | done 201 | fi 202 | 203 | 204 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 205 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 206 | 207 | # Collect all arguments for the java command: 208 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 209 | # and any embedded shellness will be escaped. 210 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 211 | # treated as '${Hostname}' itself on the command line. 212 | 213 | set -- \ 214 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 215 | -classpath "$CLASSPATH" \ 216 | -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ 217 | "$@" 218 | 219 | # Stop when "xargs" is not available. 220 | if ! command -v xargs >/dev/null 2>&1 221 | then 222 | die "xargs is not available" 223 | fi 224 | 225 | # Use "xargs" to parse quoted args. 226 | # 227 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 228 | # 229 | # In Bash we could simply go: 230 | # 231 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 232 | # set -- "${ARGS[@]}" "$@" 233 | # 234 | # but POSIX shell has neither arrays nor command substitution, so instead we 235 | # post-process each arg (as a line of input to sed) to backslash-escape any 236 | # character that might be a shell metacharacter, then use eval to reverse 237 | # that process (while maintaining the separation between arguments), and wrap 238 | # the whole thing up as a single "set" statement. 239 | # 240 | # This will of course break if any of these variables contains a newline or 241 | # an unmatched quote. 242 | # 243 | 244 | eval "set -- $( 245 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 246 | xargs -n1 | 247 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 248 | tr '\n' ' ' 249 | )" '"$@"' 250 | 251 | exec "$JAVACMD" "$@" 252 | -------------------------------------------------------------------------------- /src/test/resources/solidity/minimal_forwarder/ECDSA.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol) 3 | 4 | pragma solidity 0.8.12; 5 | 6 | import "./Strings.sol"; 7 | 8 | /** 9 | * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. 10 | * 11 | * These functions can be used to verify that a message was signed by the holder 12 | * of the private keys of a given address. 13 | */ 14 | library ECDSA { 15 | enum RecoverError { 16 | NoError, 17 | InvalidSignature, 18 | InvalidSignatureLength, 19 | InvalidSignatureS, 20 | InvalidSignatureV // Deprecated in v4.8 21 | } 22 | 23 | function _throwError(RecoverError error) private pure { 24 | if (error == RecoverError.NoError) { 25 | return; // no error: do nothing 26 | } else if (error == RecoverError.InvalidSignature) { 27 | revert("ECDSA: invalid signature"); 28 | } else if (error == RecoverError.InvalidSignatureLength) { 29 | revert("ECDSA: invalid signature length"); 30 | } else if (error == RecoverError.InvalidSignatureS) { 31 | revert("ECDSA: invalid signature 's' value"); 32 | } 33 | } 34 | 35 | /** 36 | * @dev Returns the address that signed a hashed message (`hash`) with 37 | * `signature` or error string. This address can then be used for verification purposes. 38 | * 39 | * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: 40 | * this function rejects them by requiring the `s` value to be in the lower 41 | * half order, and the `v` value to be either 27 or 28. 42 | * 43 | * IMPORTANT: `hash` _must_ be the result of a hash operation for the 44 | * verification to be secure: it is possible to craft signatures that 45 | * recover to arbitrary addresses for non-hashed data. A safe way to ensure 46 | * this is by receiving a hash of the original message (which may otherwise 47 | * be too long), and then calling {toEthSignedMessageHash} on it. 48 | * 49 | * Documentation for signature generation: 50 | * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] 51 | * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] 52 | * 53 | * _Available since v4.3._ 54 | */ 55 | function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { 56 | if (signature.length == 65) { 57 | bytes32 r; 58 | bytes32 s; 59 | uint8 v; 60 | // ecrecover takes the signature parameters, and the only way to get them 61 | // currently is to use assembly. 62 | /// @solidity memory-safe-assembly 63 | assembly { 64 | r := mload(add(signature, 0x20)) 65 | s := mload(add(signature, 0x40)) 66 | v := byte(0, mload(add(signature, 0x60))) 67 | } 68 | return tryRecover(hash, v, r, s); 69 | } else { 70 | return (address(0), RecoverError.InvalidSignatureLength); 71 | } 72 | } 73 | 74 | /** 75 | * @dev Returns the address that signed a hashed message (`hash`) with 76 | * `signature`. This address can then be used for verification purposes. 77 | * 78 | * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: 79 | * this function rejects them by requiring the `s` value to be in the lower 80 | * half order, and the `v` value to be either 27 or 28. 81 | * 82 | * IMPORTANT: `hash` _must_ be the result of a hash operation for the 83 | * verification to be secure: it is possible to craft signatures that 84 | * recover to arbitrary addresses for non-hashed data. A safe way to ensure 85 | * this is by receiving a hash of the original message (which may otherwise 86 | * be too long), and then calling {toEthSignedMessageHash} on it. 87 | */ 88 | function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { 89 | (address recovered, RecoverError error) = tryRecover(hash, signature); 90 | _throwError(error); 91 | return recovered; 92 | } 93 | 94 | /** 95 | * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. 96 | * 97 | * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] 98 | * 99 | * _Available since v4.3._ 100 | */ 101 | function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) { 102 | bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); 103 | uint8 v = uint8((uint256(vs) >> 255) + 27); 104 | return tryRecover(hash, v, r, s); 105 | } 106 | 107 | /** 108 | * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. 109 | * 110 | * _Available since v4.2._ 111 | */ 112 | function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { 113 | (address recovered, RecoverError error) = tryRecover(hash, r, vs); 114 | _throwError(error); 115 | return recovered; 116 | } 117 | 118 | /** 119 | * @dev Overload of {ECDSA-tryRecover} that receives the `v`, 120 | * `r` and `s` signature fields separately. 121 | * 122 | * _Available since v4.3._ 123 | */ 124 | function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) { 125 | // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature 126 | // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines 127 | // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most 128 | // signatures from current libraries generate a unique signature with an s-value in the lower half order. 129 | // 130 | // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value 131 | // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or 132 | // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept 133 | // these malleable signatures as well. 134 | if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { 135 | return (address(0), RecoverError.InvalidSignatureS); 136 | } 137 | 138 | // If the signature is valid (and not malleable), return the signer address 139 | address signer = ecrecover(hash, v, r, s); 140 | if (signer == address(0)) { 141 | return (address(0), RecoverError.InvalidSignature); 142 | } 143 | 144 | return (signer, RecoverError.NoError); 145 | } 146 | 147 | /** 148 | * @dev Overload of {ECDSA-recover} that receives the `v`, 149 | * `r` and `s` signature fields separately. 150 | */ 151 | function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { 152 | (address recovered, RecoverError error) = tryRecover(hash, v, r, s); 153 | _throwError(error); 154 | return recovered; 155 | } 156 | 157 | /** 158 | * @dev Returns an Ethereum Signed Message, created from a `hash`. This 159 | * produces hash corresponding to the one signed with the 160 | * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] 161 | * JSON-RPC method as part of EIP-191. 162 | * 163 | * See {recover}. 164 | */ 165 | function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) { 166 | // 32 is the length in bytes of hash, 167 | // enforced by the type signature above 168 | /// @solidity memory-safe-assembly 169 | assembly { 170 | mstore(0x00, "\x19Ethereum Signed Message:\n32") 171 | mstore(0x1c, hash) 172 | message := keccak256(0x00, 0x3c) 173 | } 174 | } 175 | 176 | /** 177 | * @dev Returns an Ethereum Signed Message, created from `s`. This 178 | * produces hash corresponding to the one signed with the 179 | * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] 180 | * JSON-RPC method as part of EIP-191. 181 | * 182 | * See {recover}. 183 | */ 184 | function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { 185 | return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); 186 | } 187 | 188 | /** 189 | * @dev Returns an Ethereum Signed Typed Data, created from a 190 | * `domainSeparator` and a `structHash`. This produces hash corresponding 191 | * to the one signed with the 192 | * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] 193 | * JSON-RPC method as part of EIP-712. 194 | * 195 | * See {recover}. 196 | */ 197 | function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) { 198 | /// @solidity memory-safe-assembly 199 | assembly { 200 | let ptr := mload(0x40) 201 | mstore(ptr, "\x19\x01") 202 | mstore(add(ptr, 0x02), domainSeparator) 203 | mstore(add(ptr, 0x22), structHash) 204 | data := keccak256(ptr, 0x42) 205 | } 206 | } 207 | 208 | /** 209 | * @dev Returns an Ethereum Signed Data with intended validator, created from a 210 | * `validator` and `data` according to the version 0 of EIP-191. 211 | * 212 | * See {recover}. 213 | */ 214 | function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { 215 | return keccak256(abi.encodePacked("\x19\x00", validator, data)); 216 | } 217 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/test/resources/solidity/minimal_forwarder/Math.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) 3 | 4 | pragma solidity 0.8.12; 5 | 6 | /** 7 | * @dev Standard math utilities missing in the Solidity language. 8 | */ 9 | library Math { 10 | enum Rounding { 11 | Down, // Toward negative infinity 12 | Up, // Toward infinity 13 | Zero // Toward zero 14 | } 15 | 16 | /** 17 | * @dev Returns the largest of two numbers. 18 | */ 19 | function max(uint256 a, uint256 b) internal pure returns (uint256) { 20 | return a > b ? a : b; 21 | } 22 | 23 | /** 24 | * @dev Returns the smallest of two numbers. 25 | */ 26 | function min(uint256 a, uint256 b) internal pure returns (uint256) { 27 | return a < b ? a : b; 28 | } 29 | 30 | /** 31 | * @dev Returns the average of two numbers. The result is rounded towards 32 | * zero. 33 | */ 34 | function average(uint256 a, uint256 b) internal pure returns (uint256) { 35 | // (a + b) / 2 can overflow. 36 | return (a & b) + (a ^ b) / 2; 37 | } 38 | 39 | /** 40 | * @dev Returns the ceiling of the division of two numbers. 41 | * 42 | * This differs from standard division with `/` in that it rounds up instead 43 | * of rounding down. 44 | */ 45 | function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { 46 | // (a + b - 1) / b can overflow on addition, so we distribute. 47 | return a == 0 ? 0 : (a - 1) / b + 1; 48 | } 49 | 50 | /** 51 | * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 52 | * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) 53 | * with further edits by Uniswap Labs also under MIT license. 54 | */ 55 | function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { 56 | unchecked { 57 | // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use 58 | // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 59 | // variables such that product = prod1 * 2^256 + prod0. 60 | uint256 prod0; // Least significant 256 bits of the product 61 | uint256 prod1; // Most significant 256 bits of the product 62 | assembly { 63 | let mm := mulmod(x, y, not(0)) 64 | prod0 := mul(x, y) 65 | prod1 := sub(sub(mm, prod0), lt(mm, prod0)) 66 | } 67 | 68 | // Handle non-overflow cases, 256 by 256 division. 69 | if (prod1 == 0) { 70 | // Solidity will revert if denominator == 0, unlike the div opcode on its own. 71 | // The surrounding unchecked block does not change this fact. 72 | // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. 73 | return prod0 / denominator; 74 | } 75 | 76 | // Make sure the result is less than 2^256. Also prevents denominator == 0. 77 | require(denominator > prod1, "Math: mulDiv overflow"); 78 | 79 | /////////////////////////////////////////////// 80 | // 512 by 256 division. 81 | /////////////////////////////////////////////// 82 | 83 | // Make division exact by subtracting the remainder from [prod1 prod0]. 84 | uint256 remainder; 85 | assembly { 86 | // Compute remainder using mulmod. 87 | remainder := mulmod(x, y, denominator) 88 | 89 | // Subtract 256 bit number from 512 bit number. 90 | prod1 := sub(prod1, gt(remainder, prod0)) 91 | prod0 := sub(prod0, remainder) 92 | } 93 | 94 | // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. 95 | // See https://cs.stackexchange.com/q/138556/92363. 96 | 97 | // Does not overflow because the denominator cannot be zero at this stage in the function. 98 | uint256 twos = denominator & (~denominator + 1); 99 | assembly { 100 | // Divide denominator by twos. 101 | denominator := div(denominator, twos) 102 | 103 | // Divide [prod1 prod0] by twos. 104 | prod0 := div(prod0, twos) 105 | 106 | // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. 107 | twos := add(div(sub(0, twos), twos), 1) 108 | } 109 | 110 | // Shift in bits from prod1 into prod0. 111 | prod0 |= prod1 * twos; 112 | 113 | // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such 114 | // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for 115 | // four bits. That is, denominator * inv = 1 mod 2^4. 116 | uint256 inverse = (3 * denominator) ^ 2; 117 | 118 | // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works 119 | // in modular arithmetic, doubling the correct bits in each step. 120 | inverse *= 2 - denominator * inverse; // inverse mod 2^8 121 | inverse *= 2 - denominator * inverse; // inverse mod 2^16 122 | inverse *= 2 - denominator * inverse; // inverse mod 2^32 123 | inverse *= 2 - denominator * inverse; // inverse mod 2^64 124 | inverse *= 2 - denominator * inverse; // inverse mod 2^128 125 | inverse *= 2 - denominator * inverse; // inverse mod 2^256 126 | 127 | // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. 128 | // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is 129 | // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 130 | // is no longer required. 131 | result = prod0 * inverse; 132 | return result; 133 | } 134 | } 135 | 136 | /** 137 | * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. 138 | */ 139 | function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { 140 | uint256 result = mulDiv(x, y, denominator); 141 | if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { 142 | result += 1; 143 | } 144 | return result; 145 | } 146 | 147 | /** 148 | * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. 149 | * 150 | * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). 151 | */ 152 | function sqrt(uint256 a) internal pure returns (uint256) { 153 | if (a == 0) { 154 | return 0; 155 | } 156 | 157 | // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. 158 | // 159 | // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have 160 | // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. 161 | // 162 | // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` 163 | // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` 164 | // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` 165 | // 166 | // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. 167 | uint256 result = 1 << (log2(a) >> 1); 168 | 169 | // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, 170 | // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at 171 | // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision 172 | // into the expected uint128 result. 173 | unchecked { 174 | result = (result + a / result) >> 1; 175 | result = (result + a / result) >> 1; 176 | result = (result + a / result) >> 1; 177 | result = (result + a / result) >> 1; 178 | result = (result + a / result) >> 1; 179 | result = (result + a / result) >> 1; 180 | result = (result + a / result) >> 1; 181 | return min(result, a / result); 182 | } 183 | } 184 | 185 | /** 186 | * @notice Calculates sqrt(a), following the selected rounding direction. 187 | */ 188 | function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { 189 | unchecked { 190 | uint256 result = sqrt(a); 191 | return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); 192 | } 193 | } 194 | 195 | /** 196 | * @dev Return the log in base 2, rounded down, of a positive value. 197 | * Returns 0 if given 0. 198 | */ 199 | function log2(uint256 value) internal pure returns (uint256) { 200 | uint256 result = 0; 201 | unchecked { 202 | if (value >> 128 > 0) { 203 | value >>= 128; 204 | result += 128; 205 | } 206 | if (value >> 64 > 0) { 207 | value >>= 64; 208 | result += 64; 209 | } 210 | if (value >> 32 > 0) { 211 | value >>= 32; 212 | result += 32; 213 | } 214 | if (value >> 16 > 0) { 215 | value >>= 16; 216 | result += 16; 217 | } 218 | if (value >> 8 > 0) { 219 | value >>= 8; 220 | result += 8; 221 | } 222 | if (value >> 4 > 0) { 223 | value >>= 4; 224 | result += 4; 225 | } 226 | if (value >> 2 > 0) { 227 | value >>= 2; 228 | result += 2; 229 | } 230 | if (value >> 1 > 0) { 231 | result += 1; 232 | } 233 | } 234 | return result; 235 | } 236 | 237 | /** 238 | * @dev Return the log in base 2, following the selected rounding direction, of a positive value. 239 | * Returns 0 if given 0. 240 | */ 241 | function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { 242 | unchecked { 243 | uint256 result = log2(value); 244 | return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); 245 | } 246 | } 247 | 248 | /** 249 | * @dev Return the log in base 10, rounded down, of a positive value. 250 | * Returns 0 if given 0. 251 | */ 252 | function log10(uint256 value) internal pure returns (uint256) { 253 | uint256 result = 0; 254 | unchecked { 255 | if (value >= 10 ** 64) { 256 | value /= 10 ** 64; 257 | result += 64; 258 | } 259 | if (value >= 10 ** 32) { 260 | value /= 10 ** 32; 261 | result += 32; 262 | } 263 | if (value >= 10 ** 16) { 264 | value /= 10 ** 16; 265 | result += 16; 266 | } 267 | if (value >= 10 ** 8) { 268 | value /= 10 ** 8; 269 | result += 8; 270 | } 271 | if (value >= 10 ** 4) { 272 | value /= 10 ** 4; 273 | result += 4; 274 | } 275 | if (value >= 10 ** 2) { 276 | value /= 10 ** 2; 277 | result += 2; 278 | } 279 | if (value >= 10 ** 1) { 280 | result += 1; 281 | } 282 | } 283 | return result; 284 | } 285 | 286 | /** 287 | * @dev Return the log in base 10, following the selected rounding direction, of a positive value. 288 | * Returns 0 if given 0. 289 | */ 290 | function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { 291 | unchecked { 292 | uint256 result = log10(value); 293 | return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); 294 | } 295 | } 296 | 297 | /** 298 | * @dev Return the log in base 256, rounded down, of a positive value. 299 | * Returns 0 if given 0. 300 | * 301 | * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. 302 | */ 303 | function log256(uint256 value) internal pure returns (uint256) { 304 | uint256 result = 0; 305 | unchecked { 306 | if (value >> 128 > 0) { 307 | value >>= 128; 308 | result += 16; 309 | } 310 | if (value >> 64 > 0) { 311 | value >>= 64; 312 | result += 8; 313 | } 314 | if (value >> 32 > 0) { 315 | value >>= 32; 316 | result += 4; 317 | } 318 | if (value >> 16 > 0) { 319 | value >>= 16; 320 | result += 2; 321 | } 322 | if (value >> 8 > 0) { 323 | result += 1; 324 | } 325 | } 326 | return result; 327 | } 328 | 329 | /** 330 | * @dev Return the log in base 256, following the selected rounding direction, of a positive value. 331 | * Returns 0 if given 0. 332 | */ 333 | function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { 334 | unchecked { 335 | uint256 result = log256(value); 336 | return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); 337 | } 338 | } 339 | } -------------------------------------------------------------------------------- /src/test/groovy/org/web3j/solidity/gradle/plugin/SolidityPluginTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Web3 Labs Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 5 | * the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 10 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | * specific language governing permissions and limitations under the License. 12 | */ 13 | package org.web3j.solidity.gradle.plugin 14 | 15 | import org.gradle.testkit.runner.BuildResult 16 | import org.gradle.testkit.runner.GradleRunner 17 | import org.junit.jupiter.api.BeforeAll 18 | import org.junit.jupiter.api.BeforeEach 19 | import org.junit.jupiter.api.Disabled 20 | import org.junit.jupiter.api.Test 21 | 22 | import java.nio.file.Files 23 | import java.nio.file.Path 24 | import java.nio.file.Paths 25 | import java.nio.file.StandardCopyOption 26 | 27 | import static org.gradle.testkit.runner.TaskOutcome.SUCCESS 28 | import static org.gradle.testkit.runner.TaskOutcome.UP_TO_DATE 29 | import static org.junit.jupiter.api.Assertions.assertEquals 30 | import static org.junit.jupiter.api.Assertions.assertTrue 31 | 32 | class SolidityPluginTest { 33 | final static String gradleVersionUnderTest = System.getProperty("gradleVersionUnderTest") 34 | 35 | /** 36 | * Gradle project directory where the test project will be run. 37 | * Has to be under /tmp because of Docker file sharing defaults. 38 | */ 39 | private Path testProjectDir 40 | 41 | /** 42 | * Folder containing Solidity smart contracts with different versions. 43 | */ 44 | private final String differentVersionsFolderName = "different_versions" 45 | 46 | /** 47 | * Solidity sources directory. 48 | */ 49 | private static Path sourcesDir 50 | 51 | /** 52 | * Gradle build file. 53 | */ 54 | private Path buildFile 55 | 56 | @BeforeAll 57 | static void setUp() throws Exception { 58 | final def resource = SolidityPlugin.getClassLoader().getResource('solidity/eip/EIP20.sol') 59 | sourcesDir = Paths.get(resource.toURI()).getParent().getParent() 60 | } 61 | 62 | @BeforeEach 63 | void setup() throws IOException { 64 | testProjectDir = Files.createTempDirectory("testProjectDir") 65 | buildFile = Files.createFile(testProjectDir.resolve('build.gradle')) 66 | Files.createDirectories(testProjectDir.resolve('src/main/solidity')) 67 | Files.walk(sourcesDir).forEach { 68 | if (Files.isRegularFile(it)) { 69 | // Copy .sol files into temp folder for Docker 70 | final def fileName = sourcesDir.relativize(it).toString() 71 | final def file = testProjectDir.resolve("src/main/solidity/$fileName") 72 | Files.createDirectories(file.getParent()) 73 | Files.copy(it, file, StandardCopyOption.REPLACE_EXISTING) 74 | } 75 | } 76 | } 77 | 78 | @Test 79 | void compileSolidity() { 80 | Files.writeString(buildFile, """ 81 | plugins { 82 | id 'org.web3j.solidity' 83 | } 84 | sourceSets { 85 | main { 86 | solidity { 87 | exclude "minimal_forwarder/**" 88 | exclude "eip/**" 89 | exclude "greeter/**" 90 | exclude "common/**" 91 | exclude "openzeppelin/**" 92 | exclude "$differentVersionsFolderName/**" 93 | } 94 | } 95 | } 96 | """) 97 | 98 | def success = build() 99 | assertEquals(SUCCESS, success.task(":compileSolidity").getOutcome()) 100 | 101 | def compiledSolDir = testProjectDir.resolve("build/resources/main/solidity") 102 | assertTrue(Files.exists(compiledSolDir.resolve("Greeter.abi"))) 103 | assertTrue(Files.exists(compiledSolDir.resolve("Greeter.bin"))) 104 | assertTrue(Files.exists(compiledSolDir.resolve("Greeter_meta.json"))) 105 | 106 | def upToDate = build() 107 | assertEquals(UP_TO_DATE, upToDate.task(":compileSolidity").getOutcome()) 108 | } 109 | 110 | @Test 111 | void compileSolidityWithLibraryImports() throws IOException { 112 | Files.writeString(buildFile, """ 113 | plugins { 114 | id 'org.web3j.solidity' 115 | } 116 | node { 117 | nodeProjectDir = file("\$project.rootDir/test") 118 | } 119 | sourceSets { 120 | main { 121 | solidity { 122 | exclude "minimal_forwarder/**" 123 | exclude "sol5/**" 124 | exclude "common/**" 125 | exclude "eip/**" 126 | exclude "$differentVersionsFolderName/**" 127 | exclude "greeter/**" 128 | } 129 | } 130 | } 131 | """) 132 | 133 | def success = build() 134 | assertEquals(SUCCESS, success.task(":compileSolidity").getOutcome()) 135 | 136 | def compiledSolDir = testProjectDir.resolve("build/resources/main/solidity") 137 | assertTrue(Files.exists(compiledSolDir.resolve("MyCollectible.abi"))) 138 | assertTrue(Files.exists(compiledSolDir.resolve("MyCollectible.bin"))) 139 | assertTrue(Files.exists(compiledSolDir.resolve("ERC721.abi"))) 140 | assertTrue(Files.exists(compiledSolDir.resolve("MyOFT.abi"))) 141 | assertTrue(Files.exists(compiledSolDir.resolve("MyOFT.bin"))) 142 | 143 | def upToDate = build() 144 | assertEquals(UP_TO_DATE, upToDate.task(":compileSolidity").getOutcome()) 145 | assertEquals(UP_TO_DATE, upToDate.task(":resolveSolidity").getOutcome()) 146 | } 147 | 148 | @Test 149 | void compileSolidityWithVersion() throws IOException { 150 | Files.writeString(buildFile, """ 151 | plugins { 152 | id 'org.web3j.solidity' 153 | } 154 | solidity { 155 | version = '0.8.7' 156 | } 157 | sourceSets { 158 | main { 159 | solidity { 160 | exclude "minimal_forwarder/**" 161 | exclude "sol5/**" 162 | exclude "greeter/**" 163 | exclude "common/**" 164 | exclude "openzeppelin/**" 165 | exclude "$differentVersionsFolderName/**" 166 | } 167 | } 168 | } 169 | """) 170 | 171 | def success = build() 172 | assertEquals(SUCCESS, success.task(":compileSolidity").getOutcome()) 173 | 174 | def compiledSolDir = testProjectDir.resolve("build/resources/main/solidity") 175 | assertTrue(Files.exists(compiledSolDir.resolve("EIP20.abi"))) 176 | assertTrue(Files.exists(compiledSolDir.resolve("EIP20.bin"))) 177 | 178 | def upToDate = build() 179 | assertEquals(UP_TO_DATE, upToDate.task(":compileSolidity").getOutcome()) 180 | } 181 | 182 | @Test 183 | void compileSolidityWithEvmVersion() throws IOException { 184 | Files.writeString(buildFile, """ 185 | plugins { 186 | id 'org.web3j.solidity' 187 | } 188 | solidity { 189 | evmVersion = 'ISTANBUL' 190 | } 191 | sourceSets { 192 | main { 193 | solidity { 194 | exclude "sol5/**" 195 | exclude "eip/**" 196 | exclude "greeter/**" 197 | exclude "common/**" 198 | exclude "openzeppelin/**" 199 | exclude "$differentVersionsFolderName/**" 200 | } 201 | } 202 | } 203 | """) 204 | 205 | def success = build() 206 | assertEquals(SUCCESS, success.task(":compileSolidity").getOutcome()) 207 | 208 | def compiledSolDir = testProjectDir.resolve("build/resources/main/solidity") 209 | assertTrue(Files.exists(compiledSolDir.resolve("MinimalForwarder.abi"))) 210 | assertTrue(Files.exists(compiledSolDir.resolve("MinimalForwarder.bin"))) 211 | 212 | def upToDate = build() 213 | assertEquals(UP_TO_DATE, upToDate.task(":compileSolidity").getOutcome()) 214 | } 215 | 216 | @Test 217 | void compileSolidityWithSourceSetsSpecificConfig() throws IOException { 218 | Files.writeString(buildFile, """ 219 | plugins { 220 | id 'org.web3j.solidity' 221 | } 222 | 223 | sourceSets { 224 | main { 225 | solidity { 226 | exclude "sol5/**" 227 | exclude "eip/**" 228 | exclude "greeter/**" 229 | exclude "common/**" 230 | exclude "openzeppelin/**" 231 | exclude "$differentVersionsFolderName/**" 232 | 233 | setEvmVersion('ISTANBUL') 234 | setOptimize(true) 235 | setOptimizeRuns(200) 236 | setVersion('0.8.12') 237 | } 238 | } 239 | } 240 | """) 241 | 242 | def success = build() 243 | assertEquals(SUCCESS, success.task(":compileSolidity").getOutcome()) 244 | 245 | def compiledSolDir = testProjectDir.resolve("build/resources/main/solidity") 246 | assertTrue(Files.exists(compiledSolDir.resolve("MinimalForwarder.abi"))) 247 | assertTrue(Files.exists(compiledSolDir.resolve("MinimalForwarder.bin"))) 248 | 249 | def upToDate = build() 250 | assertEquals(UP_TO_DATE, upToDate.task(":compileSolidity").getOutcome()) 251 | } 252 | 253 | @Test 254 | @Disabled("Requires a specific solc version on the machine to pass") 255 | void compileSolidityWithExecutable() throws IOException { 256 | Files.writeString(buildFile, """ 257 | plugins { 258 | id 'org.web3j.solidity' 259 | } 260 | solidity { 261 | executable = 'solc' 262 | } 263 | sourceSets { 264 | main { 265 | solidity { 266 | exclude "minimal_forwarder/**" 267 | exclude "sol5/**" 268 | exclude "greeter/**" 269 | exclude "common/**" 270 | exclude "openzeppelin/**" 271 | exclude "$differentVersionsFolderName/**" 272 | } 273 | } 274 | } 275 | """) 276 | 277 | def success = build() 278 | assertEquals(SUCCESS, success.task(":compileSolidity").getOutcome()) 279 | 280 | def compiledSolDir = testProjectDir.resolve("build/resources/main/solidity") 281 | assertTrue(Files.exists(compiledSolDir.resolve("EIP20.abi"))) 282 | assertTrue(Files.exists(compiledSolDir.resolve("EIP20.bin"))) 283 | 284 | def upToDate = build() 285 | assertEquals(UP_TO_DATE, upToDate.task(":compileSolidity").getOutcome()) 286 | } 287 | 288 | @Test 289 | @Disabled("This is cool but fails if docker is not running. // Needs to be solved in the CI") 290 | void compileSolidityWithDocker() throws IOException { 291 | Files.writeString(buildFile, """ 292 | plugins { 293 | id 'org.web3j.solidity' 294 | } 295 | sourceSets { 296 | main { 297 | solidity { 298 | exclude "minimal_forwarder/**" 299 | exclude "sol5/**" 300 | exclude "eip/**" 301 | exclude "openzeppelin/**" 302 | exclude "$differentVersionsFolderName/**" 303 | } 304 | } 305 | } 306 | solidity { 307 | executable = 'docker run --rm -v \$testProjectDir.root:/src satran004/aion-fastvm:0.3.1 solc' 308 | allowPaths = ['/src/src/main/solidity'] 309 | version = '0.4.15' 310 | } 311 | """) 312 | 313 | def success = build() 314 | assertEquals(SUCCESS, success.task(":compileSolidity").getOutcome()) 315 | 316 | def compiledSolDir = testProjectDir.resolve("build/resources/main/solidity") 317 | assertTrue(Files.exists(compiledSolDir.resolve("Greeter.abi"))) 318 | assertTrue(Files.exists(compiledSolDir.resolve("Greeter.bin"))) 319 | 320 | def upToDate = build() 321 | assertEquals(UP_TO_DATE, upToDate.task(":compileSolidity").getOutcome()) 322 | } 323 | 324 | @Test 325 | void compileSolidityWithDifferentVersions() throws IOException { 326 | Files.writeString(buildFile, """ 327 | plugins { 328 | id 'org.web3j.solidity' 329 | } 330 | sourceSets { 331 | main { 332 | solidity { 333 | exclude "minimal_forwarder/**" 334 | exclude "eip/**" 335 | exclude "greeter/**" 336 | exclude "common/**" 337 | exclude "sol5/**" 338 | exclude "openzeppelin/**" 339 | } 340 | } 341 | } 342 | """) 343 | 344 | def success = build() 345 | assertEquals(SUCCESS, success.task(":compileSolidity").getOutcome()) 346 | } 347 | 348 | private BuildResult build() { 349 | return GradleRunner.create() 350 | .withProjectDir(testProjectDir.toFile()) 351 | .withArguments("build", "--info", "-s", "--configuration-cache") 352 | .withPluginClasspath() 353 | .forwardOutput().with { 354 | gradleVersionUnderTest? it.withGradleVersion(gradleVersionUnderTest) : it 355 | }.build() 356 | } 357 | } 358 | --------------------------------------------------------------------------------