add missing files on bbgo contract folder

This commit is contained in:
zenix 2022-01-20 16:22:44 +09:00 committed by zenix
parent a29198f733
commit 3717148b7a
22 changed files with 33071 additions and 16 deletions

17
contracts/.eslintrc.js Normal file
View File

@ -0,0 +1,17 @@
module.exports = {
parser: 'babel-eslint',
extends: 'standard',
env: {
node: true,
es6: true,
mocha: true
},
rules: {
'space-before-function-paren': ['error', 'never']
},
globals: {
contract: true,
web3: true,
assert: true
}
}

8
contracts/.solhint.json Normal file
View File

@ -0,0 +1,8 @@
{
"extends": "solhint:recommended",
"plugins": [],
"rules": {
"compiler-version": ["error", ">=0.6.6"],
"reason-string": ["warn", {"maxLength": 64}]
}
}

View File

@ -1,7 +1,51 @@
# BBG Contracts
------------
### 1. Before Start
truffle migrate --network polygon Create and modify the following files in this directory, the secret key inside the files are dummy ones from truffle dev server:
- development-secret.json
- polygon-secret.json
- bsc-secret.json
### 2. Prepare the dependencies
```bash
npm i
# if you want to develope in localhost, try to run npm run devserver separately
# ex: npm run devserver
# it will give you a set of secrets and account addresses
```
### 3. Deploy
Migrate:
```bash
npm run migrate:dev
# npm run migrate:polygon
# npm run migrate:polygon-test
# npm run migrate:bsc
# npm run migrate:bsc-test
```
Lint:
```bash
npm run lint
# # fix solidity issue
# npm run lint:sol:fix
# # fix js issue
# npm run lint:js:fix
```
Test:
```bash
npm run test
```
```bash
truffle run verify ChildMintableERC20 --network polygon truffle run verify ChildMintableERC20 --network polygon
```
```bash
truffle run verify ChildMintableERC20@0x3Afe98235d680e8d7A52e1458a59D60f45F935C0 --network polygon truffle run verify ChildMintableERC20@0x3Afe98235d680e8d7A52e1458a59D60f45F935C0 --network polygon
```

View File

