commit
7d4f61b056
@ -0,0 +1,19 @@ |
||||
# Contract Verification Plugin |
||||
|
||||
With this plugin, contracts written and compiled in Remix can be verified at Sourcify, Etherscan, Blockscout and Routescan at the same time. Besides that, the source code of any address can be fetched from the verifiers and added to the file editor. |
||||
|
||||
## Adding a new verification service |
||||
|
||||
Currently, the plugin supports Sourcify, Etherscan, Blockscout and Routescan. To add a new verifier, you need to make the following changes: |
||||
|
||||
In `./src/app/types/VerificationTypes.ts`, add the new verifier to the `VerifierIdentifier` type and the`VERIFIERS` array. |
||||
|
||||
In order to interact with the API of the verification service, you need to create a new class that extends the `AbstractVerifier` class. If your API is based on the Etherscan API, you can simply extend the `EtherscanVerifier` class. In this case, see the `RoutescanVerifier` and the `BlockscoutVerifier` for reference. All related classes are located in the `./src/app/Verifiers` directory. |
||||
|
||||
In `./src/app/Verifiers/index.ts`, add your new verifier to the `getVerifier` function. Validate any settings properties that are required by your verifier. |
||||
|
||||
In `./src/app/utils/default-apis.json`, you need to add default settings for your new verifier. If you can, simply add your defaults in the form of `{ [VerifierIdentifier]: { [chainId]: { apiUrl: [value], explorerUrl: [value] } } }`. If you need more flexibility, you might also want to change the `src/app/utils/default-settings.ts` file. See Routescan there for reference. |
||||
|
||||
Your new verifier will automatically be shown in the `VerifyView` and the `LookupView` since we added it to the `VERIFIERS` array. You only need to make a change to the `SettingsView` because the required settings depend on the verifier. There, add a new div block in the same format as the other verifiers. Only add the `ConfigInput` elements for the settings that your verifier needs to the div block. |
||||
|
||||
That's it! Your verification service should be able to verify contracts through Remix now. |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,154 @@ |
||||
'use strict' |
||||
import { NightwatchBrowser } from 'nightwatch' |
||||
import init from '../helpers/init' |
||||
|
||||
declare global { |
||||
interface Window { testplugin: { name: string, url: string }; } |
||||
} |
||||
|
||||
const tests = { |
||||
'@disabled': true, |
||||
before: function (browser: NightwatchBrowser, done: VoidFunction) { |
||||
init(browser, done, null) |
||||
}, |
||||
|
||||
'Should show fork and delete VM state icons #group1': function (browser: NightwatchBrowser) { |
||||
browser |
||||
.clickLaunchIcon('udapp') |
||||
.waitForElementVisible('*[data-id="selected-provider-vm-cancun"]') |
||||
.waitForElementVisible('*[data-id="fork-state-icon"]') |
||||
.waitForElementVisible('*[data-id="delete-state-icon"]') |
||||
}, |
||||
'Should show toaster while trying fork and delete VM state without state #group1': function (browser: NightwatchBrowser) { |
||||
browser |
||||
.waitForElementVisible('*[data-id="fork-state-icon"]') |
||||
.click('*[data-id="fork-state-icon"]') |
||||
.waitForElementVisible( |
||||
{ |
||||
selector: "//*[@data-shared='tooltipPopup' and contains(.,'State not available to fork')]", |
||||
locateStrategy: 'xpath' |
||||
} |
||||
) |
||||
.waitForElementVisible('*[data-id="delete-state-icon"]') |
||||
.click('*[data-id="delete-state-icon"]') |
||||
.waitForElementVisible( |
||||
{ |
||||
selector: "//*[@data-shared='tooltipPopup' and contains(.,'State not available to reset')]", |
||||
locateStrategy: 'xpath' |
||||
} |
||||
) |
||||
}, |
||||
'Should fork state successfully #group1': function (browser: NightwatchBrowser) { |
||||
browser |
||||
.openFile('contracts') |
||||
.openFile('contracts/1_Storage.sol') |
||||
.verifyContracts(['Storage']) |
||||
.clickLaunchIcon('udapp') |
||||
.click('[data-id="Deploy - transact (not payable)"]') |
||||
.clickInstance(0) |
||||
.clickFunction('store - transact (not payable)', { types: 'uint256 num', values: '"55"' }) |
||||
.testFunction('last', |
||||
{ |
||||
status: '0x1 Transaction mined and execution succeed', |
||||
'decoded input': { 'uint256 num': '55' } |
||||
}) |
||||
.clickFunction('retrieve - call') |
||||
.testFunction('last', |
||||
{ |
||||
'decoded output': { '0': 'uint256: 55' } |
||||
}) |
||||
.click('*[data-id="fork-state-icon"]') |
||||
.waitForElementVisible('*[data-id="udappNotifyModalDialogModalTitle-react"]') |
||||
.click('input[data-id="modalDialogForkState"]') |
||||
.setValue('input[data-id="modalDialogForkState"]', 'forkedState_1') |
||||
.modalFooterOKClick('udappNotify') |
||||
// check toaster for forked state
|
||||
.waitForElementVisible( |
||||
{ |
||||
selector: '//*[@data-shared="tooltipPopup" and contains(.,"New environment \'forkedState_1\' created with forked state.")]', |
||||
locateStrategy: 'xpath' |
||||
} |
||||
) |
||||
// check if forked state is selected as current environment
|
||||
.assert.elementPresent('*[data-id="selected-provider-vm-fs-forkedState_1"]') |
||||
// check if forked state file is created with expected details
|
||||
.openFile('.states/forked_states/forkedState_1.json') |
||||
.getEditorValue((content) => { |
||||
browser.assert.ok(content.indexOf(`"latestBlockNumber": "0x2"`) !== -1) |
||||
browser.assert.ok(content.indexOf(`"stateName": "forkedState_1"`) !== -1) |
||||
browser.assert.ok(content.indexOf(`"forkName": "cancun"`) !== -1) |
||||
browser.assert.ok(content.indexOf(`"savingTimestamp":`) !== -1) |
||||
browser.assert.ok(content.indexOf(`"db":`) !== -1) |
||||
browser.assert.ok(content.indexOf(`"blocks":`) !== -1) |
||||
}) |
||||
}, |
||||
'Should show fork states provider in environment explorer & make txs using forked state #group1': function (browser: NightwatchBrowser) { |
||||
browser |
||||
.clickLaunchIcon('udapp') |
||||
.waitForElementVisible('[data-id="settingsSelectEnvOptions"]') |
||||
.click('[data-id="settingsSelectEnvOptions"] button') |
||||
.waitForElementVisible(`[data-id="dropdown-item-another-chain"]`) |
||||
.click(`[data-id="dropdown-item-another-chain"]`) |
||||
.assert.visible('[data-id="remixUIGSDeploy to an In-browser Forked State."]') |
||||
.assert.elementPresent('[data-id="remixUIGSforkedState_1"]') |
||||
.assert.elementPresent('[data-id="vm-fs-forkedState_1-pinned"]') |
||||
.assert.textContains('[data-id="vm-fs-forkedState_1desc"]', 'Latest Block: 2') |
||||
.assert.not.elementPresent('[data-id="remixUIGSforkedState_2"]') |
||||
.switchEnvironment('vm-cancun') |
||||
.openFile('contracts/1_Storage.sol') |
||||
.verifyContracts(['Storage']) |
||||
.clickLaunchIcon('udapp') |
||||
.click('*[data-id="Deploy - transact (not payable)"]') |
||||
.click('*[data-id="fork-state-icon"]') |
||||
.waitForElementVisible('*[data-id="udappNotifyModalDialogModalTitle-react"]') |
||||
.click('input[data-id="modalDialogForkState"]') |
||||
.setValue('input[data-id="modalDialogForkState"]', 'forkedState_2') |
||||
.modalFooterOKClick('udappNotify') |
||||
.waitForElementVisible('*[data-shared="tooltipPopup"]', 10000) |
||||
.assert.textContains('*[data-shared="tooltipPopup"]', `New environment 'forkedState_2' created with forked state.`) |
||||
// check if 'forkedState_2' is selected as current environment
|
||||
.assert.elementPresent('*[data-id="selected-provider-vm-fs-forkedState_2"]') |
||||
// check if 'forkedState_2' is present in environment explorer
|
||||
.assert.elementPresent('[data-id="remixUIGSforkedState_2"]') |
||||
// check if 'forkedState_2' is pinned in environment explorer
|
||||
.assert.elementPresent('[data-id="vm-fs-forkedState_2-pinned"]') |
||||
// 'forkedState_2' should have 3 blocks
|
||||
.assert.textContains('[data-id="vm-fs-forkedState_2desc"]', 'Latest Block: 3') |
||||
.click('*[data-id="Deploy - transact (not payable)"]') |
||||
.clickInstance(0) |
||||
.clickFunction('store - transact (not payable)', { types: 'uint256 num', values: '"555"' }) |
||||
// block number should be 5 after 2 txs
|
||||
.testFunction('last', |
||||
{ |
||||
status: '0x1 Transaction mined and execution succeed', |
||||
'block number': '5', |
||||
'decoded input': { 'uint256 num': '555' } |
||||
}) |
||||
}, |
||||
'Should delete state successfully #group1': function (browser: NightwatchBrowser) { |
||||
browser |
||||
.switchEnvironment('vm-cancun') |
||||
.openFile('contracts/1_Storage.sol') |
||||
.verifyContracts(['Storage']) |
||||
.clickLaunchIcon('udapp') |
||||
.click('*[data-id="Deploy - transact (not payable)"]') |
||||
.pause(10000) |
||||
.assert.textContains('*[data-id="deployedContractsBadge"]', '1') |
||||
.click(('*[data-id="delete-state-icon"]')) |
||||
.waitForElementVisible('*[data-id="udappNotifyModalDialogModalTitle-react"]') |
||||
.waitForElementVisible('*[data-id="deleteVmStateModal"]') |
||||
.modalFooterOKClick('udappNotify') |
||||
.waitForElementVisible('*[data-shared="tooltipPopup"]', 10000) |
||||
// check if toaster is shown
|
||||
.assert.textContains('*[data-shared="tooltipPopup"]', `VM state reset successfully.`) |
||||
// check that there are no instances
|
||||
.assert.textContains('*[data-id="deployedContractsBadge"]', '0') |
||||
// check if state file is deleted
|
||||
.openFile('.states/vm-cancun') |
||||
.assert.not.elementPresent('*[data-id="treeViewDivDraggableItem.states/vm-cancun/state.json"]') |
||||
} |
||||
} |
||||
|
||||
module.exports = { |
||||
...tests |
||||
}; |
2
apps/remix-ide/contracts/node_modules/openzeppelin-solidity/contracts/sample.sol
generated
vendored
2
apps/remix-ide/contracts/node_modules/openzeppelin-solidity/contracts/sample.sol
generated
vendored
@ -1 +1 @@ |
||||
import "https://github.com/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; contract test11 {} |
||||
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol"; contract test11 {} |
||||
|
@ -1,5 +1,5 @@ |
||||
.EECellStyle { |
||||
min-height: 6rem; |
||||
min-height: 8rem; |
||||
max-width: 12rem; |
||||
min-width: 10rem; |
||||
min-width: 12rem; |
||||
} |
||||
|
@ -0,0 +1,30 @@ |
||||
{ |
||||
"contract-verification.verifyNavTitle": "Verify", |
||||
"contract-verification.receiptsNavTitle": "Receipts", |
||||
"contract-verification.lookupNavTitle": "Lookup", |
||||
"contract-verification.settingsNavTitle": "Settings", |
||||
"contract-verification.contractAddressInput": "Contract Address", |
||||
"contract-verification.proxyContractAddressInput": "Proxy Address", |
||||
"contract-verification.proxyInputLabel": "The deployed contract is behind a proxy", |
||||
"contract-verification.panelDisplayName": "Contract Verification", |
||||
"contract-verification.searchableChainDropdownLabel": "Chain", |
||||
"contract-verification.contractAddressError": "Please enter a valid contract address", |
||||
"contract-verification.chainError": "Please select the chain.", |
||||
"contract-verification.proxyAddressError": "Please provide a valid proxy contract address.", |
||||
"contract-verification.verifyButton": "Verify", |
||||
"contract-verification.lookupButton": "Lookup", |
||||
"contract-verification.receipts.noContractsSubmitted": "No contracts submitted for verification", |
||||
"contract-verification.receiptsDefaultLayout.description": "Check the verification statuses of contracts submitted for verification", |
||||
"contract-verification.verifyDefaultLayout.description": "Verify compiled contracts on different verification services", |
||||
"contract-verification.lookupDefaultLayout.description": "Search for verified contracts and download them to Remix", |
||||
"contract-verification.settingsDefaultLayout.description": "Customize settings for each verification service and chain", |
||||
"contract-verification.configInputPlaceholderText": "Add {label}", |
||||
"contract-verification.configInputSaveButton": "Save", |
||||
"contract-verification.configInputCancelButton": "Cancel", |
||||
"contract-verification.constructorArgumentsToggleRawInput": "Enter raw ABI-encoded constructor arguments", |
||||
"contract-verification.constructorArgumentsRawAbiEncodingResult": "ABI-encoded constructor arguments", |
||||
"contract-verification.contractDropdownLabel": "{label}", |
||||
"contract-verification.contractDropDownDefaultText": "Compiled contract required" |
||||
} |
||||
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 132 KiB |
Before Width: | Height: | Size: 16 KiB |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue