-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #66 from ferrumnet/develop
Release - Testnet
- Loading branch information
Showing
159 changed files
with
13,264 additions
and
6,095 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,47 @@ | ||
##### | ||
# | ||
# This config file is used by the QP deploy script. | ||
# First, remove the hardcoded contract address for the contract you want to be deployed. | ||
# Then, after deployment, put the deployed addresses, in the config and send a commit | ||
# tagged with UPDATE_QP_CONFIG | ||
# | ||
# Use $in the DeployerKeys section to get the value from an environment variable | ||
# Note: If you provide `DeployerKeys.Owner`, you do NOT need to provide the `Owner` | ||
# | ||
##### | ||
|
||
Owner: "0xf1b1145f83cadd5199f8D8E937Aa07979e2806Aa" | ||
DeployerContract: "0xDACa19A67eB89D610eDFd891594108B569c379c0" | ||
DeployerSalt: "0x65ff7961289d09280b311966c72b708989daabefb729d1a5b64fe72a9ad26049" | ||
QuantumPortalGateway: | ||
QuantumPortalState: | ||
QuantumPortalPoc: | ||
QuantumPortalLedgerMgr: | ||
QuantumPortalAuthorityMgr: "0xe776Fedb74e85CFe6677b6774E5898c1d41867D7" | ||
QuantumPortalFeeConvertorDirect: "0x431D332F39A90e4478Ae3a13C8e17Bae1BfdDC73" | ||
QuantumPortalMinerMgr: "0x391870f7FFEC11582f3d1Dc6bc0EE7ec8e63C16f" | ||
QuantumPortalStake: "0xB1CcE8e7039395348283cbb267007351a7777876" | ||
QuantumPortalMinStake?: "10000000000000000000" | ||
Owner: '' | ||
DeployerContract: '' | ||
DeployerSalt: '' | ||
QuantumPortalGateway: '0x783eaa3d0faC7e1e335705A0554cD98E15e72dFD' | ||
QuantumPortalPoc: '0x968D9e7De42b224a67E131EE26893Ef3dC846A1e' | ||
QuantumPortalLedgerMgr: '0xfe3031004aDB3b621Fe20132e435ff6f491234DB' | ||
QuantumPortalAuthorityMgr: '0xB4C97f762BCcd93632346738Ea09157A91d8cA91' | ||
QuantumPortalFeeConvertorDirect: '0xa3753397B83725Fca56719Af9E7527a098021878' | ||
QuantumPortalMinerMgr: '0xbf18631e92A21b1DD4C6Cc49CF6A0d500A41f74A' | ||
QuantumPortalStake: '0x2E37B6D588c105f9b12ca5C2bfED009582dd3341' | ||
QuantumPortalNativeFeeRepo: '0x7A2C78415267d1125d7d05402d743f9ae675F6a7' | ||
QuantumPortalMinStake: '10000000000000000000' | ||
FRM: | ||
97: "0xF3B61752E52B92BB0B8bF9eBb4FE487B8fD1047C" | ||
43113: "0xF3B61752E52B92BB0B8bF9eBb4FE487B8fD1047C" | ||
80001: "0xF3B61752E52B92BB0B8bF9eBb4FE487B8fD1047C" | ||
26100: "0x0000000000000000000000000000000000026026" | ||
81: "0x78B94f1C07b1467D25cde8803E5c8B85d98CCA12" | ||
WFRM: "0x0000000000000000000000000000000000026026" | ||
'56': '0x0000000000000000000000000000000000026026' | ||
'81': '0x78B94f1C07b1467D25cde8803E5c8B85d98CCA12' | ||
'97': '0xF3B61752E52B92BB0B8bF9eBb4FE487B8fD1047C' | ||
'26100': '0x71156ADcddCA1DB1283EA5AA6436c5a1639b1FA2' | ||
'31337': '0xd12e9329865B6423E39a2E4C3d58b7a1C52f3849' | ||
'42161': '0x6D34420DcAf516bEc9D81e5d79FAC2100058C9AC' | ||
'43113': '0xF3B61752E52B92BB0B8bF9eBb4FE487B8fD1047C' | ||
'80001': '0xF3B61752E52B92BB0B8bF9eBb4FE487B8fD1047C' | ||
WFRM: '0x0000000000000000000000000000000000026026' | ||
WETH: | ||
97: "0x0000000000000000000000000000000000026026" | ||
43113: "0x0000000000000000000000000000000000026026" | ||
80001: "0x0000000000000000000000000000000000026026" | ||
26026: "0x0000000000000000000000000000000000026026" | ||
81: "0x78B94f1C07b1467D25cde8803E5c8B85d98CCA12" | ||
'56': '0x0000000000000000000000000000000000026026' | ||
'81': '0x78B94f1C07b1467D25cde8803E5c8B85d98CCA12' | ||
'97': '0x0000000000000000000000000000000000026026' | ||
'26026': '0x0000000000000000000000000000000000026026' | ||
'26100': '0x0000000000000000000000000000000000026026' | ||
'31337': '0x0000000000000000000000000000000000026026' | ||
'43113': '0x0000000000000000000000000000000000026026' | ||
'80001': '0x0000000000000000000000000000000000026026' | ||
UniV2Factory: | ||
97: "0x0000000000000000000000000000000000026026" | ||
43113: "0x0000000000000000000000000000000000026026" | ||
80001: "0x0000000000000000000000000000000000026026" | ||
26026: "0x0000000000000000000000000000000000026026" | ||
'56': '' | ||
'97': '0x0000000000000000000000000000000000026026' | ||
'26026': '0x0000000000000000000000000000000000026026' | ||
'31337': '0x0000000000000000000000000000000000026026' | ||
'43113': '0x0000000000000000000000000000000000026026' | ||
'80001': '0x0000000000000000000000000000000000026026' | ||
DirectFee: | ||
feePerByte: "10000000000000" | ||
feePerByte: '10000000000000' | ||
DeployerKeys: | ||
DeployerContract: $CONTRACT_DEPLOYER_KEY | ||
Qp: $QP_DEPLOYER_KEY | ||
Owner: $QP_DEPLOYER_KEY | ||
DeployerContract: | ||
type: secret | ||
env: PAIVATE_KEY_SECRET_ARN | ||
value: PRIVATEKEY_TEST_VALIDATOR | ||
Qp: c51a3cddd45c4be158d9ca4450402ee96c34639b50ed990964d0990d8736c6b7 | ||
Owner: c51a3cddd45c4be158d9ca4450402ee96c34639b50ed990964d0990d8736c6b7 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
import os | ||
import json | ||
import json5 | ||
import re | ||
import argparse | ||
|
||
def read_file(file_path): | ||
with open(file_path, 'r') as file: | ||
return file.read() | ||
|
||
def apply_remappings(import_path, remappings): | ||
for prefix, target in remappings: | ||
if import_path.startswith(prefix): | ||
return import_path.replace(prefix, target, 1) | ||
return import_path | ||
|
||
def get_imports(file_content): | ||
import_pattern = re.compile(r'import\s+(?:(?:["\']([^"\']+)["\'])|(?:{[^}]*}\s+from\s+["\']([^"\']+)["\']));') | ||
matches = import_pattern.findall(file_content) | ||
# Extract the import paths from the matches | ||
imports = [match[0] if match[0] else match[1] for match in matches] | ||
return imports | ||
|
||
def get_all_dependencies(contract_path, main_contract, remappings): | ||
def recursive_find_dependencies(file_path, sources, visited): | ||
if file_path in visited: | ||
return | ||
visited.add(file_path) | ||
file_content = read_file(file_path) | ||
cwd = os.path.abspath(".") + "/" | ||
clean_path = file_path.replace(cwd, "") | ||
clean_path = clean_path.replace("node_modules/", "") | ||
sources[clean_path] = {"content": file_content} | ||
imports = get_imports(file_content) | ||
print("IMPORTS", clean_path, imports) | ||
for import_path in imports: | ||
mapped_import_path = apply_remappings(import_path, remappings) | ||
absolute_import_path = os.path.abspath(os.path.normpath(os.path.join(os.path.dirname(file_path), mapped_import_path))) | ||
if os.path.exists(absolute_import_path): | ||
print("imported ", import_path) | ||
recursive_find_dependencies(absolute_import_path, sources, visited) | ||
else: | ||
print(f"Warning: Import {import_path} not found.", absolute_import_path) | ||
|
||
sources = {} | ||
visited = set() | ||
main_contract_path = os.path.join(contract_path, main_contract) | ||
recursive_find_dependencies(main_contract_path, sources, visited) | ||
return sources | ||
|
||
def get_hardhat_config(config_path): | ||
with open(config_path, 'r') as f: | ||
return json5.load(f) | ||
|
||
def parse_remappings(remappings): | ||
parsed_remappings = [] | ||
for remapping in remappings: | ||
prefix, target = remapping.split('=') | ||
parsed_remappings.append((prefix, os.path.abspath(target) + "/")) | ||
return parsed_remappings | ||
|
||
def generate_standard_input_json(contract_path, config_path, main_contract): | ||
hardhat_config = get_hardhat_config(config_path) | ||
remappings = parse_remappings(hardhat_config.get('remappings', [])) | ||
sources = get_all_dependencies(contract_path, main_contract, remappings) | ||
hardhat_config = get_hardhat_config(config_path) | ||
|
||
optimizer_settings = hardhat_config['solidity']['settings']['optimizer'] | ||
evm_version = hardhat_config['solidity']['settings'].get('evmVersion', 'istanbul') | ||
|
||
libraries = {} | ||
if 'libraries' in hardhat_config['solidity']['settings']: | ||
libraries = hardhat_config['solidity']['settings']['libraries'] | ||
|
||
remappings = [] | ||
if 'remappings' in hardhat_config: | ||
remappings = hardhat_config['remappings'] | ||
|
||
standard_input_json = { | ||
"language": "Solidity", | ||
"sources": sources, | ||
"settings": { | ||
"optimizer": optimizer_settings, | ||
"evmVersion": evm_version, | ||
"outputSelection": { | ||
"*": { | ||
"*": [ | ||
"abi", | ||
"evm.bytecode", | ||
"evm.deployedBytecode", | ||
"evm.methodIdentifiers" | ||
], | ||
"": [ | ||
"ast" | ||
] | ||
} | ||
}, | ||
"libraries": libraries, | ||
#"remappings": remappings | ||
} | ||
} | ||
|
||
return standard_input_json | ||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser(description="Generate Solidity Standard Input JSON for a specific contract file.") | ||
parser.add_argument("contract_file", help="The main Solidity contract file to verify, e.g., MyContract.sol") | ||
args = parser.parse_args() | ||
|
||
contract_path = "contracts" # Path to your contracts directory | ||
config_path = "hardhat.config.json" # Path to your Hardhat config file | ||
main_contract = args.contract_file # Main contract file to verify | ||
|
||
standard_input_json = generate_standard_input_json(contract_path, config_path, main_contract) | ||
|
||
output_dir = os.path.join("artifacts", "standard_input", os.path.splitext(main_contract)[0]) | ||
os.makedirs(output_dir, exist_ok=True) | ||
output_path = os.path.join(output_dir, "standard_input.json") | ||
|
||
with open(output_path, 'w') as f: | ||
json.dump(standard_input_json, f, indent=4) | ||
|
||
print(f"Standard input JSON written to {output_path}") | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
#!/bin/bash | ||
|
||
echo "npx hardhat node --fork https://eth-mainnet.alchemyapi.io/v2/$ALCHEMY_API_KEY" | ||
npx hardhat node --fork https://eth-mainnet.alchemyapi.io/v2/$ALCHEMY_API_KEY |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
pragma solidity ^0.8.24; | ||
|
||
error CallFailed(address target, bytes call, bytes err); | ||
|
||
contract BatchCall { | ||
function batchCall(address target, bytes[] calldata calls) external { | ||
for(uint i=0; i<calls.length; i++) { | ||
(bool result, bytes memory err) = target.call(calls[i]); | ||
if (!result) revert CallFailed(target, calls[i], err); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
pragma solidity ^0.8.24; | ||
|
||
import "./QpErc20Token.sol"; | ||
import "./IFeeStore.sol"; | ||
|
||
error FeeIsLessThanAmountSentToQp(uint amount, uint fee); | ||
|
||
contract Bitcoin is QpErc20Token { | ||
uint constant SATOSHI_TO_NAKAMOTO_CONVERSION = 1 gwei; | ||
function initialize( | ||
) external initializer { | ||
__QPERC20_init(0, 0, "Bitcoin", "BTC", 18, 0); | ||
__TokenReceivable_init(); | ||
__Context_init(); | ||
} | ||
|
||
/** | ||
* @notice Procecess the fee and updates the amount if necessary | ||
*/ | ||
function collectFeeForFutureUse(bytes32 txId, uint feeInBtc) internal returns (uint) { | ||
QpErc20Storage storage $ = _getQPERC20Storage(); | ||
address feeStore = $.factory.feeStore(); | ||
_mintQp(feeStore, feeInBtc); | ||
IFeeStore(feeStore).swapBtcWithFee(txId, feeInBtc); | ||
} | ||
|
||
/** | ||
* @notice Procecess the fee and updates the amount if necessary | ||
*/ | ||
function processFee(bytes32 txId, uint amount, uint feeInBtc) internal override returns (uint) { | ||
QpErc20Storage storage $ = _getQPERC20Storage(); | ||
feeInBtc *= SATOSHI_TO_NAKAMOTO_CONVERSION; // Fee is in sats. We convert it to nakamoto | ||
if (amount < feeInBtc) { | ||
revert FeeIsLessThanAmountSentToQp(amount, feeInBtc); | ||
} | ||
collectFeeForFutureUse(txId, feeInBtc); | ||
$.factory.feeStoreCollectFee(txId); // Merge the two steps, where in case of rune, these two steps are managed in separate mining calls | ||
return amount - feeInBtc; | ||
} | ||
|
||
function preProcessValues(uint[] memory values) internal pure override returns (uint[] memory) { | ||
for (uint i=0; i<values.length; i++) { | ||
values[i] *= SATOSHI_TO_NAKAMOTO_CONVERSION; | ||
} | ||
return values; | ||
} | ||
|
||
function processRemoteCall(bytes32 txId, bytes memory remoteCall, uint amount) internal override { | ||
if (remoteCall.length == 0) { | ||
// Just collect the fee | ||
collectFeeForFutureUse(txId, amount); | ||
} else { | ||
QpErc20Token.processRemoteCall(txId, remoteCall, amount); | ||
} | ||
} | ||
|
||
/** | ||
* @notice Collects fee for BTC. Difference is that the fee can be taked without allowance | ||
*/ | ||
function collectSettlementFee(uint feeToCollect) internal override returns (uint) { | ||
if (feeToCollect != 0) { | ||
_transferQp(_msgSender(), address(this), feeToCollect); | ||
} | ||
return sync(address(this)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
pragma solidity ^0.8.24; | ||
|
||
library BtcLib { | ||
struct TransferItem { | ||
address addr; | ||
uint value; | ||
} | ||
|
||
function parseBtcAddress(string calldata btcAddress) internal view returns (address) { | ||
// TODO: Call pre-compile | ||
} | ||
|
||
function initiateWithdrawal(string calldata btcAddress, uint tokenId, uint version, uint btcFee, bytes32 settlementId) internal { | ||
// TODO: Call pre-compile | ||
// Note. Pre-compile identifies who the caller is by verifying that msg.sender mapps to the token ID | ||
// For example, for rune tokens, we need to check the CREATE2 formula, to come up with the same address | ||
// Or for the case of BTC, we already know what is the BTC token address | ||
// If a token is requesting withdrawal that is not supported we just revert the tx. | ||
// Note: This should fail if there is not enough BTC to pay for the gas. | ||
} | ||
|
||
function extractSenderAndProxyFromTx(bytes32 txid) internal returns (address sender, address proxyWallet) { | ||
// TODO: Call pre-compile | ||
// This will decode a tx. First input will be the `sender` and | ||
// the address inscripted in the script is the `proxyWallet` | ||
} | ||
|
||
/** | ||
* TODO: Call pre-compile | ||
* Parse the transaction, and extract calls. | ||
* Verify that the msg.sender matches tokenId and version. | ||
* Different processor may be invoked based on the token ID (e.g. BTC vs Rune) | ||
*/ | ||
function processTx(uint tokenId, uint version, bytes32 txid) internal returns ( | ||
uint64 block, | ||
uint64 timestamp, | ||
TransferItem[] memory inputs, | ||
TransferItem[] memory outputs, | ||
bytes memory encodedCall // includes targetNetwork, beneficiary, targetContract, methodCall, fee | ||
) { | ||
} | ||
} |
Oops, something went wrong.