@ -0,0 +1,4 @@
{
"privateKey": "3899a918953e01bfe218116cdfeccbed579e26275c4a89abcbc70d2cb9e9bbb8",
"etherScanApiKey": ""
}

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0; pragma solidity >=0.4.22 <0.9.0;
contract Migrations { contract Migrations {
address public owner = msg.sender; address public owner = msg.sender;
uint public last_completed_migration; uint public last_completed_migration;

View File

@ -0,0 +1,79 @@
pragma solidity 0.6.6;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {AccessControlMixin} from "../../common/AccessControlMixin.sol";
import {IChildToken} from "./IChildToken.sol";
import {NativeMetaTransaction} from "../../common/NativeMetaTransaction.sol";
import {ContextMixin} from "../../common/ContextMixin.sol";
contract ChildMintableERC20 is
ERC20,
IChildToken,
AccessControlMixin,
NativeMetaTransaction,
ContextMixin
{
bytes32 public constant DEPOSITOR_ROLE = keccak256("DEPOSITOR_ROLE");
constructor(
string memory name_,
string memory symbol_,
uint8 decimals_,
address childChainManager
) public ERC20(name_, symbol_) {
_setupContractId("ChildMintableERC20");
_setupDecimals(decimals_);
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
_setupRole(DEPOSITOR_ROLE, childChainManager);
_initializeEIP712(name_);
}
// This is to support Native meta transactions
// never use msg.sender directly, use _msgSender() instead
function _msgSender()
internal
override
view
returns (address payable sender)
{
return ContextMixin.msgSender();
}
/**
* @notice called when token is deposited on root chain
* @dev Should be callable only by ChildChainManager
* Should handle deposit by minting the required amount for user
* Make sure minting is done only by this function
* @param user user address for whom deposit is being done
* @param depositData abi encoded amount
*/
function deposit(address user, bytes calldata depositData)
external
override
only(DEPOSITOR_ROLE)
{
uint256 amount = abi.decode(depositData, (uint256));
_mint(user, amount);
}
/**
* @notice called when user wants to withdraw tokens back to root chain
* @dev Should burn user's tokens. This transaction will be verified when exiting on root chain
* @param amount amount of tokens to withdraw
*/
function withdraw(uint256 amount) external {
_burn(_msgSender(), amount);
}
/**
* @notice Example function to handle minting tokens on matic chain
* @dev Minting can be done as per requirement,
* This implementation allows only admin to mint tokens but it can be changed as per requirement
* @param user user for whom tokens are being minted
* @param amount amount of token to mint
*/
function mint(address user, uint256 amount) public only(DEFAULT_ADMIN_ROLE) {
_mint(user, amount);
}
}

View File

@ -0,0 +1,5 @@
pragma solidity 0.6.6;
interface IChildToken {
function deposit(address user, bytes calldata depositData) external;
}

View File

@ -0,0 +1,19 @@
pragma solidity 0.6.6;
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
contract AccessControlMixin is AccessControl {
string private _revertMsg;
function _setupContractId(string memory contractId) internal {
_revertMsg = string(abi.encodePacked(contractId, ": INSUFFICIENT_PERMISSIONS"));
}
modifier only(bytes32 role) {
require(
hasRole(role, _msgSender()),
_revertMsg
);
_;
}
}

View File

@ -0,0 +1,25 @@
pragma solidity 0.6.6;
abstract contract ContextMixin {
function msgSender()
internal
view
returns (address payable sender)
{
if (msg.sender == address(this)) {
bytes memory array = msg.data;
uint256 index = msg.data.length;
/* solhint-disable no-inline-assembly */
assembly {
// Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those.
sender := and(
mload(add(array, index)),
0xffffffffffffffffffffffffffffffffffffffff
)
}
} else {
sender = msg.sender;
}
return sender;
}
}

View File

@ -0,0 +1,77 @@
pragma solidity 0.6.6;
import {Initializable} from "./Initializable.sol";
contract EIP712Base is Initializable {
struct EIP712Domain {
string name;
string version;
address verifyingContract;
bytes32 salt;
}
string constant public ERC712_VERSION = "1";
bytes32 internal constant EIP712_DOMAIN_TYPEHASH = keccak256(
bytes(
"EIP712Domain(string name,string version,address verifyingContract,bytes32 salt)"
)
);
bytes32 internal domainSeperator;
// supposed to be called once while initializing.
// one of the contractsa that inherits this contract follows proxy pattern
// so it is not possible to do this in a constructor
function _initializeEIP712(
string memory name
)
internal
initializer
{
_setDomainSeperator(name);
}
function _setDomainSeperator(string memory name) internal {
domainSeperator = keccak256(
abi.encode(
EIP712_DOMAIN_TYPEHASH,
keccak256(bytes(name)),
keccak256(bytes(ERC712_VERSION)),
address(this),
bytes32(getChainId())
)
);
}
function getDomainSeperator() public view returns (bytes32) {
return domainSeperator;
}
function getChainId() public pure returns (uint256) {
uint256 id;
/* solhint-disable no-inline-assembly */
assembly {
id := chainid()
}
return id;
}
/**
* Accept message hash and returns hash message in EIP712 compatible form
* So that it can be used to recover signer from signature signed using EIP712 formatted data
* https://eips.ethereum.org/EIPS/eip-712
* "\\x19" makes the encoding deterministic
* "\\x01" is the version byte to make it compatible to EIP-191
*/
function toTypedMessageHash(bytes32 messageHash)
internal
view
returns (bytes32)
{
return
keccak256(
abi.encodePacked("\x19\x01", getDomainSeperator(), messageHash)
);
}
}

View File

@ -0,0 +1,12 @@
pragma solidity 0.6.6;
contract Initializable {
bool public inited = false;
modifier initializer() {
require(!inited, "already inited");
_;
inited = true;
}
}

View File

@ -0,0 +1,106 @@
pragma solidity 0.6.6;
import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
import {EIP712Base} from "./EIP712Base.sol";
contract NativeMetaTransaction is EIP712Base {
using SafeMath for uint256;
bytes32 private constant META_TRANSACTION_TYPEHASH = keccak256(
bytes(
"MetaTransaction(uint256 nonce,address from,bytes functionSignature)"
)
);
event MetaTransactionExecuted(
address userAddress,
address payable relayerAddress,
bytes functionSignature
);
mapping(address => uint256) public nonces;
/*
* Meta transaction structure.
* No point of including value field here as if user is doing value transfer then he has the funds to pay for gas
* He should call the desired function directly in that case.
*/
struct MetaTransaction {
uint256 nonce;
address from;
bytes functionSignature;
}
function executeMetaTransaction(
address userAddress,
bytes memory functionSignature,
bytes32 sigR,
bytes32 sigS,
uint8 sigV
) public payable returns (bytes memory) {
MetaTransaction memory metaTx = MetaTransaction({
nonce: nonces[userAddress],
from: userAddress,
functionSignature: functionSignature
});
require(
verify(userAddress, metaTx, sigR, sigS, sigV),
"Signer and signature do not match"
);
// increase nonce for user (to avoid re-use)
nonces[userAddress] = nonces[userAddress].add(1);
emit MetaTransactionExecuted(
userAddress,
msg.sender,
functionSignature
);
// Append userAddress and relayer address at the end to extract it from calling context
/* solhint-disable avoid-low-level-calls */
(bool success, bytes memory returnData) = address(this).call(
abi.encodePacked(functionSignature, userAddress)
);
require(success, "Function call not successful");
return returnData;
}
function hashMetaTransaction(MetaTransaction memory metaTx)
internal
pure
returns (bytes32)
{
return
keccak256(
abi.encode(
META_TRANSACTION_TYPEHASH,
metaTx.nonce,
metaTx.from,
keccak256(metaTx.functionSignature)
)
);
}
function getNonce(address user) public view returns (uint256 nonce) {
nonce = nonces[user];
}
function verify(
address signer,
MetaTransaction memory metaTx,
bytes32 sigR,
bytes32 sigS,
uint8 sigV
) internal view returns (bool) {
require(signer != address(0), "NativeMetaTransaction: INVALID_SIGNER");
return
signer ==
ecrecover(
toTypedMessageHash(hashMetaTransaction(metaTx)),
sigV,
sigR,
sigS
);
}
}

View File

@ -0,0 +1,7 @@
pragma solidity 0.6.6;
interface IERCProxy {
function proxyType() external pure returns (uint256 proxyTypeId);
function implementation() external view returns (address codeAddr);
}

View File

@ -0,0 +1,39 @@
pragma solidity 0.6.6;
import {IERCProxy} from "./IERCProxy.sol";
abstract contract Proxy is IERCProxy {
function delegatedFwd(address _dst, bytes memory _calldata) internal {
// solium-disable-next-line security/no-inline-assembly
assembly {
let result := delegatecall(
sub(gas(), 10000),
_dst,
add(_calldata, 0x20),
mload(_calldata),
0,
0
)
let size := returndatasize()
let ptr := mload(0x40)
returndatacopy(ptr, 0, size)
// revert instead of invalid() bc if the underlying call failed with invalid() it already wasted gas.
// if the call returned error data, forward it
switch result
case 0 {
revert(ptr, size)
}
default {
return(ptr, size)
}
}
}
function proxyType() external virtual override pure returns (uint256 proxyTypeId) {
// Upgradeable proxy
proxyTypeId = 2;
}
function implementation() external virtual override view returns (address);
}

View File

@ -0,0 +1,103 @@
pragma solidity 0.6.6;
import {Proxy} from "./Proxy.sol";
contract UpgradableProxy is Proxy {
event ProxyUpdated(address indexed _new, address indexed _old);
event ProxyOwnerUpdate(address _new, address _old);
bytes32 constant IMPLEMENTATION_SLOT = keccak256("matic.network.proxy.implementation");
bytes32 constant OWNER_SLOT = keccak256("matic.network.proxy.owner");
constructor(address _proxyTo) public {
setProxyOwner(msg.sender);
setImplementation(_proxyTo);
}
fallback() external payable {
delegatedFwd(loadImplementation(), msg.data);
}
receive() external payable {
delegatedFwd(loadImplementation(), msg.data);
}
modifier onlyProxyOwner() {
require(loadProxyOwner() == msg.sender, "NOT_OWNER");
_;
}
function proxyOwner() external view returns(address) {
return loadProxyOwner();
}
function loadProxyOwner() internal view returns(address) {
address _owner;
bytes32 position = OWNER_SLOT;
assembly {
_owner := sload(position)
}
return _owner;
}
function implementation() external override view returns (address) {
return loadImplementation();
}
function loadImplementation() internal view returns(address) {
address _impl;
bytes32 position = IMPLEMENTATION_SLOT;
assembly {
_impl := sload(position)
}
return _impl;
}
function transferProxyOwnership(address newOwner) public onlyProxyOwner {
require(newOwner != address(0), "ZERO_ADDRESS");
emit ProxyOwnerUpdate(newOwner, loadProxyOwner());
setProxyOwner(newOwner);
}
function setProxyOwner(address newOwner) private {
bytes32 position = OWNER_SLOT;
assembly {
sstore(position, newOwner)
}
}
function updateImplementation(address _newProxyTo) public onlyProxyOwner {
require(_newProxyTo != address(0x0), "INVALID_PROXY_ADDRESS");
require(isContract(_newProxyTo), "DESTINATION_ADDRESS_IS_NOT_A_CONTRACT");
emit ProxyUpdated(_newProxyTo, loadImplementation());
setImplementation(_newProxyTo);
}
function updateAndCall(address _newProxyTo, bytes memory data) payable public onlyProxyOwner {
updateImplementation(_newProxyTo);
(bool success, bytes memory returnData) = address(this).call{value: msg.value}(data);
require(success, string(returnData));
}
function setImplementation(address _newProxyTo) private {
bytes32 position = IMPLEMENTATION_SLOT;
assembly {
sstore(position, _newProxyTo)
}
}
function isContract(address _target) internal view returns (bool) {
if (_target == address(0)) {
return false;
}
uint256 size;
assembly {
size := extcodesize(_target)
}
return size > 0;
}
}

View File

@ -0,0 +1,4 @@
{
"privateKey": "3899a918953e01bfe218116cdfeccbed579e26275c4a89abcbc70d2cb9e9bbb8",
"etherScanApiKey": ""
}

View File

@ -1,4 +1,4 @@
var ChildMintableERC20 = artifacts.require("./ChildMintableERC20.sol"); var ChildMintableERC20 = artifacts.require("ChildMintableERC20");
module.exports = function(deployer) { module.exports = function(deployer) {
deployer.deploy(ChildMintableERC20, 'BBGO', 'BBG', 18, '0xA6FA4fB5f76172d178d61B04b0ecd319C5d1C0aa'); deployer.deploy(ChildMintableERC20, 'BBGO', 'BBG', 18, '0xA6FA4fB5f76172d178d61B04b0ecd319C5d1C0aa');

32452
contracts/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -17,11 +17,24 @@
"ethereum-waffle": "^3.4.0", "ethereum-waffle": "^3.4.0",
"ethers": "^5.4.7", "ethers": "^5.4.7",
"hardhat": "^2.6.5", "hardhat": "^2.6.5",
"prettier": "^2.5.1",
"solhint": "^3.3.6",
"truffle-plugin-verify": "^0.5.18" "truffle-plugin-verify": "^0.5.18"
}, },
"scripts": { "scripts": {
"test": "mocha" "devserver": "KEY=development-secret.json truffle develop",
"test": "KEY=development-secret.json truffle test",
"migrate:dev": "KEY=development-secret.json truffle migrate --network development",
"migrate:polygon": "KEY=polygon-secret.json truffle migrate --network polygon",
"migrate:polygon-test": "KEY=polygon-secret.json truffle migrate --network mumbai",
"migrate:bsc": "KEY=bsc-secret.json truffle migrate --network bsc",
"migrate:bsc-test": "KEY=bsc-secret.json truffle migrate --network bsctestnet",
"lint": "npm run lint:sol && npm run lint:js",
"lint:js:fix": "prettier --write test/**/*.js",
"lint:js": "prettier test/**/*.js",
"lint:sol": "solhint contracts/**/*.sol",
"lint:sol:fix": "solhint -d contracts/**/*.sol --fix"
}, },
"author": "", "author": "starcrypto",
"license": "ISC" "license": "MIT"
} }

