ethereum / sourcify Goto Github PK
View Code? Open in Web Editor NEWDecentralized Solidity contract source code verification service
Home Page: https://sourcify.dev
License: MIT License
Decentralized Solidity contract source code verification service
Home Page: https://sourcify.dev
License: MIT License
The multi-file upload is currently rather unstable, it works on some browsers sometimes, but not always. It might be necessary to run custom ajax posts.
View in Huly HI-12
At some point it could make sense to have a simple ReadTheDocs explaining
View in Huly HI-266
(Following up from discussion in the Jan 8 source-verify meeting)
In the 'trust gap' slides there's a mockup of a metamask confirmation screen as an example of how source-verify could be used.
Below are notes about Metamask's plugin system (in beta).
Resources
The wallet currently decodes some transaction data using Parity's 4Byte registry and an API at eth-method-registry. It is
<pre></pre>
code block - e.g can be anything.addKnownMethod
, exposed with user permission to the plugin hereA source-verify plugin would call the backend with the transaction data of a proposed tx and its target address. Maybe something like:
const data = await verifier.parseData(tx.data, address, networkInfo)
{
name: register,
function: "register(string name, uint duration)",
arguments: {
name: "meetup.berlin.eth",
duration: "1 year"
},
description: "Registers the name meetup.berlin.eth for 1 year"
}
_metamask.addKnownMethod(data.name, data)
Other
sources
link, but it's possible to open pull requests on the beta to add UI features.View in Huly HI-321
This repository has no tests. This is a no-go.
View in Huly HI-22
Mention that because we do not compare with the creation bytecode, the constructor code could be "fake". When only dealing with abi and natspec, we are anyway trusting the developer / deployer, so that is not such a big deal, it is only important to know when we check the source code.
View in Huly HI-218
View in Huly HI-17
currently it looks like this:
it would be better if chainId's are used here instead of network names. Because if a wallet wants to look up contracts here it then needs a mapping between chainId's and the network names used here. Would be nice to not need this mapping.
View in Huly HI-46
View in Huly HI-76
(Following up on discussion in the Jan 8 source-verify meeting)
Source submission could be simplified by publishing a cli utility. Buidler and Truffle both support plugins and collecting the sources / generating the metadata would be easy to implement in that format.
Install
$ npm install --save-dev source-verify
Configure
// truffle-config.js
module.exports = {
plugins: ['source-verify'],
networks: {...}
}
Run
$ truffle run source-verify
> Generating metadata...
> ======================
> - A.sol
> - B.sol
>
> Uploading
> =========
> Your sources should be verified in a few minutes. Check at:
> Metadata: https://gateway.pinata.cloud/ipfs/QmYVd8qstdXtTd1quwv4nJen6XprykxQRLo67Jy7WyiLMB
> Sources: https://gateway.pinata.cloud/ipfs/QmYVd8qiwendlgdsfnJen6XprykxQRLo67Jy(WyiLMC
$ truffle run source-verify --fetch QmYVd8qstdXtTd1quwv4nJen6XprykxQRLo67Jy7WyiLMB
> {
> ...metadata
> }
Other
Check if the local version of a contract matches one on chain (to validate a simulation).
truffle run source-verify \
--diff \
--local build/contracts/ENSRegistry.json \
--network mainnet \
--address 0xabc....de \
> - 0.4.23+commit.124ca40d // Mainnet
> + 0.5.12+commit.7709ece9 // Local
View in Huly HI-85
View in Huly HI-13
Update README with steps on how to deploy locally with and without docker and docker-compose
View in Huly HI-19
(Following up on discussion in the Jan 8 source-verify meeting)
Am wondering about how the metadata is hashed and the importance of the source file paths. (Apologies in advance if I've misunderstood this...)
In the solidity docs there is a warning:
Since the bytecode of the resulting contract contains the metadata hash by default, any change to the metadata might result in a change of the bytecode. This includes changes to a filename or path, and since the metadata includes a hash of all the sources used, a single whitespace change results in different metadata, and different bytecode.
For example, A.sol, compiled with truffle compile
and deployed using the data in the truffle artifact, has metadata source keys like:
"sources": {
"/Users/cgewecke/code/ef/sv-truffle/contracts/A.sol": {
"keccak256": "0xfc68a9ffdb0d7d3ec5456f5e2d2c4f855e684892f6c78fcb0dc1e482696d9bb7",
"urls": [
"bzz-raw://4d22457fe6215d956a57fcd0cb63f745d8fd718ba8d85a20d65c72232038779f",
"dweb:/ipfs/QmPmUahXAjtq5mJTW9Qc6oNUVGEuocxb1un5371zLJAAb5"
]
}
},
Running solc --metadata contracts/A.sol
over the same source produces
"sources": {
"contracts/A.sol": {
"keccak256": "0xfc68a9ffdb0d7d3ec5456f5e2d2c4f855e684892f6c78fcb0dc1e482696d9bb7",
"urls": [
"bzz-raw://4d22457fe6215d956a57fcd0cb63f745d8fd718ba8d85a20d65c72232038779f",
"dweb:/ipfs/QmPmUahXAjtq5mJTW9Qc6oNUVGEuocxb1un5371zLJAAb5"
]
}
},
It seems like the file system context and tooling of the deployment and metadata compilations are not allowed to differ even when the sources are identical.
Not sure this would work but perhaps if the file's keccak hash was used as a key instead, metadata could be matched to sources from anywhere as long as paths were associated with the files when uploading to the service for JSON-IO compilation.
If metadata was pathless, you could:
View in Huly HI-209
Great suggestion on twitter: https://twitter.com/gh1dra/status/1239962423341322241
View in Huly HI-427
One way the project could be restructured prior to converting to TS might be:
.circleci
Dockerfile
public /
src/
address-db.js
injector.js
monitor.js
server.js
utils.js # Duplicate fns
scripts/
run.sh
run_monitor.sh
run_server.sh
test /
.. etc ..
Some files seem experimental (or incidental) and might be removed / stored away.
Shell scripts could be aliased to npm scripts
"scripts": {
"docker:all": "./scripts/run.sh",
"monitor": "./scripts/run_monitor.sh",
"server": "./scripts/run_server.sh",
}
View in Huly HI-16
View in Huly HI-66
Idea was to user some of the docker monitoring tools and check health of containers (healtcheck has been added to some container, not all) and to publish to gitter https://gitter.im/ethereumautomation/source-verify if something goes down.
Each gitter channel has a webhook that can be used for this.
View in Huly HI-337
View in Huly HI-65
@edisinovcic mentioned this in Feb 14 meeting...
An independent monitor runner might want to detect / record deployments from any point in the chain history.
View in Huly HI-47
We should offer a better way to browse the source code. It should not be too fancy, but currently, the directory listing is not really nice.
At the same time, a raw interface should also be supported, so that people can retrieve the unmodified source or ABI file, for example.
View in Huly HI-20
The service currently uses a static dump of the code hash -> addresses mapping made at some point in time. This database should update itself and work on mainnet and all testnets.
View in Huly HI-135
For some reason circleci does not wait for build_and_publish to finish before starting deploy. Checkout if there is some timeout or something similar that causes this.
View in Huly HI-18
Idea is to make UI runnable offline so all scripts that are loaded from web should be cached/saved locally.
View in Huly HI-26
The look and feel of the file upload page should be improved. We should have a drag and drop area and in general, better input fields.
View in Huly HI-11
currently outside docker - should be part of it. Command would be:
ipfs name publish `ipfs add -Q -r <contract_path>`
should run like once per hour or so
View in Huly HI-86
View in Huly HI-67
View in Huly HI-31
example metadata generated via useLiteralContent": true
This is for contract : 0x3845badAde8e6dFF049820680d1F14bD3903a5d0
{
"compiler": {
"version": "0.5.9+commit.e560f70d"
},
"language": "Solidity",
"output": {
"abi": [
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "newAdmin",
"type": "address"
}
],
"name": "changeExecutionAdmin",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "spender",
"type": "address"
},
{
"name": "amount",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "owner",
"type": "address"
},
{
"name": "amount",
"type": "uint256"
}
],
"name": "burnFor",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "from",
"type": "address"
},
{
"name": "to",
"type": "address"
},
{
"name": "amount",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "owner",
"type": "address"
},
{
"name": "spender",
"type": "address"
},
{
"name": "amount",
"type": "uint256"
}
],
"name": "approveFor",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "decimals",
"outputs": [
{
"name": "",
"type": "uint8"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "owner",
"type": "address"
},
{
"name": "spender",
"type": "address"
},
{
"name": "amountNeeded",
"type": "uint256"
}
],
"name": "addAllowanceIfNeeded",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "amount",
"type": "uint256"
}
],
"name": "burn",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "who",
"type": "address"
}
],
"name": "isExecutionOperator",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "who",
"type": "address"
}
],
"name": "isSuperOperator",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "executionOperator",
"type": "address"
},
{
"name": "enabled",
"type": "bool"
}
],
"name": "setExecutionOperator",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getAdmin",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "from",
"type": "address"
},
{
"name": "to",
"type": "address"
},
{
"name": "amount",
"type": "uint256"
},
{
"name": "gasLimit",
"type": "uint256"
},
{
"name": "data",
"type": "bytes"
}
],
"name": "approveAndExecuteWithSpecificGas",
"outputs": [
{
"name": "success",
"type": "bool"
},
{
"name": "returnData",
"type": "bytes"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "newAdmin",
"type": "address"
}
],
"name": "changeAdmin",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "to",
"type": "address"
},
{
"name": "amount",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"name": "success",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "superOperator",
"type": "address"
},
{
"name": "enabled",
"type": "bool"
}
],
"name": "setSuperOperator",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getExecutionAdmin",
"outputs": [
{
"name": "",
"type": "address"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "target",
"type": "address"
},
{
"name": "amount",
"type": "uint256"
},
{
"name": "data",
"type": "bytes"
}
],
"name": "paidCall",
"outputs": [
{
"name": "",
"type": "bytes"
}
],
"payable": true,
"stateMutability": "payable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "target",
"type": "address"
},
{
"name": "amount",
"type": "uint256"
},
{
"name": "data",
"type": "bytes"
}
],
"name": "approveAndCall",
"outputs": [
{
"name": "",
"type": "bytes"
}
],
"payable": true,
"stateMutability": "payable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "from",
"type": "address"
},
{
"name": "to",
"type": "address"
},
{
"name": "amount",
"type": "uint256"
},
{
"name": "gasLimit",
"type": "uint256"
},
{
"name": "tokenGasPrice",
"type": "uint256"
},
{
"name": "baseGasCharge",
"type": "uint256"
},
{
"name": "tokenReceiver",
"type": "address"
},
{
"name": "data",
"type": "bytes"
}
],
"name": "approveAndExecuteWithSpecificGasAndChargeForIt",
"outputs": [
{
"name": "success",
"type": "bool"
},
{
"name": "returnData",
"type": "bytes"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "to",
"type": "address"
},
{
"name": "gasLimit",
"type": "uint256"
},
{
"name": "data",
"type": "bytes"
}
],
"name": "executeWithSpecificGas",
"outputs": [
{
"name": "success",
"type": "bool"
},
{
"name": "returnData",
"type": "bytes"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "owner",
"type": "address"
},
{
"name": "spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"name": "remaining",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "from",
"type": "address"
},
{
"name": "to",
"type": "address"
},
{
"name": "amount",
"type": "uint256"
},
{
"name": "gasLimit",
"type": "uint256"
},
{
"name": "tokenGasPrice",
"type": "uint256"
},
{
"name": "baseGasCharge",
"type": "uint256"
},
{
"name": "tokenReceiver",
"type": "address"
}
],
"name": "transferAndChargeForGas",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"name": "sandAdmin",
"type": "address"
},
{
"name": "executionAdmin",
"type": "address"
},
{
"name": "beneficiary",
"type": "address"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "from",
"type": "address"
},
{
"indexed": true,
"name": "to",
"type": "address"
},
{
"indexed": false,
"name": "value",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"name": "owner",
"type": "address"
},
{
"indexed": true,
"name": "spender",
"type": "address"
},
{
"indexed": false,
"name": "value",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "superOperator",
"type": "address"
},
{
"indexed": false,
"name": "enabled",
"type": "bool"
}
],
"name": "SuperOperator",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "oldAdmin",
"type": "address"
},
{
"indexed": false,
"name": "newAdmin",
"type": "address"
}
],
"name": "AdminChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "oldAdmin",
"type": "address"
},
{
"indexed": false,
"name": "newAdmin",
"type": "address"
}
],
"name": "ExecutionAdminAdminChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "executionOperator",
"type": "address"
},
{
"indexed": false,
"name": "enabled",
"type": "bool"
}
],
"name": "ExecutionOperator",
"type": "event"
}
],
"devdoc": {
"methods": {
"allowance(address,address)": {
"params": {
"owner": "address whose token is allowed.",
"spender": "address allowed to transfer."
},
"return": "the amount of token `spender` is allowed to transfer on behalf of `owner`."
},
"approve(address,uint256)": {
"params": {
"amount": "the number of tokens allowed.",
"spender": "address to be given rights to transfer."
},
"return": "true if success."
},
"approveAndCall(address,uint256,bytes)": {
"params": {
"amount": "the number of tokens allowed.",
"data": "bytes for the call.",
"target": "address to be given rights to transfer and destination of the call."
},
"return": "data of the call."
},
"approveAndExecuteWithSpecificGas(address,address,uint256,uint256,bytes)": {
"params": {
"amount": "number of tokens allowed that can be transfer by the code at `to`.",
"data": "the bytes sent to the destination address.",
"from": "address of which token will be transfered.",
"gasLimit": "exact amount of gas to be passed to the call.",
"to": "destination address fo the call."
},
"return": "success whether the execution was successful.returnData data resulting from the execution."
},
"approveAndExecuteWithSpecificGasAndChargeForIt(address,address,uint256,uint256,uint256,uint256,address,bytes)": {
"details": "the reason for this function is that charging for gas here is more gas-efficient than doing it in the caller.",
"params": {
"amount": "number of tokens allowed that can be transfer by the code at `to`.",
"baseGasCharge": "amount of gas charged on top of the gas used for the call.",
"data": "the bytes sent to the destination address.",
"from": "address of which token will be transfered.",
"gasLimit": "exact amount of gas to be passed to the call.",
"to": "destination address fo the call.",
"tokenGasPrice": "price in token for the gas to be charged.",
"tokenReceiver": "recipient address of the token charged for the gas used."
},
"return": "success whether the execution was successful.returnData data resulting from the execution."
},
"approveFor(address,address,uint256)": {
"params": {
"amount": "the number of tokens allowed.",
"owner": "address whose token is allowed.",
"spender": "address to be given rights to transfer."
},
"return": "true if success."
},
"balanceOf(address)": {
"params": {
"owner": "The address to query the balance of."
},
"return": "The amount owned by `owner`."
},
"burn(uint256)": {
"params": {
"amount": "the number of tokens to burn."
},
"return": "true if success."
},
"burnFor(address,uint256)": {
"params": {
"amount": "the number of token to burn.",
"owner": "address whose token is to burn."
},
"return": "true if success."
},
"changeAdmin(address)": {
"params": {
"newAdmin": "address of the new administrator."
}
},
"changeExecutionAdmin(address)": {
"params": {
"newAdmin": "address of the new administrator."
}
},
"decimals()": {
"return": "the number of decimals."
},
"executeWithSpecificGas(address,uint256,bytes)": {
"params": {
"data": "the bytes sent to the destination address.",
"gasLimit": "exact amount of gas to be passed to the call.",
"to": "destination address fo the call."
},
"return": "success whether the execution was successful.returnData data resulting from the execution."
},
"getAdmin()": {
"return": "the current administrator of this contract."
},
"getExecutionAdmin()": {
"return": "address of the execution administrator."
},
"isExecutionOperator(address)": {
"params": {
"who": "The address to query."
},
"return": "whether the address has executionOperator rights."
},
"isSuperOperator(address)": {
"params": {
"who": "The address to query."
},
"return": "whether the address has superOperator rights."
},
"name()": {
"return": "name of the tokens"
},
"paidCall(address,uint256,bytes)": {
"params": {
"amount": "the number of tokens allowed to spend.",
"data": "bytes for the call.",
"target": "destination of the call, allowed to spend the amount specified"
},
"return": "data of the call."
},
"setExecutionOperator(address,bool)": {
"params": {
"enabled": "set whether the executionOperator is enabled or disabled.",
"executionOperator": "address that will be given/removed executionOperator right."
}
},
"setSuperOperator(address,bool)": {
"params": {
"enabled": "set whether the superOperator is enabled or disabled.",
"superOperator": "address that will be given/removed superOperator right."
}
},
"symbol()": {
"return": "symbol of the tokens"
},
"totalSupply()": {
"return": "the total number of tokens in existence."
},
"transfer(address,uint256)": {
"params": {
"amount": "the number of tokens transfered.",
"to": "the recipient address of the tokens transfered."
},
"return": "true if success."
},
"transferAndChargeForGas(address,address,uint256,uint256,uint256,uint256,address)": {
"params": {
"amount": "number of tokens allowed that can be transfer by the code at `to`.",
"baseGasCharge": "amount of gas charged on top of the gas used for the call.",
"from": "address of which token will be transfered.",
"gasLimit": "exact amount of gas to be passed to the call.",
"to": "destination address fo the call.",
"tokenGasPrice": "price in token for the gas to be charged.",
"tokenReceiver": "recipient address of the token charged for the gas used."
},
"return": "whether the transfer was successful."
},
"transferFrom(address,address,uint256)": {
"params": {
"amount": "the number of tokens transfered.",
"from": "whose token it is transferring from.",
"to": "the recipient address of the tokens transfered."
},
"return": "true if success."
}
}
},
"userdoc": {
"methods": {
"allowance(address,address)": {
"notice": "gets allowance of `spender` for `owner`'s tokens."
},
"approve(address,uint256)": {
"notice": "approve `spender` to transfer `amount` tokens."
},
"approveAndCall(address,uint256,bytes)": {
"notice": "approve `target` to spend `amount` and call it with data."
},
"approveAndExecuteWithSpecificGas(address,address,uint256,uint256,bytes)": {
"notice": "approve a specific amount of token for `from` and execute on behalf of the contract."
},
"approveAndExecuteWithSpecificGasAndChargeForIt(address,address,uint256,uint256,uint256,uint256,address,bytes)": {
"notice": "approve a specific amount of token for `from` and execute on behalf of the contract. Plus charge the gas required to perform it."
},
"approveFor(address,address,uint256)": {
"notice": "approve `spender` to transfer `amount` tokens from `owner`."
},
"balanceOf(address)": {
"notice": "Gets the balance of `owner`."
},
"burn(uint256)": {
"notice": "burn `amount` tokens."
},
"burnFor(address,uint256)": {
"notice": "burn `amount` tokens from `owner`."
},
"changeAdmin(address)": {
"notice": "change the administrator to be `newAdmin`."
},
"changeExecutionAdmin(address)": {
"notice": "change the execution adminstrator to be `newAdmin`."
},
"decimals()": {
"notice": "returns the number of decimals for that token."
},
"executeWithSpecificGas(address,uint256,bytes)": {
"notice": "execute on behalf of the contract."
},
"getAdmin()": {
"notice": "gives the current administrator of this contract."
},
"getExecutionAdmin()": {
"notice": "give the address responsible for adding execution rights."
},
"isExecutionOperator(address)": {
"notice": "check whether address `who` is given executionOperator rights."
},
"isSuperOperator(address)": {
"notice": "check whether address `who` is given superOperator rights."
},
"name()": {
"notice": "A descriptive name for the tokens"
},
"paidCall(address,uint256,bytes)": {
"notice": "temporarly approve `target` to spend `amount` and call it with data. Previous approvals remains unchanged."
},
"setExecutionOperator(address,bool)": {
"notice": "set `executionOperator` as executionOperator: `enabled`."
},
"setSuperOperator(address,bool)": {
"notice": "Enable or disable the ability of `superOperator` to transfer tokens of all (superOperator rights)."
},
"symbol()": {
"notice": "An abbreviated name for the tokens"
},
"totalSupply()": {
"notice": "Gets the total number of tokens in existence."
},
"transfer(address,uint256)": {
"notice": "Transfer `amount` tokens to `to`."
},
"transferAndChargeForGas(address,address,uint256,uint256,uint256,uint256,address)": {
"notice": "transfer 1amount1 token from `from` to `to` and charge the gas required to perform that transfer."
},
"transferFrom(address,address,uint256)": {
"notice": "Transfer `amount` tokens from `from` to `to`."
}
}
}
},
"settings": {
"compilationTarget": {
"src/Sand.sol": "Sand"
},
"evmVersion": "petersburg",
"libraries": {},
"metadata": {
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 2000
},
"remappings": []
},
"sources": {
"contracts_common/src/BaseWithStorage/Admin.sol": {
"content": "pragma solidity ^0.5.2;\n\ncontract Admin {\n\n address internal _admin;\n\n event AdminChanged(address oldAdmin, address newAdmin);\n\n /// @notice gives the current administrator of this contract.\n /// @return the current administrator of this contract.\n function getAdmin() external view returns (address) {\n return _admin;\n }\n\n /// @notice change the administrator to be `newAdmin`.\n /// @param newAdmin address of the new administrator.\n function changeAdmin(address newAdmin) external {\n require(msg.sender == _admin, \"only admin can change admin\");\n emit AdminChanged(_admin, newAdmin);\n _admin = newAdmin;\n }\n\n modifier onlyAdmin() {\n require (msg.sender == _admin, \"only admin allowed\");\n _;\n }\n\n}\n",
"keccak256": "0xf3763fa108235379b48cf8fe9a708692fcb077250d9974351fd636ff0baf84bf"
},
"contracts_common/src/BaseWithStorage/SuperOperators.sol": {
"content": "pragma solidity ^0.5.2;\n\nimport \"./Admin.sol\";\n\ncontract SuperOperators is Admin {\n\n mapping(address => bool) internal _superOperators;\n\n event SuperOperator(address superOperator, bool enabled);\n\n /// @notice Enable or disable the ability of `superOperator` to transfer tokens of all (superOperator rights).\n /// @param superOperator address that will be given/removed superOperator right.\n /// @param enabled set whether the superOperator is enabled or disabled.\n function setSuperOperator(address superOperator, bool enabled) external {\n require(\n msg.sender == _admin,\n \"only admin is allowed to add super operators\"\n );\n _superOperators[superOperator] = enabled;\n emit SuperOperator(superOperator, enabled);\n }\n\n /// @notice check whether address `who` is given superOperator rights.\n /// @param who The address to query.\n /// @return whether the address has superOperator rights.\n function isSuperOperator(address who) public view returns (bool) {\n return _superOperators[who];\n }\n}\n",
"keccak256": "0x22354cf60ccf77a6de61c13bdaf4e3094d115b960ae563b0527622c846a12abb"
},
"contracts_common/src/Interfaces/ERC20Events.sol": {
"content": "pragma solidity ^0.5.2;\n\n/* interface */\ncontract ERC20Events {\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n}\n",
"keccak256": "0xee09c10a3f9adc913227efdcd94ce44e05b59b04717f8f868153d356bd03f5d2"
},
"contracts_common/src/Libraries/BytesUtil.sol": {
"content": "pragma solidity ^0.5.2;\n\nlibrary BytesUtil {\n function memcpy(uint256 dest, uint256 src, uint256 len) internal pure {\n // Copy word-length chunks while possible\n for (; len >= 32; len -= 32) {\n assembly {\n mstore(dest, mload(src))\n }\n dest += 32;\n src += 32;\n }\n\n // Copy remaining bytes\n uint256 mask = 256**(32 - len) - 1;\n assembly {\n let srcpart := and(mload(src), not(mask))\n let destpart := and(mload(dest), mask)\n mstore(dest, or(destpart, srcpart))\n }\n }\n\n function pointerToBytes(uint256 src, uint256 len)\n internal\n pure\n returns (bytes memory)\n {\n bytes memory ret = new bytes(len);\n uint256 retptr;\n assembly {\n retptr := add(ret, 32)\n }\n\n memcpy(retptr, src, len);\n return ret;\n }\n\n function addressToBytes(address a) internal pure returns (bytes memory b) {\n assembly {\n let m := mload(0x40)\n mstore(\n add(m, 20),\n xor(0x140000000000000000000000000000000000000000, a)\n )\n mstore(0x40, add(m, 52))\n b := m\n }\n }\n\n function uint256ToBytes(uint256 a) internal pure returns (bytes memory b) {\n assembly {\n let m := mload(0x40)\n mstore(add(m, 32), a)\n mstore(0x40, add(m, 64))\n b := m\n }\n }\n\n function doFirstParamEqualsAddress(bytes memory data, address _address)\n internal\n pure\n returns (bool)\n {\n if (data.length < (36 + 32)) {\n return false;\n }\n uint256 value;\n assembly {\n value := mload(add(data, 36))\n }\n return value == uint256(_address);\n }\n\n function doParamEqualsUInt256(bytes memory data, uint256 i, uint256 value)\n internal\n pure\n returns (bool)\n {\n if (data.length < (36 + (i + 1) * 32)) {\n return false;\n }\n uint256 offset = 36 + i * 32;\n uint256 valuePresent;\n assembly {\n valuePresent := mload(add(data, offset))\n }\n return valuePresent == value;\n }\n\n function overrideFirst32BytesWithAddress(\n bytes memory data,\n address _address\n ) internal pure returns (bytes memory) {\n uint256 dest;\n assembly {\n dest := add(data, 48)\n } // 48 = 32 (offset) + 4 (func sig) + 12 (address is only 20 bytes)\n\n bytes memory addressBytes = addressToBytes(_address);\n uint256 src;\n assembly {\n src := add(addressBytes, 32)\n }\n\n memcpy(dest, src, 20);\n return data;\n }\n\n function overrideFirstTwo32BytesWithAddressAndInt(\n bytes memory data,\n address _address,\n uint256 _value\n ) internal pure returns (bytes memory) {\n uint256 dest;\n uint256 src;\n\n assembly {\n dest := add(data, 48)\n } // 48 = 32 (offset) + 4 (func sig) + 12 (address is only 20 bytes)\n bytes memory bbytes = addressToBytes(_address);\n assembly {\n src := add(bbytes, 32)\n }\n memcpy(dest, src, 20);\n\n assembly {\n dest := add(data, 68)\n } // 48 = 32 (offset) + 4 (func sig) + 32 (next slot)\n bbytes = uint256ToBytes(_value);\n assembly {\n src := add(bbytes, 32)\n }\n memcpy(dest, src, 32);\n\n return data;\n }\n}\n",
"keccak256": "0xb5c236938e1f71524127371a015836e83103c5ac1b4ed7b7f22892a8c0429e10"
},
"src/Sand.sol": {
"content": "pragma solidity 0.5.9;\n\nimport \"./Sand/erc20/ERC20ExecuteExtension.sol\";\nimport \"./Sand/erc20/ERC20BaseToken.sol\";\nimport \"./Sand/erc20/ERC20BasicApproveExtension.sol\";\n\ncontract Sand is ERC20ExecuteExtension, ERC20BasicApproveExtension, ERC20BaseToken {\n\n constructor(address sandAdmin, address executionAdmin, address beneficiary) public {\n _admin = sandAdmin;\n _executionAdmin = executionAdmin;\n _mint(beneficiary, 3000000000000000000000000000);\n }\n\n /// @notice A descriptive name for the tokens\n /// @return name of the tokens\n function name() public view returns (string memory) {\n return \"SAND\";\n }\n\n /// @notice An abbreviated name for the tokens\n /// @return symbol of the tokens\n function symbol() public view returns (string memory) {\n return \"SAND\";\n }\n\n}\n",
"keccak256": "0xe05c8232fddc05f34648fa1db29cbfff2d163357e613425a925d80dbefff75eb"
},
"src/Sand/erc20/ERC20BaseToken.sol": {
"content": "pragma solidity 0.5.9;\n\nimport \"../../../contracts_common/src/Interfaces/ERC20Events.sol\";\nimport \"../../../contracts_common/src/BaseWithStorage/SuperOperators.sol\";\n\ncontract ERC20BaseToken is SuperOperators, ERC20Events {\n\n uint256 internal _totalSupply;\n mapping(address => uint256) internal _balances;\n mapping(address => mapping(address => uint256)) internal _allowances;\n\n /// @notice Gets the total number of tokens in existence.\n /// @return the total number of tokens in existence.\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n /// @notice Gets the balance of `owner`.\n /// @param owner The address to query the balance of.\n /// @return The amount owned by `owner`.\n function balanceOf(address owner) public view returns (uint256) {\n return _balances[owner];\n }\n\n /// @notice gets allowance of `spender` for `owner`'s tokens.\n /// @param owner address whose token is allowed.\n /// @param spender address allowed to transfer.\n /// @return the amount of token `spender` is allowed to transfer on behalf of `owner`.\n function allowance(address owner, address spender)\n public\n view\n returns (uint256 remaining)\n {\n return _allowances[owner][spender];\n }\n\n /// @notice returns the number of decimals for that token.\n /// @return the number of decimals.\n function decimals() public view returns (uint8) {\n return uint8(18);\n }\n\n /// @notice Transfer `amount` tokens to `to`.\n /// @param to the recipient address of the tokens transfered.\n /// @param amount the number of tokens transfered.\n /// @return true if success.\n function transfer(address to, uint256 amount)\n public\n returns (bool success)\n {\n _transfer(msg.sender, to, amount);\n return true;\n }\n\n /// @notice Transfer `amount` tokens from `from` to `to`.\n /// @param from whose token it is transferring from.\n /// @param to the recipient address of the tokens transfered.\n /// @param amount the number of tokens transfered.\n /// @return true if success.\n function transferFrom(address from, address to, uint256 amount)\n public\n returns (bool success)\n {\n if (msg.sender != from && !_superOperators[msg.sender]) {\n uint256 currentAllowance = _allowances[from][msg.sender];\n if (currentAllowance != (2**256) - 1) {\n // save gas when allowance is maximal by not reducing it (see https://github.com/ethereum/EIPs/issues/717)\n require(currentAllowance >= amount, \"Not enough funds allowed\");\n _allowances[from][msg.sender] = currentAllowance - amount;\n }\n }\n _transfer(from, to, amount);\n return true;\n }\n\n /// @notice burn `amount` tokens.\n /// @param amount the number of tokens to burn.\n /// @return true if success.\n function burn(uint256 amount) external returns (bool) {\n _burn(msg.sender, amount);\n return true;\n }\n\n /// @notice burn `amount` tokens from `owner`.\n /// @param owner address whose token is to burn.\n /// @param amount the number of token to burn.\n /// @return true if success.\n function burnFor(address owner, uint256 amount) external returns (bool) {\n _burn(owner, amount);\n return true;\n }\n\n /// @notice approve `spender` to transfer `amount` tokens.\n /// @param spender address to be given rights to transfer.\n /// @param amount the number of tokens allowed.\n /// @return true if success.\n function approve(address spender, uint256 amount)\n public\n returns (bool success)\n {\n _approveFor(msg.sender, spender, amount);\n return true;\n }\n\n /// @notice approve `spender` to transfer `amount` tokens from `owner`.\n /// @param owner address whose token is allowed.\n /// @param spender address to be given rights to transfer.\n /// @param amount the number of tokens allowed.\n /// @return true if success.\n function approveFor(address owner, address spender, uint256 amount)\n public\n returns (bool success)\n {\n require(\n msg.sender == owner || _superOperators[msg.sender],\n \"msg.sender != owner && !superOperator\"\n );\n _approveFor(owner, spender, amount);\n return true;\n }\n\n function addAllowanceIfNeeded(address owner, address spender, uint256 amountNeeded)\n public\n returns (bool success)\n {\n require(\n msg.sender == owner || _superOperators[msg.sender],\n \"msg.sender != owner && !superOperator\"\n );\n _addAllowanceIfNeeded(owner, spender, amountNeeded);\n return true;\n }\n\n function _addAllowanceIfNeeded(address owner, address spender, uint256 amountNeeded)\n internal\n {\n if(amountNeeded > 0 && !isSuperOperator(spender)) {\n uint256 currentAllowance = _allowances[owner][spender];\n if(currentAllowance < amountNeeded) {\n _approveFor(owner, spender, amountNeeded);\n }\n }\n }\n\n function _approveFor(address owner, address spender, uint256 amount)\n internal\n {\n require(\n owner != address(0) && spender != address(0),\n \"Cannot approve with 0x0\"\n );\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n function _transfer(address from, address to, uint256 amount) internal {\n require(to != address(0), \"Cannot send to 0x0\");\n uint256 currentBalance = _balances[from];\n require(currentBalance >= amount, \"not enough fund\");\n _balances[from] = currentBalance - amount;\n _balances[to] += amount;\n emit Transfer(from, to, amount);\n }\n\n function _mint(address to, uint256 amount) internal {\n require(to != address(0), \"Cannot mint to 0x0\");\n require(amount > 0, \"cannot mint 0 tokens\");\n uint256 currentTotalSupply = _totalSupply;\n uint256 newTotalSupply = currentTotalSupply + amount;\n require(newTotalSupply > currentTotalSupply, \"overflow\");\n _totalSupply = newTotalSupply;\n _balances[to] += amount;\n emit Transfer(address(0), to, amount);\n }\n\n function _burn(address from, uint256 amount) internal {\n require(amount > 0, \"cannot burn 0 tokens\");\n if (msg.sender != from && !_superOperators[msg.sender]) {\n uint256 currentAllowance = _allowances[from][msg.sender];\n require(\n currentAllowance >= amount,\n \"Not enough funds allowed\"\n );\n if (currentAllowance != (2**256) - 1) {\n // save gas when allowance is maximal by not reducing it (see https://github.com/ethereum/EIPs/issues/717)\n _allowances[from][msg.sender] = currentAllowance - amount;\n }\n }\n\n uint256 currentBalance = _balances[from];\n require(currentBalance >= amount, \"Not enough funds\");\n _balances[from] = currentBalance - amount;\n _totalSupply -= amount;\n emit Transfer(from, address(0), amount);\n }\n}\n",
"keccak256": "0xc70b1452852cbe8f437ba3fdcff911ed3fd7820b0d853e5fe147a90989cc1085"
},
"src/Sand/erc20/ERC20BasicApproveExtension.sol": {
"content": "pragma solidity 0.5.9;\n\nimport \"../../../contracts_common/src/Libraries/BytesUtil.sol\";\n\ncontract ERC20BasicApproveExtension {\n\n /// @notice approve `target` to spend `amount` and call it with data.\n /// @param target address to be given rights to transfer and destination of the call.\n /// @param amount the number of tokens allowed.\n /// @param data bytes for the call.\n /// @return data of the call.\n function approveAndCall(\n address target,\n uint256 amount,\n bytes calldata data\n ) external payable returns (bytes memory) {\n require(\n BytesUtil.doFirstParamEqualsAddress(data, msg.sender),\n \"first param != sender\"\n );\n\n _approveFor(msg.sender, target, amount);\n\n // solium-disable-next-line security/no-call-value\n (bool success, bytes memory returnData) = target.call.value(msg.value)(data);\n require(success, string(returnData));\n return returnData;\n }\n\n /// @notice temporarly approve `target` to spend `amount` and call it with data. Previous approvals remains unchanged.\n /// @param target destination of the call, allowed to spend the amount specified\n /// @param amount the number of tokens allowed to spend.\n /// @param data bytes for the call.\n /// @return data of the call.\n function paidCall(\n address target,\n uint256 amount,\n bytes calldata data\n ) external payable returns (bytes memory) {\n require(\n BytesUtil.doFirstParamEqualsAddress(data, msg.sender),\n \"first param != sender\"\n );\n\n if (amount > 0) {\n _addAllowanceIfNeeded(msg.sender, target, amount);\n }\n\n // solium-disable-next-line security/no-call-value\n (bool success, bytes memory returnData) = target.call.value(msg.value)(data);\n require(success, string(returnData));\n\n return returnData;\n }\n\n function _approveFor(address owner, address target, uint256 amount) internal;\n function _addAllowanceIfNeeded(address owner, address spender, uint256 amountNeeded) internal;\n}\n",
"keccak256": "0xbd8c882843acf82adb849222068490302925e31ac66305b75f1663a719c7fc37"
},
"src/Sand/erc20/ERC20ExecuteExtension.sol": {
"content": "pragma solidity 0.5.9;\n\n\ncontract ERC20ExecuteExtension {\n\n /// @dev _executionAdmin != _admin so that this super power can be disabled independently\n address internal _executionAdmin;\n\n event ExecutionAdminAdminChanged(address oldAdmin, address newAdmin);\n\n /// @notice give the address responsible for adding execution rights.\n /// @return address of the execution administrator.\n function getExecutionAdmin() external view returns (address) {\n return _executionAdmin;\n }\n\n /// @notice change the execution adminstrator to be `newAdmin`.\n /// @param newAdmin address of the new administrator.\n function changeExecutionAdmin(address newAdmin) external {\n require(msg.sender == _executionAdmin, \"only executionAdmin can change executionAdmin\");\n emit ExecutionAdminAdminChanged(_executionAdmin, newAdmin);\n _executionAdmin = newAdmin;\n }\n\n mapping(address => bool) internal _executionOperators;\n event ExecutionOperator(address executionOperator, bool enabled);\n\n /// @notice set `executionOperator` as executionOperator: `enabled`.\n /// @param executionOperator address that will be given/removed executionOperator right.\n /// @param enabled set whether the executionOperator is enabled or disabled.\n function setExecutionOperator(address executionOperator, bool enabled) external {\n require(\n msg.sender == _executionAdmin,\n \"only execution admin is allowed to add execution operators\"\n );\n _executionOperators[executionOperator] = enabled;\n emit ExecutionOperator(executionOperator, enabled);\n }\n\n /// @notice check whether address `who` is given executionOperator rights.\n /// @param who The address to query.\n /// @return whether the address has executionOperator rights.\n function isExecutionOperator(address who) public view returns (bool) {\n return _executionOperators[who];\n }\n\n /// @notice execute on behalf of the contract.\n /// @param to destination address fo the call.\n /// @param gasLimit exact amount of gas to be passed to the call.\n /// @param data the bytes sent to the destination address.\n /// @return success whether the execution was successful.\n /// @return returnData data resulting from the execution.\n function executeWithSpecificGas(address to, uint256 gasLimit, bytes calldata data) external returns (bool success, bytes memory returnData) {\n require(_executionOperators[msg.sender], \"only execution operators allowed to execute on SAND behalf\");\n (success, returnData) = to.call.gas(gasLimit)(data);\n assert(gasleft() > gasLimit / 63); // not enough gas provided, assert to throw all gas // TODO use EIP-1930\n }\n\n /// @notice approve a specific amount of token for `from` and execute on behalf of the contract.\n /// @param from address of which token will be transfered.\n /// @param to destination address fo the call.\n /// @param amount number of tokens allowed that can be transfer by the code at `to`.\n /// @param gasLimit exact amount of gas to be passed to the call.\n /// @param data the bytes sent to the destination address.\n /// @return success whether the execution was successful.\n /// @return returnData data resulting from the execution.\n function approveAndExecuteWithSpecificGas(\n address from,\n address to,\n uint256 amount,\n uint256 gasLimit,\n bytes calldata data\n ) external returns (bool success, bytes memory returnData) {\n require(_executionOperators[msg.sender], \"only execution operators allowed to execute on SAND behalf\");\n return _approveAndExecuteWithSpecificGas(from, to, amount, gasLimit, data);\n }\n\n /// @dev the reason for this function is that charging for gas here is more gas-efficient than doing it in the caller.\n /// @notice approve a specific amount of token for `from` and execute on behalf of the contract. Plus charge the gas required to perform it.\n /// @param from address of which token will be transfered.\n /// @param to destination address fo the call.\n /// @param amount number of tokens allowed that can be transfer by the code at `to`.\n /// @param gasLimit exact amount of gas to be passed to the call.\n /// @param tokenGasPrice price in token for the gas to be charged.\n /// @param baseGasCharge amount of gas charged on top of the gas used for the call.\n /// @param tokenReceiver recipient address of the token charged for the gas used.\n /// @param data the bytes sent to the destination address.\n /// @return success whether the execution was successful.\n /// @return returnData data resulting from the execution.\n function approveAndExecuteWithSpecificGasAndChargeForIt(\n address from,\n address to,\n uint256 amount,\n uint256 gasLimit,\n uint256 tokenGasPrice,\n uint256 baseGasCharge,\n address tokenReceiver,\n bytes calldata data\n ) external returns (bool success, bytes memory returnData) {\n uint256 initialGas = gasleft();\n require(_executionOperators[msg.sender], \"only execution operators allowed to execute on SAND behalf\");\n (success, returnData) = _approveAndExecuteWithSpecificGas(from, to, amount, gasLimit, data);\n if (tokenGasPrice > 0) {\n _charge(from, gasLimit, tokenGasPrice, initialGas, baseGasCharge, tokenReceiver);\n }\n }\n\n /// @notice transfer 1amount1 token from `from` to `to` and charge the gas required to perform that transfer.\n /// @param from address of which token will be transfered.\n /// @param to destination address fo the call.\n /// @param amount number of tokens allowed that can be transfer by the code at `to`.\n /// @param gasLimit exact amount of gas to be passed to the call.\n /// @param tokenGasPrice price in token for the gas to be charged.\n /// @param baseGasCharge amount of gas charged on top of the gas used for the call.\n /// @param tokenReceiver recipient address of the token charged for the gas used.\n /// @return whether the transfer was successful.\n function transferAndChargeForGas(\n address from,\n address to,\n uint256 amount,\n uint256 gasLimit,\n uint256 tokenGasPrice,\n uint256 baseGasCharge,\n address tokenReceiver\n ) external returns (bool) {\n uint256 initialGas = gasleft();\n require(_executionOperators[msg.sender], \"only execution operators allowed to perfrom transfer and charge\");\n _transfer(from, to, amount);\n if (tokenGasPrice > 0) {\n _charge(from, gasLimit, tokenGasPrice, initialGas, baseGasCharge, tokenReceiver);\n }\n return true;\n }\n\n function _charge(\n address from,\n uint256 gasLimit,\n uint256 tokenGasPrice,\n uint256 initialGas,\n uint256 baseGasCharge,\n address tokenReceiver\n ) internal {\n uint256 gasCharge = initialGas - gasleft();\n if(gasCharge > gasLimit) {\n gasCharge = gasLimit;\n }\n gasCharge += baseGasCharge;\n uint256 tokensToCharge = gasCharge * tokenGasPrice;\n require(tokensToCharge / gasCharge == tokenGasPrice, \"overflow\");\n _transfer(from, tokenReceiver, tokensToCharge);\n }\n\n function _approveAndExecuteWithSpecificGas(\n address from,\n address to,\n uint256 amount,\n uint256 gasLimit,\n bytes memory data\n ) internal returns (bool success, bytes memory returnData) {\n\n if (amount > 0) {\n _addAllowanceIfNeeded(from, to, amount);\n }\n (success, returnData) = to.call.gas(gasLimit)(data);\n assert(gasleft() > gasLimit / 63); // not enough gas provided, assert to throw all gas // TODO use EIP-1930\n }\n\n\n function _transfer(address from, address to, uint256 amount) internal;\n function _addAllowanceIfNeeded(address owner, address spender, uint256 amountNeeded) internal;\n}",
"keccak256": "0x4b9a75299ab80e84aa287f2ecf2ef175e0feb074764e4a670f9397a2d2d4bda8"
}
},
"version": 1
}
View in Huly HI-8
In a special case where both monitor and server try to write to the same file simultaneously unpredictable stuff could happen with both server and monitor containers
View in Huly HI-34
Would be nice to have a check of this before restructuring the project and converting to typescript. Might look like:
View in Huly HI-15
The file upload mechanism should be done in client-side javascript to allow for the following:
Some of these tasks could also be done server-side, but the state should be kept on the client side.
It should still be possible to work with "dumb clients", i.e. external file uploads not using the client-side javascript, so some functionality should be put in modules that can be used both on the client and on the server side.
View in Huly HI-24
View in Huly HI-33
Get directory listing, not just raw files.
View in Huly HI-39
This repository currently contains quite some code repetition. It should be refactored.
This includes extracting the shared components in the monitor and the injector and rewriting them in typescript.
View in Huly HI-23
Currently, files are only downloaded from swarm by default. We should also support ipfs links.
View in Huly HI-21
Server:
Error: Error: Given address "0x00000000000000000000" is not a valid Ethereum address.
UI:
View in Huly HI-14
The various components here move data around in queues. We should have a generic architecture for that.
View in Huly HI-265
Issue: "Error: Metadata file not found. Did you include "metadata.json"?" when using the UI
Screen shot of inputs:
System : Tried on both Chrome and Firefox same issue
metadata.json was generated using solc --metadata --metadata-literal
as well as passed it into source-verify/index.js < metadata.json with output
Metadata MATCHES!
Bytecode comparison NOT performed - has to be done manually.
Sample contract used was 0xd2006b3452ff12ce48d018ff48e0df76bca6ee04 where we've already uploaded the source to ipfs here: https://ipfs.infura.io/ipfs/Qmbu6TMyKCH9HJVvhG6BFA3UkrJuGVdZjhFQqKRRKmsNyD
View in Huly HI-7
Hey looking at https://github.com/ethereum/source-verify/blob/ce90b0fa9c25f4c3183bca884376480dbbb39bd0/verify.js#L59
Why is the metadata not the same as the solc json input ? This would make sense no ?
View in Huly HI-84
Create new endpoint inside server.js For example: app.get('/health', (req, res) => res.send("I'm alive"))
This endpoint will be pinged every minute or two.
Also, create docker-compose for monitor.js that automatically restarts monitor if it fails.
View in Huly HI-10
It might be useful to have a base branch that new work is targeted at, preserving the current project state until it's safe to merge.
View in Huly HI-9
View in Huly HI-25
Tracking issue to look over ui css and identify any small things to normalize.
View in Huly HI-48
This error periodically happens on CI
https://circleci.com/gh/ethereum/source-verify/442
View in Huly HI-32
The server-side component should report why something went wrong and how much it was able to do so far.
View in Huly HI-29
We should offer an interface so that other people can clone and host the same data via ipfs.
View in Huly HI-408
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.