Skip to content

Commit

Permalink
Merge the develop branch to the master branch, preparation to v2.0.0-rc4
Browse files Browse the repository at this point in the history
This update for the master branch contains the following set of changes:
  * [Improvement] Multi part contract verification in Etherscan and Blockscout (#35)
  * [Improvement] Robust way of using TransferSingle mint for first mint ever (#36)
  • Loading branch information
akolotov authored May 29, 2021
2 parents 9702180 + ce49881 commit fbe208a
Show file tree
Hide file tree
Showing 21 changed files with 979 additions and 256 deletions.
19 changes: 14 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
types: [created]

jobs:
flats:
source:
runs-on: ubuntu-latest
steps:
- id: get_release
Expand All @@ -23,13 +23,22 @@ jobs:
key: ${{ runner.os }}-node_modules-${{ hashFiles('**/yarn.lock') }}
- run: yarn
if: ${{ !steps.yarn-cache.outputs.cache-hit }}
- run: yarn flatten
- run: zip flats $(find flats -name '*.sol')
- run: yarn compile
- run: zip contracts $(find contracts -name '*.sol')
- run: zip artifacts $(find build -name '*.json')
- uses: actions/[email protected]
env:
GITHUB_TOKEN: ${{ github.token }}
with:
upload_url: ${{ steps.get_release.outputs.upload_url }}
asset_path: flats.zip
asset_name: omnibridge-nft-contracts-flattened-${{ steps.get_release.outputs.tag_name }}.zip
asset_path: contracts.zip
asset_name: omnibridge-nft-contracts-${{ steps.get_release.outputs.tag_name }}.zip
asset_content_type: application/zip
- uses: actions/[email protected]
env:
GITHUB_TOKEN: ${{ github.token }}
with:
upload_url: ${{ steps.get_release.outputs.upload_url }}
asset_path: artifacts.zip
asset_name: omnibridge-nft-artifacts-${{ steps.get_release.outputs.tag_name }}.zip
asset_content_type: application/zip
4 changes: 0 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ COPY truffle-config.js truffle-config.js
COPY ./contracts ./contracts
RUN yarn compile

COPY flatten.sh flatten.sh
RUN yarn flatten

FROM node:14

WORKDIR /contracts
Expand All @@ -20,7 +17,6 @@ COPY package.json yarn.lock ./
RUN yarn install --prod

COPY --from=contracts /contracts/build ./build
COPY --from=contracts /contracts/flats ./flats

COPY deploy.sh deploy.sh
COPY ./deploy ./deploy
Expand Down
3 changes: 0 additions & 3 deletions Dockerfile.dev
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ COPY truffle-config.js truffle-config.js
COPY ./contracts ./contracts
RUN yarn compile

COPY flatten.sh flatten.sh
RUN yarn flatten

COPY deploy.sh deploy.sh
COPY ./deploy ./deploy
COPY ./test ./test
Expand Down
25 changes: 23 additions & 2 deletions contracts/tokens/ERC1155BridgeToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ contract ERC1155BridgeToken is ERC1155, IBurnableMintableERC1155Token {

address public bridgeContract;

bool private hasAlreadyMinted;

constructor(
string memory _name,
string memory _symbol,
Expand Down Expand Up @@ -78,7 +80,26 @@ contract ERC1155BridgeToken is ERC1155, IBurnableMintableERC1155Token {
uint256[] memory _tokenIds,
uint256[] memory _values
) external override onlyBridge {
_mintBatch(_to, _tokenIds, _values, new bytes(0));
if (_tokenIds.length == 1 && _values.length == 1) {
_mint(_to, _tokenIds[0], _values[0], new bytes(0));
} else {
// Next few lines ensure that the first mint ever happened in his token contract will performed using TransferSingle event
// Otherwise, NFT marketplaces have issues with indexing bridged token data.
// On first mint ever (when hasAlreadyMinted is false), last token id from the list is minted using TransferSingle.
// All over tokens from the list are minted using TransferBatch event.
// All subsequent operations will always use TransferBatch for operations involving more than 1 token id.
if (!hasAlreadyMinted) {
require(_tokenIds.length > 1 && _tokenIds.length == _values.length);
uint256 len = _tokenIds.length - 1;
_mint(_to, _tokenIds[len], _values[len], new bytes(0));
assembly {
mstore(_tokenIds, len) // _tokenIds.pop()
mstore(_values, len) // _values.pop()
}
}
_mintBatch(_to, _tokenIds, _values, new bytes(0));
}
hasAlreadyMinted = true;
}

/**
Expand Down Expand Up @@ -149,6 +170,6 @@ contract ERC1155BridgeToken is ERC1155, IBurnableMintableERC1155Token {
uint64 patch
)
{
return (1, 0, 1);
return (1, 1, 0);
}
}
72 changes: 72 additions & 0 deletions deploy/VERIFICATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
## Process

Due to usage of `pragma abicoder v2;` in the contracts source code,
it is not possible to verify contracts through flattened source files.

Instead, two different approaches can be used for Etherscan and Blockscout explorers.

## Verification in Etherscan/Bscscan

The simplest semi-automated solution found so far is to use `truffle-plugin-verify` and the corresponding shell script.
First, collect information about deployed contracts from the logs for the particular chain in the following format:

Example of deployed contracts list in the Foreign chain:
```
EternalStorageProxy@0xEc05e3f4D845f0E39e33146395aCE5D35c01Fcc0
ERC721BridgeToken@0xd880d9d42Fad3dcbe885F499AE15822ACBF1f1F8
ERC1155BridgeToken@0xaa5cF36b6d97a709fccF3fd4BEa94dA9753d9cA4
ForeignNFTOmnibridge@0x964C086398cba3c0BaE520bE900E660a84cA331c
```

Example of deployed contracts list in the Home chain:
```
EternalStorageProxy@0x2c0bF58cC87763783e35a625ff6a3e50d9E05337
ERC721BridgeToken@0x714c7985B073b1177356560631A30D24F60f9241
ERC1155BridgeToken@0xB2bf0271DB0d30090756A25B01be2698f3E5e556
OwnedUpgradeabilityProxy@0x4dCD4Dd4096eab35611D496087ceF7DaF1D4E57C
SelectorTokenGasLimitManager@0x783A53aC5ab27d24E83A0211e6Ff70c3705a5435
HomeNFTOmnibridge@0xFF9c66898B706cd56d2dB9587aB597A000eC6ed6
# If required:
# NFTForwardingRulesManager@0x...
```

After that run the following command for source verification in Etherscan for foreign network:
```bash
deploy/verifyEtherscan.sh ForeignNFTOmnibridge@0x964C086398cba3c0BaE520bE900E660a84cA331c
```

Use `VERIFY_HOME=true` environment variable for verification in the home network:
```bash
VERIFY_HOME=true deploy/verifyEtherscan.sh HomeNFTOmnibridge@0xFF9c66898B706cd56d2dB9587aB597A000eC6ed6
```

## Verification in Blockscout

In order to verify multi-file contract in Blockscout, it must support Sourcify integration (present in the xDAI instance).

The list of actions is the following:
1) Upload contracts sources and metadata to IPFS.
2) Wait until Sourcify monitor will handle uploaded files and will automatically verify deployed contracts.
3) Import sources to blockscout from Sourcify database.

### Upload to IPFS

Run the following in our terminal

```bash
node deploy/uploadToIPFS.js
```

You should see all compiled artifacts being uploaded sequentially, their hashes should be printed into the console.

### Check that contracts are verified in Sourcify

You can check if your contracts are verified by visiting https://sourcify.dev
Select the corresponding chain, then enter your contract address.
You should be able to see a green check sign at the top.

### Import sources to Blockscout

Go to the contract page of your contract in the Blockscout, click `Code`, then `Verify & Publish`, then `Sources and Metadata JSON file`.
Upload any file from the `./build/contract/*.json`. It could be any artifact, it does not matter, since our sources are already present in the Sourcify database.
4 changes: 4 additions & 0 deletions deploy/getChainId.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const Web3 = require('web3')

const web3 = new Web3(process.env.RPC_URL)
web3.eth.getChainId().then(console.log)
19 changes: 0 additions & 19 deletions deploy/src/deploymentUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,15 @@ const {
GAS_LIMIT_EXTRA,
HOME_DEPLOYMENT_GAS_PRICE,
FOREIGN_DEPLOYMENT_GAS_PRICE,
HOME_EXPLORER_URL,
FOREIGN_EXPLORER_URL,
HOME_EXPLORER_API_KEY,
FOREIGN_EXPLORER_API_KEY,
DEPLOYMENT_ACCOUNT_PRIVATE_KEY,
} = require('./web3')
const verifier = require('./utils/verifier')

async function deployContract(contractJson, args, { network, nonce }) {
let web3
let apiUrl
let apiKey
if (network === 'foreign') {
web3 = web3Foreign
apiUrl = FOREIGN_EXPLORER_URL
apiKey = FOREIGN_EXPLORER_API_KEY
} else {
web3 = web3Home
apiUrl = HOME_EXPLORER_URL
apiKey = HOME_EXPLORER_API_KEY
}
const instance = new web3.eth.Contract(contractJson.abi)
const result = instance
Expand All @@ -45,14 +34,6 @@ async function deployContract(contractJson, args, { network, nonce }) {
instance.options.address = receipt.contractAddress
instance.deployedBlockNumber = receipt.blockNumber

if (apiUrl) {
let constructorArguments
if (args.length) {
constructorArguments = result.substring(contractJson.bytecode.length)
}
await verifier({ artifact: contractJson, constructorArguments, address: receipt.contractAddress, apiUrl, apiKey })
}

return instance
}

Expand Down
114 changes: 0 additions & 114 deletions deploy/src/utils/verifier.js

This file was deleted.

41 changes: 41 additions & 0 deletions deploy/uploadToIPFS.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const IPFS = require('ipfs-http-client')
const shell = require('shelljs')
const path = require('path')

async function main() {
const ipfs = IPFS.create({
host: 'ipfs.infura.io',
port: 5001,
protocol: 'https',
})

const artifactPaths = shell.ls('./build/contracts/*.json')

console.log('Uploading sources & metadata to IPFS (Infura Gateway)...')
console.log('========================================================')

for (const p of artifactPaths) {
const artifact = require(path.join(process.cwd(), p))

console.log()
console.log(artifact.contractName)
console.log('-'.repeat(artifact.contractName.length))

const res1 = await ipfs.add(artifact.metadata)
console.log(`metadata: ${res1.path}`)

const res2 = await ipfs.add(artifact.source)
console.log(`source: ${res2.path}`)
}

console.log()
console.log('Finished.')
console.log()
}

main()
.then(() => process.exit(0))
.catch((err) => {
console.log(err)
process.exit(1)
})
Empty file added deploy/verifyEtherscan.js
Empty file.
Loading

0 comments on commit fbe208a

Please sign in to comment.