View File

@ -0,0 +1,4 @@
{
"privateKey": "3899a918953e01bfe218116cdfeccbed579e26275c4a89abcbc70d2cb9e9bbb8",
"etherScanApiKey": ""
}

16
contracts/test/erc20.js Normal file
View File

@ -0,0 +1,16 @@
const ChildMintableERC20 = artifacts.require("ChildMintableERC20");
contract("ChildMintableERC20", (accounts) => {
it("should have BBG deployed", async () => {
const instance = await ChildMintableERC20.deployed();
const name = await instance.name();
const decimal = await instance.decimals();
const symbol = await instance.symbol();
const balance = await instance.balanceOf(accounts[0]);
const totalSupply = await instance.totalSupply();
assert.equal(name.valueOf(), "BBGO");
assert.equal(symbol.valueOf(), "BBG");
assert.equal(decimal.toNumber(), 18);
assert.equal(balance.toNumber(), 0);
assert.equal(totalSupply.toNumber(), 0);
});
});

View File

@ -19,7 +19,8 @@
*/ */
const fs = require('fs'); const fs = require('fs');
const HDWalletProvider = require('@truffle/hdwallet-provider'); const HDWalletProvider = require('@truffle/hdwallet-provider');
const secret = JSON.parse(fs.readFileSync("polygon-secret.json").toString().trim()); const secret = JSON.parse(fs.readFileSync(process.env.KEY).toString().trim());
module.exports = { module.exports = {
/** /**
@ -69,6 +70,11 @@ module.exports = {
// network_id: 2111, // This network is yours, in the cloud. // network_id: 2111, // This network is yours, in the cloud.
// production: true // Treats this network as if it was a public net. (default: false) // production: true // Treats this network as if it was a public net. (default: false)
// } // }
development: {
host: "127.0.0.1",
port: 9545,
network_id: "*",
},
polygon: { polygon: {
provider: () => new HDWalletProvider(secret.privateKey, "https://polygon-rpc.com"), provider: () => new HDWalletProvider(secret.privateKey, "https://polygon-rpc.com"),
network_id: 137, network_id: 137,
@ -83,6 +89,20 @@ module.exports = {
timeoutBlocks: 200, timeoutBlocks: 200,
skipDryRun: true skipDryRun: true
}, },
bsctestnet: {
// "https://speedy-nodes-nyc.moralis.io/91d001d6e2a55a9696521b4b/bsc/testnet"
provider: () => new HDWalletProvider(secret.privateKey, "https://data-seed-prebsc-1-s1.binance.org:8545"),
network_id: 97,
confirmations: 10,
timeoutBlocks: 200,
},
bsc: {
provider: () => new HDWalletProvider(secret.privateKey, "https://bsc-dataseed1.binance.org"),
network_id: 56,
confirmations: 10,
timeoutBlocks: 200,
skipDryRun: true
},
}, },
// Set default mocha options here, use special reporters etc. // Set default mocha options here, use special reporters etc.