├── .prettierrc ├── .solhintignore ├── deployments ├── mumbai │ └── .chainId └── polygon │ └── .chainId ├── .npmignore ├── .eslintignore ├── commitlint.config.js ├── .DS_Store ├── .prettierignore ├── .husky └── commit-msg ├── .solhint.json ├── .env.example ├── contracts ├── uniswap │ ├── v2-periphery │ │ ├── interfaces │ │ │ ├── V1 │ │ │ │ ├── IUniswapV1Factory.sol │ │ │ │ └── IUniswapV1Exchange.sol │ │ │ ├── IUniswapV2Migrator.sol │ │ │ ├── IWETH.sol │ │ │ ├── IERC20.sol │ │ │ ├── IUniswapV2Router02.sol │ │ │ └── IUniswapV2Router01.sol │ │ ├── libraries │ │ │ ├── SafeMath.sol │ │ │ ├── TransferHelper.sol │ │ │ └── UniswapV2Library.sol │ │ └── UniswapV2Migrator.sol │ └── v2-core │ │ ├── interfaces │ │ ├── IUniswapV2Callee.sol │ │ ├── IUniswapV2Factory.sol │ │ ├── IERC20.sol │ │ ├── IUniswapV2ERC20.sol │ │ └── IUniswapV2Pair.sol │ │ ├── libraries │ │ ├── SafeMath.sol │ │ ├── UQ112x112.sol │ │ └── Math.sol │ │ ├── UniswapV2Factory.sol │ │ └── UniswapV2ERC20.sol ├── types │ ├── ScriptTypesEnum.sol │ └── DataTypes.sol ├── lockers │ ├── LockersProxy.sol │ ├── interfaces │ │ └── ILockersStorage.sol │ └── LockersStorageStructure.sol ├── erc20 │ ├── interfaces │ │ ├── IWETH.sol │ │ └── ITeleBTC.sol │ ├── WETH.sol │ ├── ERC20AsDot.sol │ ├── ERC20AsLink.sol │ └── TeleBTC.sol ├── pools │ ├── interfaces │ │ ├── ICollateralPool.sol │ │ ├── ICollateralPoolFactory.sol │ │ └── IInstantPool.sol │ └── CollateralPoolFactory.sol ├── connectors │ └── interfaces │ │ └── IExchangeConnector.sol ├── oracle │ └── interfaces │ │ └── IPriceOracle.sol ├── routers │ └── interfaces │ │ ├── ICCTransferRouter.sol │ │ └── ICCExchangeRouter.sol ├── libraries │ └── RequestHelper.sol └── relay │ └── interfaces │ └── IBitcoinRelay.sol ├── .gitignore ├── tsconfig.json ├── test ├── block_utils.js ├── block_utils.ts ├── utils.js └── test_fixtures │ ├── blockWithTx.json │ ├── ccBurnRequests.json │ ├── headersReorgAndRetarget.json │ └── ccTransferRequests.json ├── .eslintrc.js ├── helper-functions.ts ├── deploy ├── 001_TDT_Erc20.ts ├── 016_CollateralPoolFactory.ts ├── 003_TeleBTC.ts ├── 011_LockersLogic.ts ├── 010_PriceOracle.ts ├── 012_LockersProxy.ts ├── 009_ExchangeConnector.ts ├── 018_InstantPool.ts ├── 013_CCTransferRouter.ts ├── 015_CCExchangeRouter.ts ├── 017_InstantRouter.ts ├── 014_CCBurnRouter.ts └── 006_BitcoinRelay.ts ├── scripts ├── settlement-scripts │ ├── 003_SetExchangeRouterInConnector.ts │ ├── 006_SetTeleBTCInCCBurnRouter.ts │ ├── 010_SetInstantRouterInInstantPool.ts │ ├── 008_SetInstantPoolInInstantRouter.ts │ ├── 005_SetInstantRouterInCCTransfer.ts │ ├── 004_SetExchangeRouterInPriceOracle.ts │ ├── 001_TeleBTCSettlement.ts │ ├── 007_SetInstantRouterInCCExchange.ts │ ├── 009_AddLiquidityToInstantPool.ts │ └── 002_AddOrChargeLiquidityPair.ts ├── locker-logic-update-script │ └── 001_SetNewLockerLogicInLockerProxy.ts ├── set-global-variables │ ├── 004_SetPriceOracle.ts │ ├── 002_SetInstantRouter.ts │ ├── 001_SetRelay.ts │ └── 003_SetTeleBTC.ts ├── collateralPool-script │ ├── 002_CollateralCreationUSDT.ts │ ├── 003_CollateralCreationUSDC.ts │ └── 001_CollateralCreationWMATIC.ts ├── locker-settlement-script │ ├── 002_SetPriceOracleInLocker.ts │ ├── 004_SetCCBurnRouterInLocker.ts │ ├── 003_InitializeLockersLogic.ts │ └── 001_SetTeleBTCInLocker.ts └── add-price-proxy-to-oracle │ └── 001_AddPriceProxies.ts ├── .solcover.js ├── config ├── mumbai.json └── polygon.json ├── README.md ├── hardhat.config.ts └── package.json /.prettierrc: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /.solhintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /deployments/mumbai/.chainId: -------------------------------------------------------------------------------- 1 | 80001 -------------------------------------------------------------------------------- /deployments/polygon/.chainId: -------------------------------------------------------------------------------- 1 | 137 -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | hardhat.config.ts 2 | scripts 3 | test 4 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | artifacts 3 | cache 4 | coverage 5 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = {extends: ['@commitlint/config-conventional']} 2 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeleportDAO/bitcoin-ethereum-smart-contracts/HEAD/.DS_Store -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | artifacts 3 | cache 4 | coverage* 5 | gasReporterOutput.json 6 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx --no -- commitlint --edit 5 | -------------------------------------------------------------------------------- /.solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solhint:recommended", 3 | "rules": { 4 | "compiler-version": ["error", "^0.8.0"], 5 | "func-visibility": ["warn", { "ignoreConstructors": true }] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | ETHERSCAN_API_KEY=ABC123ABC123ABC123ABC123ABC123ABC1 2 | PRIVATE_KEY=0xabc123abc123abc123abc123abc123abc123abc123abc123abc123abc123abc1 3 | PROJECT_ID= 4 | VERIFY_OPTION=0 5 | 6 | BLOCK_HEIGHT=2417958 -------------------------------------------------------------------------------- /contracts/uniswap/v2-periphery/interfaces/V1/IUniswapV1Factory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.5.0; 3 | 4 | interface IUniswapV1Factory { 5 | function getExchange(address) external view returns (address); 6 | } 7 | -------------------------------------------------------------------------------- /contracts/uniswap/v2-core/interfaces/IUniswapV2Callee.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.5.0; 3 | 4 | interface IUniswapV2Callee { 5 | function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external; 6 | } 7 | -------------------------------------------------------------------------------- /contracts/uniswap/v2-periphery/interfaces/IUniswapV2Migrator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.5.0; 3 | 4 | interface IUniswapV2Migrator { 5 | function migrate(address token, uint amountTokenMin, uint amountETHMin, address to, uint deadline) external; 6 | } 7 | -------------------------------------------------------------------------------- /contracts/uniswap/v2-periphery/interfaces/IWETH.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.5.0; 3 | 4 | interface IWETH { 5 | function deposit() external payable; 6 | function transfer(address to, uint value) external returns (bool); 7 | function withdraw(uint) external; 8 | } 9 | -------------------------------------------------------------------------------- /contracts/types/ScriptTypesEnum.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.8.4; 3 | 4 | enum ScriptTypes { 5 | P2PK, // 32 bytes 6 | P2PKH, // 20 bytes 7 | P2SH, // 20 bytes 8 | P2WPKH, // 20 bytes 9 | P2WSH // 32 bytes 10 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | coverage 4 | coverage.json 5 | typechain 6 | 7 | #Hardhat files 8 | cache 9 | artifacts 10 | 11 | 12 | contracts.json 13 | coverage* 14 | deployments/localhost 15 | deployments/*/solcInputs/*.json 16 | dist 17 | src/types 18 | .vscode 19 | .nodn 20 | *.abe* 21 | *.bii 22 | /out 23 | build 24 | .env 25 | .venv 26 | /export 27 | vendor 28 | 29 | yarn-error.log 30 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "strict": true, 6 | "esModuleInterop": true, 7 | "outDir": "dist", 8 | "declaration": true 9 | }, 10 | "include": [ 11 | "hardhat.config.ts", 12 | "./scripts", 13 | "./deploy", 14 | "./test", 15 | "./typechain" 16 | ], 17 | "files": ["./hardhat.config.ts"] 18 | } 19 | -------------------------------------------------------------------------------- /contracts/lockers/LockersProxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.8.4; 3 | 4 | import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; 5 | 6 | contract LockersProxy is TransparentUpgradeableProxy { 7 | 8 | constructor( 9 | address _logic, 10 | address admin_, 11 | bytes memory _data 12 | ) payable TransparentUpgradeableProxy(_logic, admin_, _data) {} 13 | 14 | } -------------------------------------------------------------------------------- /contracts/erc20/interfaces/IWETH.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.8.4; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | 6 | interface IWETH is IERC20 { 7 | 8 | function name() external view returns (string memory); 9 | function symbol() external view returns (string memory); 10 | function decimals() external view returns (uint8); 11 | 12 | function deposit() external payable; 13 | function withdraw(uint) external; 14 | } -------------------------------------------------------------------------------- /test/block_utils.js: -------------------------------------------------------------------------------- 1 | 2 | const advanceBlockWithTime = async (provider, seconds) => { 3 | await provider.send("evm_increaseTime", [seconds]) 4 | await provider.send("evm_mine") 5 | } 6 | 7 | const takeSnapshot = async (provider) => { 8 | return await provider.send("evm_snapshot") 9 | } 10 | 11 | const revertProvider = async (provider, snapshotId) => { 12 | await provider.send("evm_revert", [snapshotId]) 13 | } 14 | 15 | module.exports = { 16 | advanceBlockWithTime, 17 | takeSnapshot, 18 | revertProvider, 19 | } 20 | -------------------------------------------------------------------------------- /test/block_utils.ts: -------------------------------------------------------------------------------- 1 | const advanceBlockWithTime = async (provider: any, seconds: number) => { 2 | await provider.send("evm_increaseTime", [seconds]) 3 | await provider.send("evm_mine") 4 | } 5 | 6 | const takeSnapshot = async (provider: any) => { 7 | return await provider.send("evm_snapshot") 8 | } 9 | 10 | const revertProvider = async (provider: any, snapshotId: any) => { 11 | await provider.send("evm_revert", [snapshotId]) 12 | } 13 | 14 | export { 15 | advanceBlockWithTime, 16 | takeSnapshot, 17 | revertProvider, 18 | } -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: false, 4 | es2021: true, 5 | mocha: true, 6 | node: true, 7 | }, 8 | plugins: ["@typescript-eslint"], 9 | extends: [ 10 | "standard", 11 | "plugin:prettier/recommended", 12 | "plugin:node/recommended", 13 | ], 14 | parser: "@typescript-eslint/parser", 15 | parserOptions: { 16 | ecmaVersion: 12, 17 | }, 18 | rules: { 19 | "node/no-unsupported-features/es-syntax": [ 20 | "error", 21 | { ignores: ["modules"] }, 22 | ], 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /helper-functions.ts: -------------------------------------------------------------------------------- 1 | import { run } from "hardhat" 2 | 3 | const verify = async (contractAddress: string, args: any[], codePath: string) => { 4 | console.log("Verifying contract...") 5 | try { 6 | await run("verify:verify", { 7 | address: contractAddress, 8 | constructorArguments: args, 9 | contract: codePath, 10 | }) 11 | } catch (e: any) { 12 | if (e.message.toLowerCase().includes("already verified")) { 13 | console.log("Already verified!") 14 | } else { 15 | console.log(e) 16 | } 17 | } 18 | } 19 | 20 | export default verify -------------------------------------------------------------------------------- /contracts/uniswap/v2-periphery/interfaces/V1/IUniswapV1Exchange.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.5.0; 3 | 4 | interface IUniswapV1Exchange { 5 | function balanceOf(address owner) external view returns (uint); 6 | function transferFrom(address from, address to, uint value) external returns (bool); 7 | function removeLiquidity(uint, uint, uint, uint) external returns (uint, uint); 8 | function tokenToEthSwapInput(uint, uint, uint) external returns (uint); 9 | function ethToTokenSwapInput(uint, uint) external payable returns (uint); 10 | } 11 | -------------------------------------------------------------------------------- /contracts/uniswap/v2-core/libraries/SafeMath.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) 4 | 5 | library SafeMath { 6 | function add(uint x, uint y) internal pure returns (uint z) { 7 | require((z = x + y) >= x, 'ds-math-add-overflow'); 8 | } 9 | 10 | function sub(uint x, uint y) internal pure returns (uint z) { 11 | require((z = x - y) <= x, 'ds-math-sub-underflow'); 12 | } 13 | 14 | function mul(uint x, uint y) internal pure returns (uint z) { 15 | require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/utils.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | 4 | strip0xPrefix: function strip0xPrefix(hexString) { 5 | return hexString.substring(0, 2) === '0x' ? hexString.substring(2) : hexString; 6 | }, 7 | 8 | concatenateHexStrings: function concatenateHexStrings(strs) { 9 | let current = '0x'; 10 | for (let i = 0; i < strs.length; i += 1) { 11 | current = `${current}${this.strip0xPrefix(strs[i])}`; 12 | } 13 | return current; 14 | }, 15 | concatenateHeadersHexes: function concatenateHeadersHexes(arr) { 16 | const hexes = arr.map(_arr => _arr.hex); 17 | return this.concatenateHexStrings(hexes); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /contracts/uniswap/v2-core/libraries/UQ112x112.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format)) 4 | 5 | // range: [0, 2**112 - 1] 6 | // resolution: 1 / 2**112 7 | 8 | library UQ112x112 { 9 | uint224 constant Q112 = 2**112; 10 | 11 | // encode a uint112 as a UQ112x112 12 | function encode(uint112 y) internal pure returns (uint224 z) { 13 | z = uint224(y) * Q112; // never overflows 14 | } 15 | 16 | // divide a UQ112x112 by a uint112, returning a UQ112x112 17 | function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) { 18 | z = x / uint224(y); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /contracts/uniswap/v2-periphery/libraries/SafeMath.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity =0.6.6; 3 | 4 | // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) 5 | 6 | library SafeMath { 7 | function add(uint x, uint y) internal pure returns (uint z) { 8 | require((z = x + y) >= x, 'ds-math-add-overflow'); 9 | } 10 | 11 | function sub(uint x, uint y) internal pure returns (uint z) { 12 | require((z = x - y) <= x, 'ds-math-sub-underflow'); 13 | } 14 | 15 | function mul(uint x, uint y) internal pure returns (uint z) { 16 | require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contracts/uniswap/v2-core/libraries/Math.sol: -------------------------------------------------------------------------------- 1 | pragma solidity =0.5.16; 2 | 3 | // a library for performing various math operations 4 | 5 | library Math { 6 | function min(uint x, uint y) internal pure returns (uint z) { 7 | z = x < y ? x : y; 8 | } 9 | 10 | // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) 11 | function sqrt(uint y) internal pure returns (uint z) { 12 | if (y > 3) { 13 | z = y; 14 | uint x = y / 2 + 1; 15 | while (x < z) { 16 | z = x; 17 | x = (y / x + x) / 2; 18 | } 19 | } else if (y != 0) { 20 | z = 1; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /contracts/erc20/WETH.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.8.4; 3 | 4 | import "./interfaces/IWETH.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 6 | 7 | contract WETH is ERC20 { 8 | 9 | constructor(string memory _name, string memory _symbol) 10 | ERC20(_name, _symbol) {} 11 | 12 | function deposit() external payable { 13 | require(msg.value > 0); 14 | _mint(_msgSender(), msg.value); 15 | } 16 | 17 | function withdraw(uint value) external { 18 | require(balanceOf(_msgSender()) >= value, "Balance is not sufficient"); 19 | _burn(_msgSender(), value); 20 | address payable recipient = payable(_msgSender()); 21 | recipient.transfer(value); 22 | } 23 | } -------------------------------------------------------------------------------- /contracts/uniswap/v2-core/interfaces/IUniswapV2Factory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.5.0; 3 | 4 | interface IUniswapV2Factory { 5 | event PairCreated(address indexed token0, address indexed token1, address pair, uint); 6 | 7 | function feeTo() external view returns (address); 8 | function feeToSetter() external view returns (address); 9 | 10 | function getPair(address tokenA, address tokenB) external view returns (address pair); 11 | function allPairs(uint) external view returns (address pair); 12 | function allPairsLength() external view returns (uint); 13 | 14 | function createPair(address tokenA, address tokenB) external returns (address pair); 15 | 16 | function setFeeTo(address) external; 17 | function setFeeToSetter(address) external; 18 | } 19 | -------------------------------------------------------------------------------- /deploy/001_TDT_Erc20.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { BigNumber, BigNumberish } from "ethers"; 4 | 5 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 6 | const {deployments, getNamedAccounts} = hre; 7 | const {deploy} = deployments; 8 | const { deployer } = await getNamedAccounts(); 9 | 10 | const tokenName = "TeleportDAOToken" 11 | const tokenSymbol = "TDT" 12 | const initialSupply = BigNumber.from(10).pow(18).mul(10000) 13 | 14 | await deploy("ERC20", { 15 | from: deployer, 16 | log: true, 17 | skipIfAlreadyDeployed: true, 18 | args: [ 19 | tokenName, 20 | tokenSymbol, 21 | // initialSupply 22 | ], 23 | }); 24 | 25 | 26 | }; 27 | 28 | export default func; 29 | func.tags = ["TeleportDAOToken"]; 30 | -------------------------------------------------------------------------------- /deploy/016_CollateralPoolFactory.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import verify from "../helper-functions" 4 | 5 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 6 | const {deployments, getNamedAccounts, network} = hre; 7 | const {deploy} = deployments; 8 | const { deployer } = await getNamedAccounts(); 9 | 10 | const deployedContract = await deploy("CollateralPoolFactory", { 11 | from: deployer, 12 | log: true, 13 | skipIfAlreadyDeployed: true 14 | }); 15 | 16 | if (network.name != "hardhat" && process.env.ETHERSCAN_API_KEY && process.env.VERIFY_OPTION == "1") { 17 | await verify(deployedContract.address, [], "contracts/pools/CollateralPoolFactory.sol:CollateralPoolFactory") 18 | } 19 | }; 20 | 21 | export default func; 22 | func.tags = ["CollateralPoolFactory"]; 23 | -------------------------------------------------------------------------------- /contracts/uniswap/v2-core/interfaces/IERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.5.0; 3 | 4 | interface IERC20 { 5 | event Approval(address indexed owner, address indexed spender, uint value); 6 | event Transfer(address indexed from, address indexed to, uint value); 7 | 8 | function name() external view returns (string memory); 9 | function symbol() external view returns (string memory); 10 | function decimals() external view returns (uint8); 11 | function totalSupply() external view returns (uint); 12 | function balanceOf(address owner) external view returns (uint); 13 | function allowance(address owner, address spender) external view returns (uint); 14 | 15 | function approve(address spender, uint value) external returns (bool); 16 | function transfer(address to, uint value) external returns (bool); 17 | function transferFrom(address from, address to, uint value) external returns (bool); 18 | } 19 | -------------------------------------------------------------------------------- /contracts/uniswap/v2-periphery/interfaces/IERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.5.0; 3 | 4 | interface IERC20 { 5 | event Approval(address indexed owner, address indexed spender, uint value); 6 | event Transfer(address indexed from, address indexed to, uint value); 7 | 8 | function name() external view returns (string memory); 9 | function symbol() external view returns (string memory); 10 | function decimals() external view returns (uint8); 11 | function totalSupply() external view returns (uint); 12 | function balanceOf(address owner) external view returns (uint); 13 | function allowance(address owner, address spender) external view returns (uint); 14 | 15 | function approve(address spender, uint value) external returns (bool); 16 | function transfer(address to, uint value) external returns (bool); 17 | function transferFrom(address from, address to, uint value) external returns (bool); 18 | } 19 | -------------------------------------------------------------------------------- /test/test_fixtures/blockWithTx.json: -------------------------------------------------------------------------------- 1 | { 2 | "block": { 3 | "id": "0000000000000468b21ddcda74388a6f3a52687a494e88d244529fb2545b98b9", 4 | "height": 201597, 5 | "version": 1, 6 | "timestamp": 1349225725, 7 | "tx_count": 20, 8 | "size": 7849, 9 | "weight": 31072, 10 | "merkle_root": "1c1c9168f7c2343932506d6a4366f58646675aa5fef05bf87ac171845ec174b7", 11 | "previous_blockhash": "00000000000002e74a1d20af3afc49a386912f78cfe69bd04da1432d1d6e9bb9", 12 | "mediantime": 1349224200, 13 | "nonce": 2401054706, 14 | "bits": 436591499, 15 | "difficulty": 2864140 16 | }, 17 | "transaction": { 18 | "tx_id": "0x5EB1C2C1530ADC93AE8B160E53E946E7B09F7273D80C9C8AC0646573D8CD5F99", 19 | "intermediate_nodes": "0xaa6c8fafbe800d8159d3a266ab3fec99a7aea5115baca77adfe4658d377ed9d9e23afa26ed94d660cb4ae98a3878de76641d82d4a95b39a2d549fe1d0dc3717a92a5829d173ebb5edebb57726a92ba6527ac27a49b11642cb390ef88d7ad2c8f65b07be3eafac4a7a40ec24835b7c4de496211ae40d603b27abe0f066691093fe99acfe9d27688865c341ea216316a693e76f0df978b9dbe971205861e741121", 20 | "index": 10 21 | } 22 | } -------------------------------------------------------------------------------- /deploy/003_TeleBTC.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import verify from "../helper-functions" 4 | 5 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 6 | const {deployments, getNamedAccounts, network} = hre; 7 | const {deploy} = deployments; 8 | const { deployer } = await getNamedAccounts(); 9 | 10 | const tokenName = "teleBTC" 11 | const tokenSymbol = "TELEBTC" 12 | 13 | const theArgs = [ 14 | tokenName, 15 | tokenSymbol 16 | ] 17 | 18 | const deployedContract = await deploy("TeleBTC", { 19 | from: deployer, 20 | log: true, 21 | skipIfAlreadyDeployed: true, 22 | args: theArgs 23 | }); 24 | 25 | if (network.name != "hardhat" && process.env.ETHERSCAN_API_KEY && process.env.VERIFY_OPTION == "1") { 26 | await verify(deployedContract.address, [ 27 | tokenName, 28 | tokenSymbol, 29 | ], "contracts/erc20/TeleBTC.sol:TeleBTC") 30 | } 31 | 32 | }; 33 | 34 | export default func; 35 | func.tags = ["TeleBTC"]; 36 | -------------------------------------------------------------------------------- /deploy/011_LockersLogic.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import verify from "../helper-functions" 4 | 5 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 6 | const {deployments, getNamedAccounts, network} = hre; 7 | const {deploy} = deployments; 8 | const { deployer } = await getNamedAccounts(); 9 | 10 | const lockersLib = await deploy("LockersLib", { 11 | from: deployer, 12 | log: true, 13 | skipIfAlreadyDeployed: true, 14 | }) 15 | 16 | const deployedContract = await deploy("LockersLogic", { 17 | from: deployer, 18 | log: true, 19 | skipIfAlreadyDeployed: true, 20 | libraries: { 21 | "LockersLib": lockersLib.address 22 | }, 23 | }); 24 | 25 | if (network.name != "hardhat" && process.env.ETHERSCAN_API_KEY && process.env.VERIFY_OPTION == "1") { 26 | await verify(deployedContract.address, [], "contracts/lockers/LockersLogic.sol:LockersLogic") 27 | } 28 | }; 29 | 30 | export default func; 31 | func.tags = ["LockersLogic"]; 32 | -------------------------------------------------------------------------------- /contracts/lockers/interfaces/ILockersStorage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.8.4; 3 | 4 | import "../../types/DataTypes.sol"; 5 | 6 | interface ILockersStorage { 7 | // Read-only functions 8 | 9 | function TeleportDAOToken() external view returns(address); 10 | 11 | function teleBTC() external view returns(address); 12 | 13 | function ccBurnRouter() external view returns(address); 14 | 15 | function exchangeConnector() external view returns(address); 16 | 17 | function priceOracle() external view returns(address); 18 | 19 | function minRequiredTDTLockedAmount() external view returns(uint); 20 | 21 | function minRequiredTNTLockedAmount() external view returns(uint); 22 | 23 | function lockerPercentageFee() external view returns(uint); 24 | 25 | function collateralRatio() external view returns(uint); 26 | 27 | function liquidationRatio() external view returns(uint); 28 | 29 | function priceWithDiscountRatio() external view returns(uint); 30 | 31 | function totalNumberOfCandidates() external view returns(uint); 32 | 33 | function totalNumberOfLockers() external view returns(uint); 34 | 35 | } 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /deploy/010_PriceOracle.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import config from 'config' 4 | import verify from "../helper-functions" 5 | 6 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 7 | const {deployments, getNamedAccounts, network} = hre; 8 | const {deploy} = deployments; 9 | const { deployer } = await getNamedAccounts(); 10 | 11 | const acceptableDelay = config.get("acceptable_delay"); 12 | const tntToken = config.get("wrapped_matic") 13 | 14 | const deployedContract = await deploy("PriceOracle", { 15 | from: deployer, 16 | log: true, 17 | skipIfAlreadyDeployed: true, 18 | args: [ 19 | acceptableDelay, 20 | tntToken 21 | ], 22 | }); 23 | 24 | if (network.name != "hardhat" && process.env.ETHERSCAN_API_KEY && process.env.VERIFY_OPTION == "1") { 25 | await verify(deployedContract.address, [ 26 | acceptableDelay, 27 | tntToken 28 | ], "contracts/oracle/PriceOracle.sol:PriceOracle") 29 | } 30 | }; 31 | 32 | export default func; 33 | func.tags = ["PriceOracle"]; 34 | -------------------------------------------------------------------------------- /deploy/012_LockersProxy.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers, network } from 'hardhat'; 4 | import verify from "../helper-functions" 5 | 6 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 7 | const {deployments, getNamedAccounts, network} = hre; 8 | const {deploy} = deployments; 9 | const { deployer } = await getNamedAccounts(); 10 | 11 | const lockersLogic = await deployments.get("LockersLogic") 12 | 13 | const deployedContract = await deploy("LockersProxy", { 14 | from: deployer, 15 | log: true, 16 | skipIfAlreadyDeployed: true, 17 | args: [ 18 | lockersLogic.address, 19 | deployer, 20 | "0x" 21 | ], 22 | }); 23 | 24 | if (network.name != "hardhat" && process.env.ETHERSCAN_API_KEY && process.env.VERIFY_OPTION == "1") { 25 | await verify(deployedContract.address, [ 26 | lockersLogic.address, 27 | deployer, 28 | "0x" 29 | ], "contracts/lockers/LockersProxy.sol:LockersProxy") 30 | } 31 | }; 32 | 33 | export default func; 34 | func.tags = ["LockersProxy"]; 35 | -------------------------------------------------------------------------------- /deploy/009_ExchangeConnector.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import config from 'config' 4 | import verify from "../helper-functions" 5 | 6 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 7 | const {deployments, getNamedAccounts, network} = hre; 8 | const {deploy} = deployments; 9 | const { deployer } = await getNamedAccounts(); 10 | 11 | const connectorName = "QuickswapV2" 12 | 13 | const uniswapV2Router02 = config.get("uniswap_v2_router_02") 14 | 15 | const deployedContract = await deploy("UniswapV2Connector", { 16 | from: deployer, 17 | log: true, 18 | skipIfAlreadyDeployed: true, 19 | args: [ 20 | connectorName, 21 | uniswapV2Router02 22 | ], 23 | }); 24 | 25 | if (network.name != "hardhat" && process.env.ETHERSCAN_API_KEY && process.env.VERIFY_OPTION == "1") { 26 | await verify(deployedContract.address, [ 27 | connectorName, 28 | uniswapV2Router02 29 | ], "contracts/connectors/UniswapV2Connector.sol:UniswapV2Connector") 30 | } 31 | }; 32 | 33 | export default func; 34 | func.tags = ["UniswapV2Connector"]; 35 | -------------------------------------------------------------------------------- /contracts/uniswap/v2-core/interfaces/IUniswapV2ERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.5.0; 3 | 4 | interface IUniswapV2ERC20 { 5 | event Approval(address indexed owner, address indexed spender, uint value); 6 | event Transfer(address indexed from, address indexed to, uint value); 7 | 8 | function name() external pure returns (string memory); 9 | function symbol() external pure returns (string memory); 10 | function decimals() external pure returns (uint8); 11 | function totalSupply() external view returns (uint); 12 | function balanceOf(address owner) external view returns (uint); 13 | function allowance(address owner, address spender) external view returns (uint); 14 | 15 | function approve(address spender, uint value) external returns (bool); 16 | function transfer(address to, uint value) external returns (bool); 17 | function transferFrom(address from, address to, uint value) external returns (bool); 18 | 19 | function DOMAIN_SEPARATOR() external view returns (bytes32); 20 | function PERMIT_TYPEHASH() external pure returns (bytes32); 21 | function nonces(address owner) external view returns (uint); 22 | 23 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; 24 | } 25 | -------------------------------------------------------------------------------- /contracts/pools/interfaces/ICollateralPool.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.8.4; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | 6 | interface ICollateralPool is IERC20 { 7 | 8 | // Events 9 | 10 | event AddCollateral(address indexed doer, address indexed user, uint amount, uint collateralPoolTokenAmount); 11 | 12 | event RemoveCollateral(address indexed doer, address indexed user, uint amount, uint collateralPoolTokenAmount); 13 | 14 | event NewCollateralizationRatio(uint oldCollateralizationRatio, uint newCollateralizationRatio); 15 | 16 | // Read-only functions 17 | 18 | function collateralToken() external view returns (address); 19 | 20 | function collateralizationRatio() external view returns(uint); 21 | 22 | function totalAddedCollateral() external view returns (uint); 23 | 24 | function equivalentCollateralToken(uint _collateralPoolTokenAmount) external view returns (uint); 25 | 26 | function equivalentCollateralPoolToken(uint _collateralTokenAmount) external view returns (uint); 27 | 28 | // State-changing functions 29 | 30 | function setCollateralizationRatio(uint _collateralizationRatio) external; 31 | 32 | function addCollateral(address _user, uint _amount) external returns (bool); 33 | 34 | function removeCollateral(uint _collateralPoolTokenAmount) external returns (bool); 35 | 36 | } -------------------------------------------------------------------------------- /contracts/erc20/interfaces/ITeleBTC.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.8.4; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | 6 | interface ITeleBTC is IERC20 { 7 | 8 | // Events 9 | event Mint(address indexed doer, address indexed receiver, uint value); 10 | 11 | event Burn(address indexed doer, address indexed burner, uint value); 12 | 13 | event MinterAdded(address indexed newMinter); 14 | 15 | event MinterRemoved(address indexed minter); 16 | 17 | event BurnerAdded(address indexed newBurner); 18 | 19 | event BurnerRemoved(address indexed burner); 20 | 21 | event NewMintLimit(uint oldMintLimit, uint newMintLimit); 22 | 23 | event NewEpochLength(uint oldEpochLength, uint newEpochLength); 24 | 25 | // read functions 26 | 27 | function decimals() external view returns (uint8); 28 | 29 | // state-changing functions 30 | 31 | function addMinter(address account) external; 32 | 33 | function removeMinter(address account) external; 34 | 35 | function addBurner(address account) external; 36 | 37 | function removeBurner(address account) external; 38 | 39 | function mint(address receiver, uint amount) external returns(bool); 40 | 41 | function burn(uint256 amount) external returns(bool); 42 | 43 | function setMaxMintLimit(uint _mintLimit) external; 44 | 45 | function setEpochLength(uint _length) external; 46 | } -------------------------------------------------------------------------------- /scripts/settlement-scripts/003_SetExchangeRouterInConnector.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import config from 'config' 5 | import { BigNumber, BigNumberish } from "ethers"; 6 | const logger = require('node-color-log'); 7 | 8 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 9 | const {deployments, getNamedAccounts, network} = hre; 10 | const {deploy, log} = deployments; 11 | const { deployer } = await getNamedAccounts(); 12 | 13 | logger.color('blue').log("-------------------------------------------------") 14 | logger.color('blue').bold().log("Set Exchange Router in connector...") 15 | 16 | const uniswapRouter = config.get("uniswap_v2_router_02") 17 | const uniswapConnector = await deployments.get("UniswapV2Connector") 18 | 19 | const uniswapConnectorFactory = await ethers.getContractFactory("UniswapV2Connector"); 20 | const uniswapConnectorInstance = await uniswapConnectorFactory.attach( 21 | uniswapConnector.address 22 | ); 23 | 24 | const setExchangeRouterTx = await uniswapConnectorInstance.setExchangeRouter( 25 | uniswapRouter 26 | ) 27 | await setExchangeRouterTx.wait(1) 28 | console.log("set exchange router in connector: ", setExchangeRouterTx.hash) 29 | 30 | 31 | }; 32 | 33 | export default func; 34 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 35 | -------------------------------------------------------------------------------- /.solcover.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | skipFiles: [ 3 | 'uniswap/v2-core/UniswapV2ERC20.sol', 4 | 'uniswap/v2-core/UniswapV2Factory.sol', 5 | 'uniswap/v2-core/UniswapV2Pair.sol', 6 | 'uniswap/v2-periphery/UniswapV2Migrator.sol', 7 | 'uniswap/v2-periphery/UniswapV2Router01.sol', 8 | 'uniswap/v2-periphery/UniswapV2Router02.sol', 9 | 'uniswap/v2-core/interfaces/IERC20.sol', 10 | 'uniswap/v2-core/interfaces/IUniswapV2Callee.sol', 11 | 'uniswap/v2-core/interfaces/IUniswapV2ERC20.sol', 12 | 'uniswap/v2-core/interfaces/IUniswapV2Factory.sol', 13 | 'uniswap/v2-core/interfaces/IUniswapV2Pair.sol', 14 | 'uniswap/v2-core/libraries/Math.sol', 15 | 'uniswap/v2-core/libraries/SafeMath.sol', 16 | 'uniswap/v2-core/libraries/UQ112x112.sol', 17 | 'uniswap/v2-periphery/interfaces/IERC20.sol', 18 | 'uniswap/v2-periphery/interfaces/IUniswapV2Migrator.sol', 19 | 'uniswap/v2-periphery/interfaces/IUniswapV2Router01.sol', 20 | 'uniswap/v2-periphery/interfaces/IUniswapV2Router02.sol', 21 | 'uniswap/v2-periphery/interfaces/IWETH.sol', 22 | 'uniswap/v2-periphery/interfaces/V1/IUniswapV1Exchange.sol', 23 | 'uniswap/v2-periphery/interfaces/V1/IUniswapV1Factory.sol', 24 | 'uniswap/v2-periphery/libraries/SafeMath.sol', 25 | 'uniswap/v2-periphery/libraries/TransferHelper.sol', 26 | 'uniswap/v2-periphery/libraries/UniswapV2Library.sol', 27 | ], 28 | configureYulOptimizer: 'true' 29 | }; -------------------------------------------------------------------------------- /contracts/connectors/interfaces/IExchangeConnector.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.8.4; 3 | 4 | interface IExchangeConnector { 5 | 6 | // Events 7 | 8 | event Swap(address[] path, uint[] amounts, address receiver); 9 | 10 | // Read-only functions 11 | 12 | function name() external view returns (string memory); 13 | 14 | function exchangeRouter() external view returns (address); 15 | 16 | function liquidityPoolFactory() external view returns (address); 17 | 18 | function wrappedNativeToken() external view returns (address); 19 | 20 | function getInputAmount( 21 | uint _outputAmount, 22 | address _inputToken, 23 | address _outputToken 24 | ) external view returns (bool, uint); 25 | 26 | function getOutputAmount( 27 | uint _inputAmount, 28 | address _inputToken, 29 | address _outputToken 30 | ) external view returns (bool, uint); 31 | 32 | // State-changing functions 33 | 34 | function setExchangeRouter(address _exchangeRouter) external; 35 | 36 | function setLiquidityPoolFactory() external; 37 | 38 | function setWrappedNativeToken() external; 39 | 40 | function swap( 41 | uint256 _inputAmount, 42 | uint256 _outputAmount, 43 | address[] memory _path, 44 | address _to, 45 | uint256 _deadline, 46 | bool _isFixedToken 47 | ) external returns (bool, uint[] memory); 48 | 49 | function isPathValid(address[] memory _path) external view returns(bool); 50 | } -------------------------------------------------------------------------------- /contracts/uniswap/v2-periphery/interfaces/IUniswapV2Router02.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2; 3 | 4 | import './IUniswapV2Router01.sol'; 5 | 6 | interface IUniswapV2Router02 is IUniswapV2Router01 { 7 | function removeLiquidityETHSupportingFeeOnTransferTokens( 8 | address token, 9 | uint liquidity, 10 | uint amountTokenMin, 11 | uint amountETHMin, 12 | address to, 13 | uint deadline 14 | ) external returns (uint amountETH); 15 | function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( 16 | address token, 17 | uint liquidity, 18 | uint amountTokenMin, 19 | uint amountETHMin, 20 | address to, 21 | uint deadline, 22 | bool approveMax, uint8 v, bytes32 r, bytes32 s 23 | ) external returns (uint amountETH); 24 | 25 | function swapExactTokensForTokensSupportingFeeOnTransferTokens( 26 | uint amountIn, 27 | uint amountOutMin, 28 | address[] calldata path, 29 | address to, 30 | uint deadline 31 | ) external; 32 | function swapExactETHForTokensSupportingFeeOnTransferTokens( 33 | uint amountOutMin, 34 | address[] calldata path, 35 | address to, 36 | uint deadline 37 | ) external payable; 38 | function swapExactTokensForETHSupportingFeeOnTransferTokens( 39 | uint amountIn, 40 | uint amountOutMin, 41 | address[] calldata path, 42 | address to, 43 | uint deadline 44 | ) external; 45 | } 46 | -------------------------------------------------------------------------------- /deploy/018_InstantPool.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import config from 'config' 4 | import verify from "../helper-functions" 5 | 6 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 7 | const {deployments, getNamedAccounts, network} = hre; 8 | const {deploy} = deployments; 9 | const { deployer } = await getNamedAccounts(); 10 | 11 | const instantPercentageFee = config.get("instant_pool.instant_percentage_fee"); 12 | 13 | const teleBTC = await deployments.get("TeleBTC") 14 | const instantRouter = await deployments.get("InstantRouter") 15 | 16 | const name = "teleBTCInstantPoolToken" 17 | const symbol = "TELEBTCIPT" 18 | 19 | const deployedContract = await deploy("InstantPool", { 20 | from: deployer, 21 | log: true, 22 | skipIfAlreadyDeployed: true, 23 | args: [ 24 | teleBTC.address, 25 | instantRouter.address, 26 | instantPercentageFee, 27 | name, 28 | symbol 29 | ], 30 | }); 31 | 32 | if (network.name != "hardhat" && process.env.ETHERSCAN_API_KEY && process.env.VERIFY_OPTION == "1") { 33 | await verify(deployedContract.address, [ 34 | teleBTC.address, 35 | instantRouter.address, 36 | instantPercentageFee, 37 | name, 38 | symbol 39 | ], "contracts/pools/InstantPool.sol:InstantPool") 40 | } 41 | }; 42 | 43 | export default func; 44 | func.tags = ["InstantPool"]; 45 | -------------------------------------------------------------------------------- /scripts/settlement-scripts/006_SetTeleBTCInCCBurnRouter.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import { BigNumber, BigNumberish } from "ethers"; 5 | const logger = require('node-color-log'); 6 | 7 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 8 | const {deployments, getNamedAccounts, network} = hre; 9 | const {deploy, log} = deployments; 10 | const { deployer } = await getNamedAccounts(); 11 | 12 | logger.color('blue').log("-------------------------------------------------") 13 | logger.color('blue').bold().log("Set teleBTC in CC burn...") 14 | 15 | const teleBTC = await deployments.get("TeleBTC") 16 | const ccBurnRouter = await deployments.get("CCBurnRouter") 17 | 18 | const ccBurnRouterFactory = await ethers.getContractFactory("CCBurnRouter"); 19 | const ccBurnRouterInstance = await ccBurnRouterFactory.attach( 20 | ccBurnRouter.address 21 | ); 22 | 23 | const checkTeleBTCInCCBurn = await ccBurnRouterInstance.teleBTC() 24 | 25 | if (checkTeleBTCInCCBurn != teleBTC.address ) { 26 | const setTeleBTCTx = await ccBurnRouterInstance.setTeleBTC( 27 | teleBTC.address 28 | ) 29 | 30 | await setTeleBTCTx.wait(1) 31 | console.log("set telebtc in CC burn: ", setTeleBTCTx.hash) 32 | } else { 33 | console.log("telebtc is already settled in CC burn") 34 | } 35 | 36 | 37 | }; 38 | 39 | export default func; 40 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 41 | -------------------------------------------------------------------------------- /scripts/locker-logic-update-script/001_SetNewLockerLogicInLockerProxy.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import { BigNumber, BigNumberish } from "ethers"; 5 | const logger = require('node-color-log'); 6 | 7 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 8 | const {deployments, getNamedAccounts, network} = hre; 9 | const {deploy, log} = deployments; 10 | const { deployer } = await getNamedAccounts(); 11 | 12 | logger.color('blue').log("-------------------------------------------------") 13 | logger.color('blue').bold().log("Set logic in lockers proxy...") 14 | 15 | const lockersProxy = await deployments.get("LockersProxy") 16 | const lockersLogic = await deployments.get("LockersLogic") 17 | 18 | const lockersProxyFactory = await ethers.getContractFactory("LockersProxy"); 19 | const lockersProxyInstance = await lockersProxyFactory.attach( 20 | lockersProxy.address 21 | ); 22 | 23 | const checkLogicInLockersProxy = await lockersProxyInstance.implementation() 24 | 25 | if (checkLogicInLockersProxy != lockersLogic.address) { 26 | const setLogicTx = await lockersProxyInstance.upgradeTo( 27 | lockersLogic.address 28 | ) 29 | 30 | await setLogicTx.wait(1) 31 | console.log("set logic in lockers proxy: ", setLogicTx.hash) 32 | } else { 33 | console.log("logic is already settled in lockers proxy") 34 | } 35 | 36 | }; 37 | 38 | export default func; 39 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 40 | -------------------------------------------------------------------------------- /contracts/erc20/ERC20AsDot.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity >=0.8.0 <0.8.4; 4 | 5 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 6 | 7 | /** 8 | * @dev Implementation of the {IERC20} interface. 9 | * 10 | * This implementation is agnostic to the way tokens are created. This means 11 | * that a supply mechanism has to be added in a derived contract using {_mint}. 12 | * For a generic mechanism see {ERC20PresetMinterPauser}. 13 | * 14 | * TIP: For a detailed writeup see our guide 15 | * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How 16 | * to implement supply mechanisms]. 17 | * 18 | * We have followed general OpenZeppelin guidelines: functions revert instead 19 | * of returning `false` on failure. This behavior is nonetheless conventional 20 | * and does not conflict with the expectations of ERC20 applications. 21 | * 22 | * Additionally, an {Approval} event is emitted on calls to {transferFrom}. 23 | * This allows applications to reconstruct the allowance for all accounts just 24 | * by listening to said events. Other implementations of the EIP may not emit 25 | * these events, as it isn't required by the specification. 26 | * 27 | * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} 28 | * functions have been added to mitigate the well-known issues around setting 29 | * allowances. See {IERC20-approve}. 30 | */ 31 | contract ERC20AsDot is ERC20 { 32 | constructor ( 33 | string memory name_, 34 | string memory symbol_, 35 | uint initialMintedAmount 36 | ) ERC20(name_, symbol_) { 37 | _mint(_msgSender(), initialMintedAmount); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /contracts/erc20/ERC20AsLink.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity >=0.8.0 <0.8.4; 4 | 5 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 6 | 7 | /** 8 | * @dev Implementation of the {IERC20} interface. 9 | * 10 | * This implementation is agnostic to the way tokens are created. This means 11 | * that a supply mechanism has to be added in a derived contract using {_mint}. 12 | * For a generic mechanism see {ERC20PresetMinterPauser}. 13 | * 14 | * TIP: For a detailed writeup see our guide 15 | * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How 16 | * to implement supply mechanisms]. 17 | * 18 | * We have followed general OpenZeppelin guidelines: functions revert instead 19 | * of returning `false` on failure. This behavior is nonetheless conventional 20 | * and does not conflict with the expectations of ERC20 applications. 21 | * 22 | * Additionally, an {Approval} event is emitted on calls to {transferFrom}. 23 | * This allows applications to reconstruct the allowance for all accounts just 24 | * by listening to said events. Other implementations of the EIP may not emit 25 | * these events, as it isn't required by the specification. 26 | * 27 | * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} 28 | * functions have been added to mitigate the well-known issues around setting 29 | * allowances. See {IERC20-approve}. 30 | */ 31 | contract ERC20AsLink is ERC20 { 32 | constructor ( 33 | string memory name_, 34 | string memory symbol_, 35 | uint initialMintedAmount 36 | ) ERC20(name_, symbol_) { 37 | _mint(_msgSender(), initialMintedAmount); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /config/mumbai.json: -------------------------------------------------------------------------------- 1 | { 2 | "bitcoin_network": "testnet", 3 | "uniswap_v2_router_02": "0x8954AfA98594b838bda56FE4C12a09D7739D179b", 4 | "uniswap_v2_factory": "0x5757371414417b8C6CAad45bAeF941aBc7d3Ab32", 5 | "wrapped_matic": "0x9c3C9283D3e44854697Cd22D3Faa240Cfb032889", 6 | "usdt_token": "0xA02f6adc7926efeBBd59Fd43A84f4E0c0c91e832", 7 | "usdc_token": "0xE097d6B3100777DC31B34dC2c58fB524C2e76921", 8 | "acceptable_delay": 900, 9 | "chain_id": 137, 10 | "fee_to_setter": "0x5364E3557572bd5D5903C0e9C21BE359F2Eac1dA", 11 | "treasury": "0x5364E3557572bd5D5903C0e9C21BE359F2Eac1dA", 12 | "chain_link_oracles": { 13 | "matic_usd": "0xd0D5e3DB44DE05E9F294BB0a3bEEaF030DE24Ada", 14 | "btc_usd": "0x007A22900a3B98143368Bd5906f8E17e9867581b", 15 | "usdt_usd": "0x92C09849638959196E976289418e5973CC96d645", 16 | "usdc_usd": "0x572dDec9087154dC5dfBB1546Bb62713147e0Ab0" 17 | }, 18 | "cc_transfer": { 19 | "app_id": 1, 20 | "protocol_percentage_fee": 5 21 | }, 22 | "cc_exchange": { 23 | "app_id": 10, 24 | "protocol_percentage_fee": 5 25 | }, 26 | "cc_burn": { 27 | "protocol_percentage_fee": 5, 28 | "slasher_percentage_reward": 500, 29 | "bitcoin_fee": 10000, 30 | "transfer_deadLine": 72 31 | }, 32 | "instant_router": { 33 | "slasher_percentage_reward": 500, 34 | "payback_deadline": 12, 35 | "max_price_difference_percent": 2500 36 | }, 37 | "instant_pool": { 38 | "instant_percentage_fee": 15 39 | }, 40 | "lockers_contract": { 41 | "minimum_native_locked_amount": "6", 42 | "collateral_ratio": 13000, 43 | "liquidation_ratio": 10500, 44 | "locker_percentage_fee": 15, 45 | "price_with_discount_ratio": 9000 46 | } 47 | } -------------------------------------------------------------------------------- /scripts/settlement-scripts/010_SetInstantRouterInInstantPool.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import { BigNumber, BigNumberish } from "ethers"; 5 | const logger = require('node-color-log'); 6 | 7 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 8 | const {deployments, getNamedAccounts, network} = hre; 9 | const {deploy, log} = deployments; 10 | const { deployer } = await getNamedAccounts(); 11 | 12 | logger.color('blue').log("-------------------------------------------------") 13 | logger.color('blue').bold().log("Set instant router in CC transfer...") 14 | 15 | const instantPool = await deployments.get("InstantPool") 16 | const instantRouter = await deployments.get("InstantRouter") 17 | 18 | const instantPoolFactory = await ethers.getContractFactory("InstantPool"); 19 | const instantPoolInstance = await instantPoolFactory.attach( 20 | instantPool.address 21 | ); 22 | 23 | const checkInstantRouterInInstantPool = await instantPoolInstance.instantRouter() 24 | 25 | if (checkInstantRouterInInstantPool != instantRouter.address) { 26 | const setInstantRouterTx = await instantPoolInstance.setInstantRouter( 27 | instantRouter.address 28 | ) 29 | 30 | await setInstantRouterTx.wait(1) 31 | console.log("set instant router in instant pool: ", setInstantRouterTx.hash) 32 | } else { 33 | console.log("instant router is already settled in instant pool") 34 | } 35 | 36 | }; 37 | 38 | export default func; 39 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 40 | -------------------------------------------------------------------------------- /scripts/set-global-variables/004_SetPriceOracle.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import { BigNumber, BigNumberish } from "ethers"; 5 | const logger = require('node-color-log'); 6 | 7 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 8 | const {deployments, getNamedAccounts, network} = hre; 9 | const {deploy} = deployments; 10 | const { deployer } = await getNamedAccounts(); 11 | let tx 12 | 13 | logger.color('blue').log("-------------------------------------------------") 14 | logger.color('blue').bold().log("Set price oracle globally...") 15 | 16 | const priceOracle = await deployments.get("PriceOracle") 17 | 18 | 19 | // set relay in instant router 20 | const instantRouter = await deployments.get("InstantRouter") 21 | const instantRouterFactory = await ethers.getContractFactory("InstantRouter") 22 | const instantRouterInstance = await instantRouterFactory.attach( 23 | instantRouter.address 24 | ) 25 | 26 | const checkPriceOracleInInstantRouter = await instantRouterInstance.priceOracle() 27 | 28 | if (checkPriceOracleInInstantRouter != priceOracle.address) { 29 | tx = await instantRouterInstance.setPriceOracle( 30 | priceOracle.address 31 | ) 32 | tx.wait(1) 33 | 34 | console.log("set priceOracle in instant router: ", tx.hash) 35 | } else { 36 | console.log("priceOracle is already settled in instant router") 37 | } 38 | 39 | 40 | 41 | }; 42 | 43 | export default func; 44 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 45 | -------------------------------------------------------------------------------- /config/polygon.json: -------------------------------------------------------------------------------- 1 | { 2 | "bitcoin_network": "mainnet", 3 | "uniswap_v2_router_02": "0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff", 4 | "uniswap_v2_factory": "0x5757371414417b8C6CAad45bAeF941aBc7d3Ab32", 5 | "wrapped_matic": "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270", 6 | "usdt_token": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F", 7 | "usdc_token": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", 8 | "acceptable_delay": 177, 9 | "chain_id": 137, 10 | "fee_to_setter": "0x5364E3557572bd5D5903C0e9C21BE359F2Eac1dA", 11 | "treasury": "0x5364E3557572bd5D5903C0e9C21BE359F2Eac1dA", 12 | "chain_link_oracles": { 13 | "matic_usd": "0xAB594600376Ec9fD91F8e885dADF0CE036862dE0", 14 | "btc_usd": "0xc907E116054Ad103354f2D350FD2514433D57F6f", 15 | "usdt_usd": "0x0A6513e40db6EB1b165753AD52E80663aeA50545", 16 | "usdc_usd": "0xfE4A8cc5b5B2366C1B58Bea3858e81843581b2F7" 17 | }, 18 | "cc_transfer": { 19 | "app_id": 1, 20 | "protocol_percentage_fee": 5 21 | }, 22 | "cc_exchange": { 23 | "app_id": 10, 24 | "protocol_percentage_fee": 5 25 | }, 26 | "cc_burn": { 27 | "protocol_percentage_fee": 5, 28 | "slasher_percentage_reward": 500, 29 | "bitcoin_fee": 10000, 30 | "transfer_deadLine": 72 31 | }, 32 | "instant_router": { 33 | "slasher_percentage_reward": 500, 34 | "payback_deadline": 12, 35 | "max_price_difference_percent": 500 36 | }, 37 | "instant_pool": { 38 | "instant_percentage_fee": 15 39 | }, 40 | "lockers_contract": { 41 | "minimum_native_locked_amount": "40000000000000000000000", 42 | "collateral_ratio": 13000, 43 | "liquidation_ratio": 10500, 44 | "locker_percentage_fee": 15, 45 | "price_with_discount_ratio": 9000 46 | } 47 | } -------------------------------------------------------------------------------- /scripts/settlement-scripts/008_SetInstantPoolInInstantRouter.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import { BigNumber, BigNumberish } from "ethers"; 5 | const logger = require('node-color-log'); 6 | 7 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 8 | const {deployments, getNamedAccounts, network} = hre; 9 | const {deploy, log} = deployments; 10 | const { deployer } = await getNamedAccounts(); 11 | 12 | logger.color('blue').log("-------------------------------------------------") 13 | logger.color('blue').bold().log("Set instant pool in instant router...") 14 | 15 | const instantRouter = await deployments.get("InstantRouter") 16 | const instantPool = await deployments.get("InstantPool") 17 | 18 | const instantRouterFactory = await ethers.getContractFactory("InstantRouter"); 19 | const instantRouterInstance = await instantRouterFactory.attach( 20 | instantRouter.address 21 | ); 22 | 23 | const checkInstantPoolInInstantRouter = await instantRouterInstance.teleBTCInstantPool() 24 | 25 | if (checkInstantPoolInInstantRouter != instantPool.address) { 26 | const setInstantPoolTx = await instantRouterInstance.setTeleBTCInstantPool( 27 | instantPool.address 28 | ) 29 | 30 | await setInstantPoolTx.wait(1) 31 | console.log("set instant pool in instant router: ", setInstantPoolTx.hash) 32 | } else { 33 | console.log("instant pool is already settled in instant router") 34 | } 35 | 36 | }; 37 | 38 | export default func; 39 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 40 | -------------------------------------------------------------------------------- /scripts/settlement-scripts/005_SetInstantRouterInCCTransfer.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import { BigNumber, BigNumberish } from "ethers"; 5 | const logger = require('node-color-log'); 6 | 7 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 8 | const {deployments, getNamedAccounts, network} = hre; 9 | const {deploy, log} = deployments; 10 | const { deployer } = await getNamedAccounts(); 11 | 12 | logger.color('blue').log("-------------------------------------------------") 13 | logger.color('blue').bold().log("Set instant router in CC transfer...") 14 | 15 | const ccTransferRouter = await deployments.get("CCTransferRouter") 16 | const instantRouter = await deployments.get("InstantRouter") 17 | 18 | const ccTransferRouterFactory = await ethers.getContractFactory("CCTransferRouter"); 19 | const ccTransferRouterInstance = await ccTransferRouterFactory.attach( 20 | ccTransferRouter.address 21 | ); 22 | 23 | const checkInstantRouterInCCTransfer = await ccTransferRouterInstance.instantRouter() 24 | 25 | if (checkInstantRouterInCCTransfer != instantRouter.address) { 26 | const setInstantRouterTx = await ccTransferRouterInstance.setInstantRouter( 27 | instantRouter.address 28 | ) 29 | 30 | await setInstantRouterTx.wait(1) 31 | console.log("set instant router in CC transfer: ", setInstantRouterTx.hash) 32 | } else { 33 | console.log("instant router is already settled in CC transfer") 34 | } 35 | 36 | }; 37 | 38 | export default func; 39 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 40 | -------------------------------------------------------------------------------- /scripts/settlement-scripts/004_SetExchangeRouterInPriceOracle.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import config from 'config' 5 | import { BigNumber, BigNumberish } from "ethers"; 6 | const logger = require('node-color-log'); 7 | 8 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 9 | const {deployments, getNamedAccounts, network} = hre; 10 | const {deploy, log} = deployments; 11 | const { deployer } = await getNamedAccounts(); 12 | 13 | logger.color('blue').log("-------------------------------------------------") 14 | logger.color('blue').bold().log("Set Exchange Router in price oracle...") 15 | 16 | const uniswapV2Router02 = config.get("uniswap_v2_router_02") 17 | const uniswapV2Connector = await deployments.get("UniswapV2Connector") 18 | const priceOracle = await deployments.get("PriceOracle") 19 | 20 | 21 | const PriceOracleFactory = await ethers.getContractFactory("PriceOracle"); 22 | const priceOracleInstance = await PriceOracleFactory.attach( 23 | priceOracle.address 24 | ); 25 | 26 | const exchangeConnectorAddress = await priceOracleInstance.exchangeConnector( 27 | uniswapV2Router02 28 | ) 29 | 30 | if (exchangeConnectorAddress == "0x0000000000000000000000000000000000000000") { 31 | const addExchangeTx = await priceOracleInstance.addExchangeConnector( 32 | uniswapV2Router02, 33 | uniswapV2Connector.address 34 | ) 35 | 36 | await addExchangeTx.wait(1) 37 | console.log("set exchange router in price oracle: ", addExchangeTx.hash) 38 | } 39 | }; 40 | 41 | export default func; 42 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TeleportDAO Protocol V1 2 | 3 | This repository contains the smart contracts for the TeleportDAO bridge, cross-chain transfer, and cross-chain exchange. The codes belong to connecting Bitcoin to EVM-based blockchains. The repository uses Hardhat as development environment for compilation, testing and deployment tasks. 4 | 5 | ## What is Teleport? 6 | 7 | Teleport is a trustless and universal protocol that provides an infrastructure for developers to build cross-chain applications. In other words, Teleport helps blockchains communicate with each other. Applications on one blockchain can access the latest data on other blockchains using Teleport relay smart contract. 8 | 9 | ## Documentation 10 | 11 | See the link below: 12 | - [Documentation](https://docs.teleportdao.xyz/introduction/what-is-teleportdao) 13 | 14 | ## Community 15 | 16 | You can join the discord channel [here](https://discord.com/invite/6RSsgfQgcb). 17 | 18 | ## Getting Started 19 | 20 | To start, clone the codes and install the needed packages using: 21 | 22 | `yarn` 23 | 24 | If you only want to compile the codes enter the below command: 25 | 26 | `yarn clean` 27 | 28 | `yarn build` 29 | 30 | You can also run the full test suite with the following command: 31 | 32 | `yarn test` 33 | 34 | 35 | You can deploy the contracts on specified networks in package.json with the following command: 36 | 37 | `yarn test` 38 | 39 | After deployments, the contracts need some settlements, do them by the following commands: 40 | 41 | `yarn settlement:mumbai` 42 | 43 | `yarn collateral_pool_scripts:mumbai` 44 | 45 | (with a different private key than the deployer one) 46 | 47 | `yarn lockers_settlement:mumbai` 48 | 49 | If some contracts has changed, update their addresses in other contracts by the following command: 50 | 51 | `yarn global_variables_settlement:mumbai` 52 | -------------------------------------------------------------------------------- /contracts/pools/interfaces/ICollateralPoolFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.8.4; 3 | 4 | interface ICollateralPoolFactory { 5 | 6 | // Events 7 | 8 | /// @notice Emits when a collateral pool is created 9 | /// @param name Name of the collateral token 10 | /// @param collateralToken Collateral token address 11 | /// @param collateralizationRatio At most (collateral value)/(collateralization ratio) can be moved instantly by the user 12 | /// @param collateralPool Collateral pool contract address 13 | event CreateCollateralPool( 14 | string name, 15 | address indexed collateralToken, 16 | uint collateralizationRatio, 17 | address indexed collateralPool 18 | ); 19 | 20 | /// @notice Emits when a collateral pool is removed 21 | /// @param collateralToken Collateral token address 22 | /// @param collateralPool Collateral pool contract address 23 | event RemoveCollateralPool( 24 | address indexed collateralToken, 25 | address indexed collateralPool 26 | ); 27 | 28 | // Read-only functions 29 | 30 | function getCollateralPoolByToken(address _collateralToken) external view returns (address); 31 | 32 | function allCollateralPools(uint _index) external view returns (address); 33 | 34 | function allCollateralPoolsLength() external view returns (uint); 35 | 36 | function isCollateral(address _collateralToken) external view returns (bool); 37 | 38 | // State-changing functions 39 | 40 | function createCollateralPool(address _collateralToken, uint _collateralizationRatio) external returns (address); 41 | 42 | function removeCollateralPool(address _collateralToken, uint _index) external returns (bool); 43 | } -------------------------------------------------------------------------------- /contracts/lockers/LockersStorageStructure.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.8.4; 3 | 4 | import "./interfaces/ILockersStorage.sol"; 5 | 6 | contract LockersStorageStructure is ILockersStorage { 7 | 8 | // Constants 9 | uint public constant ONE_HUNDRED_PERCENT = 10000; 10 | uint public constant HEALTH_FACTOR = 10000; 11 | uint public constant UPPER_HEALTH_FACTOR = 12500; 12 | uint public constant MAX_LOCKER_FEE = 10000; 13 | uint public constant INACTIVATION_DELAY = 345600; // 4 days (it should be greater than MAX_FINALIZATION_PARAMETER) 14 | uint public constant NATIVE_TOKEN_DECIMAL = 18; 15 | address public constant NATIVE_TOKEN = address(1); 16 | 17 | // Public variables 18 | address public override TeleportDAOToken; 19 | address public override teleBTC; 20 | address public override ccBurnRouter; 21 | address public override exchangeConnector; 22 | address public override priceOracle; 23 | 24 | uint public override minRequiredTDTLockedAmount; 25 | uint public override minRequiredTNTLockedAmount; 26 | uint public override lockerPercentageFee; 27 | uint public override collateralRatio; 28 | uint public override liquidationRatio; 29 | uint public override priceWithDiscountRatio; 30 | uint public override totalNumberOfCandidates; 31 | uint public override totalNumberOfLockers; 32 | 33 | mapping(address => DataTypes.locker) public lockersMapping; // locker's target address -> locker structure 34 | mapping(address => uint) public lockerInactivationTimestamp; 35 | mapping(address => bool) public lockerLeavingAcceptance; 36 | mapping(bytes => address) public lockerTargetAddress; // locker's locking script -> locker's target address 37 | mapping(address => bool) minters; 38 | mapping(address => bool) burners; 39 | 40 | DataTypes.lockersLibConstants public libConstants; 41 | DataTypes.lockersLibParam public libParams; 42 | 43 | } 44 | -------------------------------------------------------------------------------- /scripts/collateralPool-script/002_CollateralCreationUSDT.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import config from 'config' 5 | import { BigNumber } from 'ethers'; 6 | const logger = require('node-color-log'); 7 | 8 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 9 | const {deployments, getNamedAccounts, network} = hre; 10 | const {deploy, log} = deployments; 11 | const { deployer } = await getNamedAccounts(); 12 | 13 | logger.color('blue').log("-------------------------------------------------") 14 | logger.color('blue').bold().log("Create collateral pool with factory and add liquidity to it...") 15 | 16 | const collateralPoolFactoryContract = await deployments.get("CollateralPoolFactory") 17 | const collateralPoolFactoryFactory = await ethers.getContractFactory("CollateralPoolFactory") 18 | const collateralPoolFactoryInstance = await collateralPoolFactoryFactory.attach( 19 | collateralPoolFactoryContract.address 20 | ) 21 | 22 | const usdt = config.get("usdt_token") as string 23 | 24 | const hasCollateralPoolAddress = await collateralPoolFactoryInstance.getCollateralPoolByToken( 25 | usdt 26 | ) 27 | 28 | if (hasCollateralPoolAddress == "0x0000000000000000000000000000000000000000") { 29 | const createCollateralPoolTx = await collateralPoolFactoryInstance.createCollateralPool( 30 | usdt, 31 | 15000 32 | ) 33 | 34 | await createCollateralPoolTx.wait(1) 35 | console.log("create usdt collateral pool: ", createCollateralPoolTx.hash) 36 | 37 | } else { 38 | console.log("usdt collateral pool already exists: ") 39 | } 40 | 41 | logger.color('blue').log("-------------------------------------------------") 42 | }; 43 | 44 | export default func; 45 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 46 | -------------------------------------------------------------------------------- /scripts/collateralPool-script/003_CollateralCreationUSDC.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import config from 'config' 5 | import { BigNumber } from 'ethers'; 6 | const logger = require('node-color-log'); 7 | 8 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 9 | const {deployments, getNamedAccounts, network} = hre; 10 | const {deploy, log} = deployments; 11 | const { deployer } = await getNamedAccounts(); 12 | 13 | logger.color('blue').log("-------------------------------------------------") 14 | logger.color('blue').bold().log("Create collateral pool with factory and add liquidity to it...") 15 | 16 | const collateralPoolFactoryContract = await deployments.get("CollateralPoolFactory") 17 | const collateralPoolFactoryFactory = await ethers.getContractFactory("CollateralPoolFactory") 18 | const collateralPoolFactoryInstance = await collateralPoolFactoryFactory.attach( 19 | collateralPoolFactoryContract.address 20 | ) 21 | 22 | const usdc = config.get("usdc_token") as string 23 | 24 | const hasCollateralPoolAddress = await collateralPoolFactoryInstance.getCollateralPoolByToken( 25 | usdc 26 | ) 27 | 28 | if (hasCollateralPoolAddress == "0x0000000000000000000000000000000000000000") { 29 | const createCollateralPoolTx = await collateralPoolFactoryInstance.createCollateralPool( 30 | usdc, 31 | 15000 32 | ) 33 | 34 | await createCollateralPoolTx.wait(1) 35 | console.log("create usdc collateral pool: ", createCollateralPoolTx.hash) 36 | 37 | } else { 38 | console.log("usdc collateral pool already exists: ") 39 | } 40 | 41 | logger.color('blue').log("-------------------------------------------------") 42 | }; 43 | 44 | export default func; 45 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 46 | -------------------------------------------------------------------------------- /scripts/settlement-scripts/001_TeleBTCSettlement.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | const logger = require('node-color-log'); 5 | 6 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 7 | const {deployments, getNamedAccounts, network} = hre; 8 | const {deploy} = deployments; 9 | const { deployer } = await getNamedAccounts(); 10 | 11 | logger.color('blue').log("-------------------------------------------------") 12 | logger.color('blue').bold().log("TeleBTC settlement...") 13 | 14 | const teleBTC = await deployments.get("TeleBTC") 15 | const lockersProxy = await deployments.get("LockersProxy") 16 | 17 | 18 | const teleBTCFactory = await ethers.getContractFactory("TeleBTC"); 19 | const teleBTCInstance = await teleBTCFactory.attach( 20 | teleBTC.address 21 | ); 22 | 23 | const isLockerMinter = await teleBTCInstance.minters( 24 | lockersProxy.address 25 | ) 26 | 27 | if (!isLockerMinter) { 28 | const addLockerAsMinter = await teleBTCInstance.addMinter( 29 | lockersProxy.address 30 | ) 31 | 32 | await addLockerAsMinter.wait(1) 33 | console.log("add locker as minter: ", addLockerAsMinter.hash) 34 | } else { 35 | console.log("locker is already a minter") 36 | } 37 | 38 | const isLockerBurner = await teleBTCInstance.burners( 39 | lockersProxy.address 40 | ) 41 | 42 | if (!isLockerBurner) { 43 | const addLockerAsBurner = await teleBTCInstance.addBurner( 44 | lockersProxy.address 45 | ) 46 | 47 | await addLockerAsBurner.wait(1) 48 | console.log("add locker as burner: ", addLockerAsBurner.hash) 49 | } else { 50 | console.log("locker is already a burner") 51 | } 52 | 53 | }; 54 | 55 | export default func; 56 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 57 | -------------------------------------------------------------------------------- /scripts/locker-settlement-script/002_SetPriceOracleInLocker.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import { BigNumber, BigNumberish } from "ethers"; 5 | const logger = require('node-color-log'); 6 | 7 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 8 | const {deployments, getNamedAccounts, network} = hre; 9 | const {deploy, log} = deployments; 10 | const { deployer } = await getNamedAccounts(); 11 | 12 | logger.color('blue').log("-------------------------------------------------") 13 | logger.color('blue').bold().log("Set teleBTC in Locker...") 14 | 15 | const one = BigNumber.from(10).pow(18).mul(1) 16 | 17 | const lockersLib = await deployments.get("LockersLib") 18 | const lockersProxy = await deployments.get("LockersProxy") 19 | 20 | const priceOracle = await deployments.get("PriceOracle") 21 | 22 | const lockersLogicFactory = await ethers.getContractFactory( 23 | "LockersLogic", 24 | { 25 | libraries: { 26 | LockersLib: lockersLib.address 27 | } 28 | } 29 | ); 30 | const lockersInstance = await lockersLogicFactory.attach( 31 | lockersProxy.address 32 | ); 33 | 34 | 35 | const priceOracleAddress = await lockersInstance.priceOracle() 36 | 37 | if (priceOracleAddress != priceOracle.address) { 38 | const addPriceOracle = await lockersInstance.setPriceOracle( 39 | priceOracle.address 40 | ) 41 | 42 | await addPriceOracle.wait(1) 43 | console.log("add price oracle in lockers proxy contract: ", addPriceOracle.hash) 44 | } else { 45 | console.log("price oracle is already settled in lockers proxy contract") 46 | } 47 | 48 | logger.color('blue').log("-------------------------------------------------") 49 | 50 | }; 51 | 52 | export default func; 53 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 54 | -------------------------------------------------------------------------------- /contracts/uniswap/v2-periphery/libraries/TransferHelper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.6.0; 4 | 5 | // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false 6 | library TransferHelper { 7 | function safeApprove( 8 | address token, 9 | address to, 10 | uint256 value 11 | ) internal { 12 | // bytes4(keccak256(bytes('approve(address,uint256)'))); 13 | (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value)); 14 | require( 15 | success && (data.length == 0 || abi.decode(data, (bool))), 16 | 'TransferHelper::safeApprove: approve failed' 17 | ); 18 | } 19 | 20 | function safeTransfer( 21 | address token, 22 | address to, 23 | uint256 value 24 | ) internal { 25 | // bytes4(keccak256(bytes('transfer(address,uint256)'))); 26 | (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value)); 27 | require( 28 | success && (data.length == 0 || abi.decode(data, (bool))), 29 | 'TransferHelper::safeTransfer: transfer failed' 30 | ); 31 | } 32 | 33 | function safeTransferFrom( 34 | address token, 35 | address from, 36 | address to, 37 | uint256 value 38 | ) internal { 39 | // bytes4(keccak256(bytes('transferFrom(address,address,uint256)'))); 40 | (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value)); 41 | require( 42 | success && (data.length == 0 || abi.decode(data, (bool))), 43 | 'TransferHelper::transferFrom: transferFrom failed' 44 | ); 45 | } 46 | 47 | function safeTransferETH(address to, uint256 value) internal { 48 | (bool success, ) = to.call{value: value}(new bytes(0)); 49 | require(success, 'TransferHelper::safeTransferETH: ETH transfer failed'); 50 | } 51 | } -------------------------------------------------------------------------------- /scripts/locker-settlement-script/004_SetCCBurnRouterInLocker.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import { BigNumber, BigNumberish } from "ethers"; 5 | const logger = require('node-color-log'); 6 | 7 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 8 | const {deployments, getNamedAccounts, network} = hre; 9 | const {deploy, log} = deployments; 10 | const { deployer } = await getNamedAccounts(); 11 | 12 | logger.color('blue').log("-------------------------------------------------") 13 | logger.color('blue').bold().log("Set teleBTC in Locker...") 14 | 15 | const one = BigNumber.from(10).pow(18).mul(1) 16 | 17 | const lockersLib = await deployments.get("LockersLib") 18 | const lockersProxy = await deployments.get("LockersProxy") 19 | 20 | const ccBurnRouter = await deployments.get("CCBurnRouter") 21 | 22 | const lockersLogicFactory = await ethers.getContractFactory( 23 | "LockersLogic", 24 | { 25 | libraries: { 26 | LockersLib: lockersLib.address 27 | } 28 | } 29 | ); 30 | const lockersInstance = await lockersLogicFactory.attach( 31 | lockersProxy.address 32 | ); 33 | 34 | 35 | const ccBurnRouterAddress = await lockersInstance.ccBurnRouter() 36 | 37 | if (ccBurnRouterAddress != ccBurnRouter.address) { 38 | const addCCBurnRouter = await lockersInstance.setCCBurnRouter( 39 | ccBurnRouter.address 40 | ) 41 | 42 | await addCCBurnRouter.wait(1) 43 | console.log("add cc burn router in lockers proxy contract: ", addCCBurnRouter.hash) 44 | } else { 45 | console.log("cc burn router is already settled in lockers proxy contract") 46 | } 47 | 48 | logger.color('blue').log("-------------------------------------------------") 49 | 50 | }; 51 | 52 | export default func; 53 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 54 | -------------------------------------------------------------------------------- /contracts/uniswap/v2-core/UniswapV2Factory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity =0.5.16; 3 | 4 | import './interfaces/IUniswapV2Factory.sol'; 5 | import './UniswapV2Pair.sol'; 6 | 7 | contract UniswapV2Factory is IUniswapV2Factory { 8 | address public feeTo; 9 | address public feeToSetter; 10 | 11 | mapping(address => mapping(address => address)) public getPair; 12 | address[] public allPairs; 13 | 14 | event PairCreated(address indexed token0, address indexed token1, address pair, uint); 15 | 16 | constructor(address _feeToSetter) public { 17 | feeToSetter = _feeToSetter; 18 | } 19 | 20 | function allPairsLength() external view returns (uint) { 21 | return allPairs.length; 22 | } 23 | 24 | function createPair(address tokenA, address tokenB) external returns (address pair) { 25 | require(tokenA != tokenB, 'UniswapV2: IDENTICAL_ADDRESSES'); 26 | (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); 27 | require(token0 != address(0), 'UniswapV2: ZERO_ADDRESS'); 28 | require(getPair[token0][token1] == address(0), 'UniswapV2: PAIR_EXISTS'); // single check is sufficient 29 | bytes memory bytecode = type(UniswapV2Pair).creationCode; 30 | bytes32 salt = keccak256(abi.encodePacked(token0, token1)); 31 | assembly { 32 | pair := create2(0, add(bytecode, 32), mload(bytecode), salt) 33 | } 34 | IUniswapV2Pair(pair).initialize(token0, token1); 35 | getPair[token0][token1] = pair; 36 | getPair[token1][token0] = pair; // populate mapping in the reverse direction 37 | allPairs.push(pair); 38 | emit PairCreated(token0, token1, pair, allPairs.length); 39 | } 40 | 41 | function setFeeTo(address _feeTo) external { 42 | require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN'); 43 | feeTo = _feeTo; 44 | } 45 | 46 | function setFeeToSetter(address _feeToSetter) external { 47 | require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN'); 48 | feeToSetter = _feeToSetter; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /deploy/013_CCTransferRouter.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import config from 'config' 4 | import { BigNumber } from 'ethers'; 5 | import verify from "../helper-functions" 6 | 7 | import * as dotenv from "dotenv"; 8 | dotenv.config(); 9 | 10 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 11 | const {deployments, getNamedAccounts, network} = hre; 12 | const {deploy} = deployments; 13 | const { deployer } = await getNamedAccounts(); 14 | 15 | let theBlockHeight = await process.env.BLOCK_HEIGHT; 16 | 17 | const protocolPercentageFee = config.get("cc_transfer.protocol_percentage_fee") 18 | const chainId = config.get("chain_id") 19 | const appId = config.get("cc_transfer.app_id") 20 | 21 | // TODO: update treasury address for main net 22 | const treasuryAddress = config.get("treasury") 23 | 24 | const bitcoinRelay = await deployments.get("BitcoinRelay") 25 | const lockersProxy = await deployments.get("LockersProxy") 26 | const teleBTC = await deployments.get("TeleBTC") 27 | 28 | const deployedContract = await deploy("CCTransferRouter", { 29 | from: deployer, 30 | log: true, 31 | skipIfAlreadyDeployed: true, 32 | args: [ 33 | theBlockHeight, 34 | protocolPercentageFee, 35 | chainId, 36 | appId, 37 | bitcoinRelay.address, 38 | lockersProxy.address, 39 | teleBTC.address, 40 | treasuryAddress 41 | ], 42 | }); 43 | 44 | if (network.name != "hardhat" && process.env.ETHERSCAN_API_KEY && process.env.VERIFY_OPTION == "1") { 45 | await verify(deployedContract.address, [ 46 | theBlockHeight, 47 | protocolPercentageFee, 48 | chainId, 49 | appId, 50 | bitcoinRelay.address, 51 | lockersProxy.address, 52 | teleBTC.address, 53 | treasuryAddress 54 | ], "contracts/routers/CCTransferRouter.sol:CCTransferRouter") 55 | } 56 | }; 57 | 58 | export default func; 59 | func.tags = ["CCTransferRouter"]; 60 | -------------------------------------------------------------------------------- /deploy/015_CCExchangeRouter.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import config from 'config' 4 | import { BigNumber } from 'ethers'; 5 | import verify from "../helper-functions" 6 | 7 | require('dotenv').config({path:"../config/temp.env"}); 8 | 9 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 10 | const {deployments, getNamedAccounts, network} = hre; 11 | const {deploy} = deployments; 12 | const { deployer } = await getNamedAccounts(); 13 | 14 | let theBlockHeight = process.env.BLOCK_HEIGHT; 15 | let theBlockHeightStr = theBlockHeight as string 16 | let blockHeightBigNumber = BigNumber.from(theBlockHeightStr) 17 | 18 | const protocolPercentageFee = config.get("cc_exchange.protocol_percentage_fee") 19 | const chainID = config.get("chain_id") 20 | 21 | // TODO: update treasury address for main net 22 | const treasuryAddress = config.get("treasury") 23 | 24 | const bitcoinRelay = await deployments.get("BitcoinRelay") 25 | const lockersProxy = await deployments.get("LockersProxy") 26 | const teleBTC = await deployments.get("TeleBTC") 27 | 28 | 29 | const deployedContract = await deploy("CCExchangeRouter", { 30 | from: deployer, 31 | log: true, 32 | skipIfAlreadyDeployed: true, 33 | args: [ 34 | blockHeightBigNumber, 35 | protocolPercentageFee, 36 | chainID, 37 | lockersProxy.address, 38 | bitcoinRelay.address, 39 | teleBTC.address, 40 | treasuryAddress 41 | ], 42 | }); 43 | 44 | if (network.name != "hardhat" && process.env.ETHERSCAN_API_KEY && process.env.VERIFY_OPTION == "1") { 45 | await verify(deployedContract.address, [ 46 | blockHeightBigNumber, 47 | protocolPercentageFee, 48 | chainID, 49 | lockersProxy.address, 50 | bitcoinRelay.address, 51 | teleBTC.address, 52 | treasuryAddress 53 | ], "contracts/routers/CCExchangeRouter.sol:CCExchangeRouter") 54 | } 55 | }; 56 | 57 | export default func; 58 | func.tags = ["CCExchangeRouter"]; 59 | -------------------------------------------------------------------------------- /scripts/settlement-scripts/007_SetInstantRouterInCCExchange.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import config from 'config' 5 | import { BigNumber, BigNumberish } from "ethers"; 6 | const logger = require('node-color-log'); 7 | 8 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 9 | const {deployments, getNamedAccounts, network} = hre; 10 | const {deploy, log} = deployments; 11 | const { deployer } = await getNamedAccounts(); 12 | 13 | 14 | logger.color('blue').log("-------------------------------------------------") 15 | logger.color('blue').bold().log("Set instant router and connector in CC exchange...") 16 | 17 | const ccExchangeRouter = await deployments.get("CCExchangeRouter") 18 | const instantRouter = await deployments.get("InstantRouter") 19 | const exchangeConnector = await deployments.get("UniswapV2Connector") 20 | 21 | const ccExchangeRouterFactory = await ethers.getContractFactory("CCExchangeRouter"); 22 | const ccExchangeRouterInstance = await ccExchangeRouterFactory.attach( 23 | ccExchangeRouter.address 24 | ); 25 | 26 | const setInstantRouterTx = await ccExchangeRouterInstance.setInstantRouter( 27 | instantRouter.address 28 | ) 29 | await setInstantRouterTx.wait(1) 30 | console.log("set instant router in CC exchange: ", setInstantRouterTx.hash) 31 | 32 | const exchangeAppId = config.get("cc_exchange.app_id") 33 | 34 | const checkExchangeConnectorInCCExchange = await ccExchangeRouterInstance.exchangeConnector(exchangeAppId) 35 | 36 | if (checkExchangeConnectorInCCExchange != exchangeConnector.address) { 37 | const setConnectorAndAppIdTx = await ccExchangeRouterInstance.setExchangeConnector( 38 | exchangeAppId, 39 | exchangeConnector.address 40 | ) 41 | await setConnectorAndAppIdTx.wait(1) 42 | console.log("set connector and app id in CC exchange: ", setConnectorAndAppIdTx.hash) 43 | } else { 44 | console.log("connector and app id are already settled in CC exchange") 45 | } 46 | 47 | 48 | }; 49 | 50 | export default func; 51 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 52 | -------------------------------------------------------------------------------- /deploy/017_InstantRouter.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import config from 'config' 4 | import verify from "../helper-functions" 5 | 6 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 7 | const {deployments, getNamedAccounts, network} = hre; 8 | const {deploy} = deployments; 9 | const { deployer } = await getNamedAccounts(); 10 | 11 | const slasherPercentageReward = config.get("instant_router.slasher_percentage_reward"); 12 | const paybackDeadline = config.get("instant_router.payback_deadline"); 13 | const maxPriceDifferencePercent = config.get("instant_router.max_price_difference_percent"); 14 | 15 | // TODO: update treasury address for main net 16 | const treasuryAddress = config.get("treasury") 17 | 18 | const teleBTC = await deployments.get("TeleBTC") 19 | const bitcoinRelay = await deployments.get("BitcoinRelay") 20 | const priceOracle = await deployments.get("PriceOracle") 21 | const collateralPoolFactory = await deployments.get("CollateralPoolFactory") 22 | const defaultExchangeConnector = await deployments.get("UniswapV2Connector") 23 | 24 | 25 | const deployedContract = await deploy("InstantRouter", { 26 | from: deployer, 27 | log: true, 28 | skipIfAlreadyDeployed: true, 29 | args: [ 30 | teleBTC.address, 31 | bitcoinRelay.address, 32 | priceOracle.address, 33 | collateralPoolFactory.address, 34 | slasherPercentageReward, 35 | paybackDeadline, 36 | defaultExchangeConnector.address, 37 | maxPriceDifferencePercent, 38 | treasuryAddress 39 | ], 40 | }); 41 | 42 | if (network.name != "hardhat" && process.env.ETHERSCAN_API_KEY && process.env.VERIFY_OPTION == "1") { 43 | await verify(deployedContract.address, [ 44 | teleBTC.address, 45 | bitcoinRelay.address, 46 | priceOracle.address, 47 | collateralPoolFactory.address, 48 | slasherPercentageReward, 49 | paybackDeadline, 50 | defaultExchangeConnector.address, 51 | maxPriceDifferencePercent, 52 | treasuryAddress 53 | ], "contracts/routers/InstantRouter.sol:InstantRouter") 54 | } 55 | }; 56 | 57 | export default func; 58 | func.tags = ["InstantRouter"]; 59 | -------------------------------------------------------------------------------- /deploy/014_CCBurnRouter.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import config from 'config' 4 | import verify from "../helper-functions" 5 | 6 | require('dotenv').config({path:"../config/temp.env"}); 7 | 8 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 9 | const {deployments, getNamedAccounts, network} = hre; 10 | const {deploy} = deployments; 11 | const { deployer } = await getNamedAccounts(); 12 | 13 | // TODO: un-comment the above one and remove the second one 14 | // let theBlockHeight = process.env.BLOCK_HEIGHT; 15 | let theBlockHeight = 777121; 16 | 17 | const protocolPercentageFee = config.get("cc_burn.protocol_percentage_fee") 18 | const slasherPercentageReward = config.get("cc_burn.slasher_percentage_reward") 19 | const bitcoinFee = config.get("cc_burn.bitcoin_fee") 20 | 21 | // TODO: update treasury address for main net 22 | const treasuryAddress = config.get("treasury") 23 | 24 | const transferDeadLine = config.get("cc_burn.transfer_deadLine") 25 | 26 | const bitcoinRelay = await deployments.get("BitcoinRelay") 27 | const lockersProxy = await deployments.get("LockersProxy") 28 | const teleBTC = await deployments.get("TeleBTC") 29 | 30 | 31 | 32 | const deployedContract = await deploy("CCBurnRouter", { 33 | from: deployer, 34 | log: true, 35 | skipIfAlreadyDeployed: true, 36 | args: [ 37 | theBlockHeight, 38 | bitcoinRelay.address, 39 | lockersProxy.address, 40 | treasuryAddress, 41 | teleBTC.address, 42 | transferDeadLine, 43 | protocolPercentageFee, 44 | slasherPercentageReward, 45 | bitcoinFee 46 | ], 47 | }); 48 | 49 | if (network.name != "hardhat" && process.env.ETHERSCAN_API_KEY && process.env.VERIFY_OPTION == "1") { 50 | await verify(deployedContract.address, [ 51 | theBlockHeight, 52 | bitcoinRelay.address, 53 | lockersProxy.address, 54 | treasuryAddress, 55 | teleBTC.address, 56 | transferDeadLine, 57 | protocolPercentageFee, 58 | slasherPercentageReward, 59 | bitcoinFee 60 | ], "contracts/routers/CCBurnRouter.sol:CCBurnRouter") 61 | } 62 | }; 63 | 64 | export default func; 65 | func.tags = ["CCBurnRouter"]; 66 | -------------------------------------------------------------------------------- /contracts/types/DataTypes.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.8.4; 3 | 4 | import "./ScriptTypesEnum.sol"; 5 | 6 | library DataTypes { 7 | 8 | /// @notice Structure for registering lockers 9 | /// @dev 10 | /// @param lockerLockingScript Locker redeem script 11 | /// @param lockerRescueType Locker script type in case of getting BTCs back 12 | /// @param lockerRescueScript Locker script in case of getting BTCs back 13 | /// @param TDTLockedAmount Bond amount of locker in TDT 14 | /// @param nativeTokenLockedAmount Bond amount of locker in native token of the target chain 15 | /// @param netMinted Total minted - total burnt 16 | /// @param slashingTeleBTCAmount Total amount of teleBTC a locker must be slashed 17 | /// @param reservedNativeTokenForSlash Total native token reserved to support slashing teleBTC 18 | /// @param isLocker Indicates that is already a locker or not 19 | /// @param isCandidate Indicates that is a candidate or not 20 | /// @param isScriptHash Shows if it's script hash 21 | /// has enough collateral to accept more minting requests) 22 | struct locker { 23 | bytes lockerLockingScript; 24 | ScriptTypes lockerRescueType; 25 | bytes lockerRescueScript; 26 | uint TDTLockedAmount; 27 | uint nativeTokenLockedAmount; 28 | uint netMinted; 29 | uint slashingTeleBTCAmount; 30 | uint reservedNativeTokenForSlash; 31 | bool isLocker; 32 | bool isCandidate; 33 | bool isScriptHash; 34 | } 35 | 36 | struct lockersLibConstants { 37 | uint OneHundredPercent; 38 | uint HealthFactor; 39 | uint UpperHealthFactor; 40 | uint MaxLockerFee; 41 | uint NativeTokenDecimal; 42 | address NativeToken; 43 | } 44 | 45 | struct lockersLibParam { 46 | address teleportDAOToken; 47 | address teleBTC; 48 | address ccBurnRouter; 49 | address exchangeConnector; 50 | address priceOracle; 51 | 52 | uint minRequiredTDTLockedAmount; 53 | uint minRequiredTNTLockedAmount; 54 | uint lockerPercentageFee; 55 | uint collateralRatio; 56 | uint liquidationRatio; 57 | uint priceWithDiscountRatio; 58 | uint inactivationDelay; 59 | } 60 | } -------------------------------------------------------------------------------- /contracts/uniswap/v2-periphery/UniswapV2Migrator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity =0.6.6; 3 | 4 | // import '@uniswap/lib/contracts/libraries/TransferHelper.sol'; 5 | 6 | import './interfaces/IUniswapV2Migrator.sol'; 7 | import './interfaces/V1/IUniswapV1Factory.sol'; 8 | import './interfaces/V1/IUniswapV1Exchange.sol'; 9 | import './interfaces/IUniswapV2Router01.sol'; 10 | import './interfaces/IERC20.sol'; 11 | import './libraries/TransferHelper.sol'; // Added 12 | 13 | contract UniswapV2Migrator is IUniswapV2Migrator { 14 | IUniswapV1Factory immutable factoryV1; 15 | IUniswapV2Router01 immutable router; 16 | 17 | constructor(address _factoryV1, address _router) public { 18 | factoryV1 = IUniswapV1Factory(_factoryV1); 19 | router = IUniswapV2Router01(_router); 20 | } 21 | 22 | // needs to accept ETH from any v1 exchange and the router. ideally this could be enforced, as in the router, 23 | // but it's not possible because it requires a call to the v1 factory, which takes too much gas 24 | receive() external payable {} 25 | 26 | function migrate(address token, uint amountTokenMin, uint amountETHMin, address to, uint deadline) 27 | external 28 | override 29 | { 30 | IUniswapV1Exchange exchangeV1 = IUniswapV1Exchange(factoryV1.getExchange(token)); 31 | uint liquidityV1 = exchangeV1.balanceOf(msg.sender); 32 | require(exchangeV1.transferFrom(msg.sender, address(this), liquidityV1), 'TRANSFER_FROM_FAILED'); 33 | (uint amountETHV1, uint amountTokenV1) = exchangeV1.removeLiquidity(liquidityV1, 1, 1, uint(-1)); 34 | TransferHelper.safeApprove(token, address(router), amountTokenV1); 35 | (uint amountTokenV2, uint amountETHV2,) = router.addLiquidityETH{value: amountETHV1}( 36 | token, 37 | amountTokenV1, 38 | amountTokenMin, 39 | amountETHMin, 40 | to, 41 | deadline 42 | ); 43 | if (amountTokenV1 > amountTokenV2) { 44 | TransferHelper.safeApprove(token, address(router), 0); // be a good blockchain citizen, reset allowance to 0 45 | TransferHelper.safeTransfer(token, msg.sender, amountTokenV1 - amountTokenV2); 46 | } else if (amountETHV1 > amountETHV2) { 47 | // addLiquidityETH guarantees that all of amountETHV1 or amountTokenV1 will be used, hence this else is safe 48 | TransferHelper.safeTransferETH(msg.sender, amountETHV1 - amountETHV2); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /contracts/uniswap/v2-core/interfaces/IUniswapV2Pair.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.5.0; 3 | 4 | interface IUniswapV2Pair { 5 | event Approval(address indexed owner, address indexed spender, uint value); 6 | event Transfer(address indexed from, address indexed to, uint value); 7 | 8 | function name() external pure returns (string memory); 9 | function symbol() external pure returns (string memory); 10 | function decimals() external pure returns (uint8); 11 | function totalSupply() external view returns (uint); 12 | function balanceOf(address owner) external view returns (uint); 13 | function allowance(address owner, address spender) external view returns (uint); 14 | 15 | function approve(address spender, uint value) external returns (bool); 16 | function transfer(address to, uint value) external returns (bool); 17 | function transferFrom(address from, address to, uint value) external returns (bool); 18 | 19 | function DOMAIN_SEPARATOR() external view returns (bytes32); 20 | function PERMIT_TYPEHASH() external pure returns (bytes32); 21 | function nonces(address owner) external view returns (uint); 22 | 23 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; 24 | 25 | event Mint(address indexed sender, uint amount0, uint amount1); 26 | event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); 27 | event Swap( 28 | address indexed sender, 29 | uint amount0In, 30 | uint amount1In, 31 | uint amount0Out, 32 | uint amount1Out, 33 | address indexed to 34 | ); 35 | event Sync(uint112 reserve0, uint112 reserve1); 36 | 37 | function MINIMUM_LIQUIDITY() external pure returns (uint); 38 | function factory() external view returns (address); 39 | function token0() external view returns (address); 40 | function token1() external view returns (address); 41 | function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); 42 | function price0CumulativeLast() external view returns (uint); 43 | function price1CumulativeLast() external view returns (uint); 44 | function kLast() external view returns (uint); 45 | 46 | function mint(address to) external returns (uint liquidity); 47 | function burn(address to) external returns (uint amount0, uint amount1); 48 | function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; 49 | function skim(address to) external; 50 | function sync() external; 51 | 52 | function initialize(address, address) external; 53 | } 54 | -------------------------------------------------------------------------------- /scripts/settlement-scripts/009_AddLiquidityToInstantPool.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import { BigNumber, BigNumberish } from "ethers"; 5 | import config from 'config' 6 | const logger = require('node-color-log'); 7 | let bitcoinNetwork = config.get("bitcoin_network") 8 | 9 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 10 | const {deployments, getNamedAccounts, network} = hre; 11 | const {deploy, log} = deployments; 12 | const { deployer } = await getNamedAccounts(); 13 | 14 | const one8Dec = BigNumber.from(10).pow(8).mul(1) 15 | 16 | if (bitcoinNetwork == "testnet") { 17 | logger.color('blue').log("-------------------------------------------------") 18 | logger.color('blue').bold().log("Add liquidity to instant pool...") 19 | 20 | const teleBTC = await deployments.get("TeleBTC") 21 | const instantPool = await deployments.get("InstantPool") 22 | 23 | const teleBTCFactory = await ethers.getContractFactory("TeleBTC"); 24 | const teleBTCInstance = await teleBTCFactory.attach( 25 | teleBTC.address 26 | ); 27 | 28 | const instantPoolFactory = await ethers.getContractFactory("InstantPool"); 29 | const instantPoolInstance = await instantPoolFactory.attach( 30 | instantPool.address 31 | ); 32 | 33 | const isMinterTeleBTCTx = await teleBTCInstance.minters(deployer) 34 | 35 | if(!isMinterTeleBTCTx) { 36 | const addMinterTeleBTCTx = await teleBTCInstance.addMinter(deployer) 37 | await addMinterTeleBTCTx.wait(1) 38 | } 39 | 40 | const mintTeleBTCTx = await teleBTCInstance.mint(deployer, one8Dec.div(2)) 41 | await mintTeleBTCTx.wait(1) 42 | console.log("mint telebtc: ", mintTeleBTCTx.hash) 43 | 44 | const approveTeleBTCTx = await teleBTCInstance.approve( 45 | instantPool.address, 46 | one8Dec.div(2) 47 | ) 48 | await approveTeleBTCTx.wait(1) 49 | console.log("approve instant pool to has access to telebtc: ", approveTeleBTCTx.hash) 50 | 51 | const addLiquiditylTx = await instantPoolInstance.addLiquidity( 52 | deployer, 53 | one8Dec.div(2) 54 | ) 55 | 56 | await addLiquiditylTx.wait(1) 57 | console.log("add liquidity to instant pool: ", addLiquiditylTx.hash) 58 | 59 | logger.color('blue').log("-------------------------------------------------") 60 | } 61 | 62 | }; 63 | 64 | export default func; 65 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 66 | -------------------------------------------------------------------------------- /scripts/locker-settlement-script/003_InitializeLockersLogic.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import { BigNumber, BigNumberish } from "ethers"; 5 | import config from 'config' 6 | const logger = require('node-color-log'); 7 | 8 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 9 | const {deployments, getNamedAccounts, network} = hre; 10 | const {deploy, log} = deployments; 11 | const { deployer } = await getNamedAccounts(); 12 | 13 | logger.color('blue').log("-------------------------------------------------") 14 | logger.color('blue').bold().log("Initialize lockers logic...") 15 | 16 | const lockersLib = await deployments.get("LockersLib") 17 | const lockersLogic = await deployments.get("LockersLogic") 18 | 19 | const ccBurnRouter = await deployments.get("CCBurnRouter") 20 | 21 | const teleDAOToken = await deployments.get("ERC20") 22 | const teleBTC = await deployments.get("TeleBTC") 23 | const exchangeConnector = await deployments.get("UniswapV2Connector") 24 | const priceOracle = await deployments.get("PriceOracle") 25 | const minTDTLockedAmount = 0; 26 | 27 | const minNativeLockedAmount = config.get("lockers_contract.minimum_native_locked_amount"); 28 | const collateralRatio = config.get("lockers_contract.collateral_ratio"); 29 | const liquidationRatio = config.get("lockers_contract.liquidation_ratio"); 30 | const lockerPercentageFee = config.get("lockers_contract.locker_percentage_fee"); 31 | const priceWithDiscountRatio = config.get("lockers_contract.price_with_discount_ratio"); 32 | 33 | const lockersLogicFactory = await ethers.getContractFactory( 34 | "LockersLogic", 35 | { 36 | libraries: { 37 | LockersLib: lockersLib.address 38 | } 39 | } 40 | ); 41 | const lockersInstance = await lockersLogicFactory.attach( 42 | lockersLogic.address 43 | ); 44 | 45 | const teleDAOTokenAddress = await lockersInstance.TeleportDAOToken() 46 | 47 | if (teleDAOTokenAddress == "0x0000000000000000000000000000000000000000") { 48 | const initializeTx = await lockersInstance.initialize( 49 | teleBTC.address, 50 | teleDAOToken.address, 51 | exchangeConnector.address, 52 | priceOracle.address, 53 | ccBurnRouter.address, 54 | minTDTLockedAmount, 55 | minNativeLockedAmount, 56 | collateralRatio, 57 | liquidationRatio, 58 | lockerPercentageFee, 59 | priceWithDiscountRatio 60 | ) 61 | 62 | await initializeTx.wait(1) 63 | console.log("initialize lockers logic: ", initializeTx.hash) 64 | } else { 65 | console.log("lockers logic is already initialized") 66 | } 67 | 68 | logger.color('blue').log("-------------------------------------------------") 69 | 70 | }; 71 | 72 | export default func; 73 | -------------------------------------------------------------------------------- /scripts/set-global-variables/002_SetInstantRouter.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import { BigNumber, BigNumberish } from "ethers"; 5 | const logger = require('node-color-log'); 6 | 7 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 8 | const {deployments, getNamedAccounts, network} = hre; 9 | const {deploy} = deployments; 10 | const { deployer } = await getNamedAccounts(); 11 | let tx 12 | 13 | logger.color('blue').log("-------------------------------------------------") 14 | logger.color('blue').bold().log("Set instant router globally...") 15 | 16 | const instantRouter = await deployments.get("InstantRouter") 17 | 18 | // set instant router in cc transfer router 19 | const ccTransferRouter = await deployments.get("CCTransferRouter") 20 | const ccTransferRouterFactory = await ethers.getContractFactory("CCTransferRouter") 21 | const ccTransferRouterInstance = await ccTransferRouterFactory.attach( 22 | ccTransferRouter.address 23 | ) 24 | 25 | const checkInstantRouterInCCTransfer = await ccTransferRouterInstance.instantRouter() 26 | 27 | if (checkInstantRouterInCCTransfer != instantRouter.address) { 28 | tx = await ccTransferRouterInstance.setInstantRouter( 29 | instantRouter.address 30 | ) 31 | tx.wait(1) 32 | console.log("set instant router in CCtransfer router: ", tx.hash) 33 | } else { 34 | console.log("instant router is already settled in CCtransfer router") 35 | } 36 | 37 | 38 | 39 | // set instant router in cc instant pool 40 | const instantPool = await deployments.get("InstantPool") 41 | const instantPoolFactory = await ethers.getContractFactory("InstantPool") 42 | const instantPoolInstance = await instantPoolFactory.attach( 43 | instantPool.address 44 | ) 45 | 46 | const checkInstantRouterInInstantPool = await instantPoolInstance.instantRouter() 47 | 48 | if (checkInstantRouterInInstantPool != instantRouter.address) { 49 | tx = await instantPoolInstance.setInstantRouter( 50 | instantRouter.address 51 | ) 52 | tx.wait(1) 53 | console.log("set instant router in instant pool: ", tx.hash) 54 | } 55 | 56 | 57 | 58 | // set instant router in cc exchange router 59 | const ccExchangeRouter = await deployments.get("CCExchangeRouter") 60 | const ccExchangeRouterFactory = await ethers.getContractFactory("CCExchangeRouter") 61 | const ccExchangeRouterInstance = await ccExchangeRouterFactory.attach( 62 | ccExchangeRouter.address 63 | ) 64 | 65 | const checkInstantRouterCCExchange = await ccExchangeRouterInstance.instantRouter() 66 | 67 | if (checkInstantRouterCCExchange != instantRouter.address) { 68 | tx = await ccExchangeRouterInstance.setInstantRouter( 69 | instantRouter.address 70 | ) 71 | tx.wait(1) 72 | console.log("set instant router in CCexchange router: ", tx.hash) 73 | } else { 74 | console.log("instant router is already settled in CCexchange router") 75 | } 76 | 77 | }; 78 | 79 | export default func; 80 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 81 | -------------------------------------------------------------------------------- /contracts/pools/interfaces/IInstantPool.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.8.4; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | 6 | interface IInstantPool is IERC20 { 7 | 8 | // Events 9 | 10 | /// @notice emits when an instant pool is created 11 | /// @param instantToken The instant token of this instant pool 12 | event CreatedInstantPool(address indexed instantToken); 13 | 14 | /// @notice emits when some liquidity gets added to the pool 15 | /// @param user User who added the liquidity 16 | /// @param teleBTCAmount Amount of teleBTC added to the pool 17 | /// @param instantPoolTokenAmount User's share from the pool 18 | event AddLiquidity(address indexed user, uint teleBTCAmount, uint instantPoolTokenAmount); 19 | 20 | /// @notice Emits when some liquidity gets removed from the pool 21 | /// @param user User who removed the liquidity 22 | /// @param teleBTCAmount Amount of teleBTC removed from the pool 23 | /// @param instantPoolTokenAmount User's share from the pool 24 | event RemoveLiquidity(address indexed user, uint teleBTCAmount, uint instantPoolTokenAmount); 25 | 26 | /// @notice Gets an instant loan from the contract 27 | /// @param user User who wants to get the loan 28 | /// @param requestedAmount Amount of loan requested and sent to the user 29 | /// @param instantFee Amount of fee that the user should pay back later with the loan 30 | event InstantLoan(address indexed user, uint256 requestedAmount, uint instantFee); 31 | 32 | /// @notice Emits when changes made to instant router address 33 | event NewInstantRouter(address oldInstantRouter, address newInstaneRouter); 34 | 35 | /// @notice Emits when changes made to instant percentage fee 36 | event NewInstantPercentageFee(uint oldInstantPercentageFee, uint newInstantPercentageFee); 37 | 38 | /// @notice Emits when changes made to TeleBTC address 39 | event NewTeleBTC(address oldTeleBTC, address newTeleBTC); 40 | 41 | // Read-only functions 42 | 43 | function teleBTC() external view returns (address); 44 | 45 | function instantRouter() external view returns (address); 46 | 47 | function totalAddedTeleBTC() external view returns (uint); 48 | 49 | function availableTeleBTC() external view returns (uint); 50 | 51 | function totalUnpaidLoan() external view returns (uint); 52 | 53 | function instantPercentageFee() external view returns (uint); 54 | 55 | function getFee(uint _loanAmount) external view returns (uint); 56 | 57 | // State-changing functions 58 | 59 | function setInstantRouter(address _instantRouter) external; 60 | 61 | function setInstantPercentageFee(uint _instantPercentageFee) external; 62 | 63 | function setTeleBTC(address _teleBTC) external; 64 | 65 | function addLiquidity(address _user, uint _amount) external returns (uint); 66 | 67 | function addLiquidityWithoutMint(uint _amount) external returns (bool); 68 | 69 | function removeLiquidity(address _user, uint _instantPoolTokenAmount) external returns (uint); 70 | 71 | function getLoan(address _user, uint _amount) external returns (bool); 72 | 73 | } -------------------------------------------------------------------------------- /deploy/006_BitcoinRelay.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import config from 'config' 4 | import verify from "../helper-functions" 5 | import { number } from 'bitcoinjs-lib/src/script'; 6 | 7 | var path = require('path'); 8 | var fs = require('fs'); 9 | 10 | var tempFilePath = path.join(__dirname, '..', '.env'); 11 | 12 | const {BitcoinRESTAPI} = require('bitcoin_rest_api'); 13 | const {baseURLMainnet} = require('bitcoin_rest_api'); 14 | const {baseURLTestnet} = require('bitcoin_rest_api'); 15 | const {networkMainnet} = require('bitcoin_rest_api'); 16 | const {networkTestnet} = require('bitcoin_rest_api'); 17 | 18 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 19 | const {deployments, getNamedAccounts, network} = hre; 20 | const {deploy} = deployments; 21 | const { deployer } = await getNamedAccounts(); 22 | 23 | // TODO: check with Sina to use the new bitcoin package 24 | let bitcoinRESTAPI; 25 | let bitcoinNetwork = config.get("bitcoin_network") 26 | 27 | if (bitcoinNetwork == "testnet") { 28 | bitcoinRESTAPI = new BitcoinRESTAPI(networkTestnet, baseURLTestnet, 2); 29 | } 30 | if (bitcoinNetwork == "mainnet") { 31 | bitcoinRESTAPI = new BitcoinRESTAPI(networkMainnet, baseURLMainnet, 2); 32 | } 33 | 34 | 35 | // Deploys BitcoinRelay 36 | // note: NEVER START WITH 0! IT MAKES PROBLEM 37 | let blockCount = await bitcoinRESTAPI.getBlockCount(); 38 | let height; 39 | if (blockCount > 5) { 40 | height = blockCount - 5; 41 | } else { 42 | height = blockCount; 43 | } 44 | 45 | let genesisHeader = await bitcoinRESTAPI.getHexBlockHeader(height); 46 | 47 | let periodStartHeight = height - height%2016; 48 | let periodStart = await bitcoinRESTAPI.getHexBlockHash(periodStartHeight); 49 | periodStart = Buffer.from(periodStart , 'hex').reverse().toString('hex'); 50 | 51 | const tdtToken = await deployments.get("ERC20") 52 | 53 | var blockHeight = "BLOCK_HEIGHT=" + height + "\n"; 54 | fs.appendFileSync(tempFilePath, blockHeight); 55 | 56 | const deployedContract = await deploy("BitcoinRelay", { 57 | from: deployer, 58 | log: true, 59 | skipIfAlreadyDeployed: true, 60 | args: [ 61 | '0x' + genesisHeader, 62 | height, 63 | '0x' + periodStart, 64 | tdtToken.address 65 | ], 66 | }); 67 | 68 | if (network.name != "hardhat" && process.env.ETHERSCAN_API_KEY && process.env.VERIFY_OPTION == "1") { 69 | 70 | let theBlockHeight = await process.env.BLOCK_HEIGHT; 71 | let height = Number(theBlockHeight) 72 | 73 | let genesisHeader = await bitcoinRESTAPI.getHexBlockHeader(height); 74 | 75 | let periodStartHeight = height - height%2016; 76 | let periodStart = await bitcoinRESTAPI.getHexBlockHash(periodStartHeight); 77 | periodStart = Buffer.from(periodStart , 'hex').reverse().toString('hex'); 78 | 79 | await verify(deployedContract.address, [ 80 | '0x' + genesisHeader, 81 | height, 82 | '0x' + periodStart, 83 | tdtToken.address 84 | ], "contracts/relay/BitcoinRelay.sol:BitcoinRelay") 85 | } 86 | }; 87 | 88 | export default func; 89 | func.tags = ["BitcoinRelay"]; 90 | -------------------------------------------------------------------------------- /hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import * as dotenv from "dotenv"; 2 | 3 | import { task, HardhatUserConfig} from "hardhat/config"; 4 | import { HttpNetworkUserConfig } from "hardhat/types"; 5 | 6 | import "@nomiclabs/hardhat-etherscan"; 7 | import "@nomiclabs/hardhat-waffle"; 8 | import "@typechain/hardhat"; 9 | import "hardhat-gas-reporter"; 10 | import "solidity-coverage"; 11 | import "hardhat-deploy"; 12 | import "hardhat-deploy-tenderly"; 13 | import "hardhat-contract-sizer"; 14 | 15 | dotenv.config(); 16 | 17 | const infuraNetwork = ( 18 | accounts: any, 19 | network: string, 20 | chainId?: number, 21 | gas?: number 22 | ): HttpNetworkUserConfig => { 23 | return { 24 | url: `https://${network}.infura.io/v3/${process.env.PROJECT_ID}`, 25 | chainId, 26 | gas, 27 | accounts, 28 | gasPrice: 200000000000, 29 | } 30 | } 31 | 32 | const config: HardhatUserConfig = { 33 | solidity: { 34 | compilers: [ 35 | { 36 | version: "0.5.16", 37 | settings: { 38 | optimizer: { 39 | enabled: true 40 | }, 41 | }, 42 | }, 43 | { 44 | version: "0.6.6", 45 | settings: { 46 | optimizer: { 47 | enabled: true 48 | }, 49 | }, 50 | }, 51 | { 52 | version: "0.7.6", 53 | settings: { 54 | optimizer: { 55 | enabled: true 56 | }, 57 | }, 58 | }, 59 | { 60 | version: "0.8.0", 61 | settings: { 62 | optimizer: { 63 | enabled: true 64 | }, 65 | }, 66 | }, 67 | { 68 | version: "0.8.2", 69 | settings: { 70 | optimizer: { 71 | enabled: true 72 | }, 73 | }, 74 | } 75 | ], 76 | }, 77 | networks: { 78 | mainnet: infuraNetwork( 79 | process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 80 | "mainnet", 81 | 1, 82 | 6283185, 83 | ), 84 | goerli: infuraNetwork( 85 | process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 86 | "goerli", 87 | 5, 88 | 6283185 89 | ), 90 | polygon: { 91 | url: "https://rpc-mainnet.maticvigil.com/", 92 | chainId: 137, 93 | accounts: process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 94 | gasPrice: 180000000000 95 | }, 96 | mumbai: { 97 | url: "https://rpc-mumbai.matic.today", 98 | chainId: 80001, 99 | accounts: process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 100 | }, 101 | bsc: { 102 | url: "https://bsc-dataseed.binance.org/", 103 | chainId: 56, 104 | gasPrice: 20000000000, 105 | accounts: process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 106 | }, 107 | bsc_testnet: { 108 | url: "https://data-seed-prebsc-1-s1.binance.org:8545", 109 | chainId: 97, 110 | accounts: process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], 111 | }, 112 | }, 113 | paths: { 114 | artifacts: "artifacts", 115 | deploy: "deploy", 116 | deployments: "deployments", 117 | }, 118 | typechain: { 119 | outDir: "src/types", 120 | target: "ethers-v5", 121 | }, 122 | namedAccounts: { 123 | deployer: { 124 | default: 0, 125 | }, 126 | }, 127 | gasReporter: { 128 | // enabled: process.env.REPORT_GAS !== undefined, 129 | enabled: true, 130 | currency: "USD", 131 | }, 132 | etherscan: { 133 | apiKey: process.env.ETHERSCAN_API_KEY, 134 | }, 135 | }; 136 | 137 | export default config; 138 | -------------------------------------------------------------------------------- /scripts/collateralPool-script/001_CollateralCreationWMATIC.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import config from 'config' 5 | import { BigNumber } from 'ethers'; 6 | const logger = require('node-color-log'); 7 | let bitcoinNetwork = config.get("bitcoin_network") 8 | 9 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 10 | const {deployments, getNamedAccounts, network} = hre; 11 | const {deploy, log} = deployments; 12 | const { deployer } = await getNamedAccounts(); 13 | 14 | logger.color('blue').log("-------------------------------------------------") 15 | logger.color('blue').bold().log("Create collateral pool with factory and add liquidity to it...") 16 | 17 | const oneUnit8Decimal = BigNumber.from(10).pow(8).mul(1) 18 | 19 | const collateralPoolFactoryContract = await deployments.get("CollateralPoolFactory") 20 | const collateralPoolFactoryFactory = await ethers.getContractFactory("CollateralPoolFactory") 21 | const collateralPoolFactoryInstance = await collateralPoolFactoryFactory.attach( 22 | collateralPoolFactoryContract.address 23 | ) 24 | 25 | const wrappedMatic = config.get("wrapped_matic") as string 26 | const erc20Factory = await ethers.getContractFactory("WETH") 27 | const erc20Instance = await erc20Factory.attach( 28 | wrappedMatic 29 | ) 30 | 31 | const hasCollateralPoolAddress = await collateralPoolFactoryInstance.getCollateralPoolByToken( 32 | wrappedMatic 33 | ) 34 | 35 | let collateralPoolAddress: any 36 | 37 | if (hasCollateralPoolAddress == "0x0000000000000000000000000000000000000000") { 38 | const createCollateralPoolTx = await collateralPoolFactoryInstance.createCollateralPool( 39 | wrappedMatic, 40 | 20000 41 | ) 42 | 43 | await createCollateralPoolTx.wait(1) 44 | console.log("create wmatic collateral pool: ", createCollateralPoolTx.hash) 45 | 46 | collateralPoolAddress = await collateralPoolFactoryInstance.getCollateralPoolByToken( 47 | wrappedMatic 48 | ) 49 | 50 | } else { 51 | collateralPoolAddress = hasCollateralPoolAddress 52 | } 53 | 54 | if (bitcoinNetwork == "testnet") { 55 | const depositTx = await erc20Instance.deposit( 56 | {value: oneUnit8Decimal} 57 | ); 58 | await depositTx.wait(1) 59 | 60 | const approveForCollateralPoolTx = await erc20Instance.approve(collateralPoolAddress, oneUnit8Decimal) 61 | await approveForCollateralPoolTx.wait(1) 62 | console.log("approve collateral pool to access to wrapped matic: ", approveForCollateralPoolTx.hash) 63 | 64 | const collateralPoolContract = await ethers.getContractFactory( 65 | "CollateralPool" 66 | ); 67 | 68 | const collateralPoolInstance = await collateralPoolContract.attach( 69 | collateralPoolAddress 70 | ); 71 | 72 | const addLiquidityTx = await collateralPoolInstance.addCollateral( 73 | deployer, 74 | oneUnit8Decimal 75 | ) 76 | 77 | await addLiquidityTx.wait(1) 78 | console.log("add collateral to collateral pool: ", addLiquidityTx.hash) 79 | } 80 | 81 | logger.color('blue').log("-------------------------------------------------") 82 | }; 83 | 84 | export default func; 85 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 86 | -------------------------------------------------------------------------------- /scripts/settlement-scripts/002_AddOrChargeLiquidityPair.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import config from 'config' 5 | import { BigNumber, BigNumberish } from "ethers"; 6 | const logger = require('node-color-log'); 7 | let bitcoinNetwork = config.get("bitcoin_network") 8 | 9 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 10 | const {deployments, getNamedAccounts, network} = hre; 11 | const {deploy} = deployments; 12 | const { deployer } = await getNamedAccounts(); 13 | 14 | logger.color('blue').log("-------------------------------------------------") 15 | logger.color('blue').bold().log("Add and charge liquidity pool if not exists...") 16 | 17 | const one8Dec = BigNumber.from(10).pow(8).mul(1) 18 | const one18Dec = BigNumber.from(10).pow(18).mul(1) 19 | 20 | const wrappedMatic = config.get("wrapped_matic") as string 21 | const teleBTC = await deployments.get("TeleBTC") 22 | const uniswapFactory = await config.get("uniswap_v2_factory") as string 23 | const uniswapRouter = await config.get("uniswap_v2_router_02") as string 24 | 25 | const wETHFactory = await ethers.getContractFactory("WETH"); 26 | const wETHInstance = await wETHFactory.attach( 27 | wrappedMatic 28 | ); 29 | 30 | const teleBTCFactory = await ethers.getContractFactory("TeleBTC"); 31 | const teleBTCInstance = await teleBTCFactory.attach( 32 | teleBTC.address 33 | ); 34 | 35 | 36 | const uniswapFactoryFactory = await ethers.getContractFactory("UniswapV2Factory"); 37 | const uniswapFactoryInstance = await uniswapFactoryFactory.attach( 38 | uniswapFactory 39 | ); 40 | 41 | const uniswapRouterFactory = await ethers.getContractFactory("UniswapV2Router02"); 42 | const uniswapRouterInstance = await uniswapRouterFactory.attach( 43 | uniswapRouter 44 | ); 45 | 46 | 47 | const theLiquidityPair2 = await uniswapFactoryInstance.getPair( 48 | teleBTC.address, 49 | wrappedMatic 50 | ) 51 | 52 | 53 | if (bitcoinNetwork == "testnet" && theLiquidityPair2 == "0x0000000000000000000000000000000000000000") { 54 | 55 | const timeNow = Date.now() 56 | const unixTimeNow = (timeNow - (timeNow % 1000))/1000 + 1000 57 | 58 | const isMinterTeleBTCTx = await teleBTCInstance.minters(deployer) 59 | 60 | // TODO: in main net the following code can not be ran 61 | if(!isMinterTeleBTCTx) { 62 | const addMinterTeleBTCTx = await teleBTCInstance.addMinter(deployer) 63 | await addMinterTeleBTCTx.wait(1) 64 | } 65 | 66 | const mintTeleBTCTx = await teleBTCInstance.mint(deployer, one8Dec.div(2)) 67 | await mintTeleBTCTx.wait(1) 68 | 69 | const approveTeleBTCTx = await teleBTCInstance.approve( 70 | uniswapRouter, 71 | one8Dec.div(2) 72 | ) 73 | await approveTeleBTCTx.wait(1) 74 | 75 | 76 | const addLiquidityPairTx = await uniswapRouterInstance.addLiquidityETH( 77 | teleBTC.address, 78 | one8Dec.div(2300), 79 | one8Dec.div(2500), 80 | one18Dec.div(12), 81 | deployer, 82 | unixTimeNow, 83 | { 84 | value: one18Dec.mul(10) 85 | } 86 | ) 87 | 88 | await addLiquidityPairTx.wait(1) 89 | console.log("add or charge telebtc-eth liquidity pair: ", addLiquidityPairTx.hash) 90 | } 91 | 92 | 93 | }; 94 | 95 | export default func; 96 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 97 | -------------------------------------------------------------------------------- /test/test_fixtures/ccBurnRequests.json: -------------------------------------------------------------------------------- 1 | { 2 | "burnProof_valid": { 3 | "txId" : "0x3bc193f1c3d40f1550ea31893da99120ab264cbc702208c21fc0065e8bc1d2a8", 4 | "version": "0x02000000", 5 | "vin": "0x01df4a990ad3c3a225862465bb660f06d445914a038ada819ace235afb9f23cff30200000000feffffff", 6 | "vout": "0x0200e1f505000000001976a91412ab8dc588ca9d5787dde7eb29569da63c3a238c88ac00e1f505000000001976a914748284390f9e263a4b766a75d0633c50426eb87587ac", 7 | "locktime": "0x00000000", 8 | "intermediateNodes": "0x7451e7cd7a5afcd93d5a3f84e4d7976fb3bd771dc6aeab416d818ea1d72c0476" 9 | }, 10 | "burnProof_validP2WPKH": { 11 | "txId": "0x9111c946df1b515a1a2a7a0d80124949829ba723a2fa20def361de6b3322fcb6", 12 | "version": "0x02000000", 13 | "vin": "0x01df4a990ad3c3a225862465bb660f06d445914a038ada819ace235afb9f23cff30200000000feffffff", 14 | "vout": "0x0200e1f50500000000160014751e76e8199196d454941c45d1b3a323f1433bd600e1f505000000001976a914748284390f9e263a4b766a75d0633c50426eb87587ac", 15 | "locktime": "0x00000000", 16 | "intermediateNodes": "0x7451e7cd7a5afcd93d5a3f84e4d7976fb3bd771dc6aeab416d818ea1d72c0476" 17 | }, 18 | "burnProof_validWithoutChange": { 19 | "txId": "0x5c91f47b3fb76bc0b4433fee7968aedb3081484de526095fdba763e39558ce46", 20 | "version": "0x02000000", 21 | "vin": "0x01df4a990ad3c3a225862465bb660f06d445914a038ada819ace235afb9f23cff30200000000feffffff", 22 | "vout": "0x0100e1f505000000001976a91412ab8dc588ca9d5787dde7eb29569da63c3a238c88ac", 23 | "locktime": "0x00000000", 24 | "intermediateNodes": "0x7451e7cd7a5afcd93d5a3f84e4d7976fb3bd771dc6aeab416d818ea1d72c0476" 25 | }, 26 | "burnProof_invalidChange": { 27 | "txId": "0xca36c95e99efb70de74c98832a1fd8141acb86229eab4130bd9894052c279703", 28 | "version": "0x02000000", 29 | "vin": "0x01df4a990ad3c3a225862465bb660f06d445914a038ada819ace235afb9f23cff30200000000feffffff", 30 | "vout": "0x0200e1f505000000001976a91412ab8dc588ca9d5787dde7eb29569da63c3a238c88ac00e1f505000000001976a914748284390f9e263a4b766a75d0633c50426eb87588ac", 31 | "locktime": "0x00000000", 32 | "intermediateNodes": "0x7451e7cd7a5afcd93d5a3f84e4d7976fb3bd771dc6aeab416d818ea1d72c0476" 33 | }, 34 | "disputeLocker_input": { 35 | "txId": "0xcc71d5eeeb0c5bfa8a1bcb6243287e48cd30ff96c954a328323f336192c05ae9", 36 | "version": "0x02000000", 37 | "vin": "0x013BC193F1C3D40F1550EA31893DA99120AB264CBC702208C21FC0065E8BC1D2A80100000000feffffff", 38 | "vout": "0x0200e1f505000000001976a91412ab8dc588ca9d5787dde7eb29569da63c3a238c88ac00e1f505000000001976a914748284390f9e263a4b766a75d0633c50426eb87587ac", 39 | "locktime": "0x00000000", 40 | "intermediateNodes": "0x7451e7cd7a5afcd93d5a3f84e4d7976fb3bd771dc6aeab416d818ea1d72c0476", 41 | "OutputValue": 200000000 42 | }, 43 | "disputeLocker_output": { 44 | "txId": "0x3BC193F1C3D40F1550EA31893DA99120AB264CBC702208C21FC0065E8BC1D2A8", 45 | "version": "0x02000000", 46 | "vin": "0x01df4a990ad3c3a225862465bb660f06d445914a038ada819ace235afb9f23cff30200000000feffffff", 47 | "vout": "0x0200e1f505000000001976a91412ab8dc588ca9d5787dde7eb29569da63c3a238c88ac00e1f505000000001976a914748284390f9e263a4b766a75d0633c50426eb87587ac", 48 | "locktime": "0x00000000", 49 | "intermediateNodes": "0x7451e7cd7a5afcd93d5a3f84e4d7976fb3bd771dc6aeab416d818ea1d72c0476" 50 | }, 51 | "disputeLocker_invalidOutput": { 52 | "txId": "0xa8d2c18b5e06c01fc2082270bc4c26ab2091a93d8931ea50150fd4c3f193c13b", 53 | "version": "0x02000000", 54 | "vin": "0x01af4a990ad3c3a225862465bb660f06d445914a038ada819ace235afb9f23cff30200000000feffffff", 55 | "vout": "0x0200e1f505000000001976a91412ab8dc588ca9d5787dde7eb29569da63c3a238c88ac00e1f505000000001976a914748284390f9e263a4b766a75d0633c50426eb87587ac", 56 | "locktime": "0x00000000", 57 | "intermediateNodes": "0x7451e7cd7a5afcd93d5a3f84e4d7976fb3bd771dc6aeab416d818ea1d72c0476" 58 | } 59 | } -------------------------------------------------------------------------------- /contracts/uniswap/v2-core/UniswapV2ERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity =0.5.16; 3 | 4 | import './interfaces/IUniswapV2ERC20.sol'; 5 | import './libraries/SafeMath.sol'; 6 | 7 | contract UniswapV2ERC20 is IUniswapV2ERC20 { 8 | using SafeMath for uint; 9 | 10 | string public constant name = 'Uniswap V2'; 11 | string public constant symbol = 'UNI-V2'; 12 | uint8 public constant decimals = 18; 13 | uint public totalSupply; 14 | mapping(address => uint) public balanceOf; 15 | mapping(address => mapping(address => uint)) public allowance; 16 | 17 | bytes32 public DOMAIN_SEPARATOR; 18 | // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); 19 | bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; 20 | mapping(address => uint) public nonces; 21 | 22 | event Approval(address indexed owner, address indexed spender, uint value); 23 | event Transfer(address indexed from, address indexed to, uint value); 24 | 25 | constructor() public { 26 | uint chainId; 27 | assembly { 28 | chainId := chainid 29 | } 30 | DOMAIN_SEPARATOR = keccak256( 31 | abi.encode( 32 | keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), 33 | keccak256(bytes(name)), 34 | keccak256(bytes('1')), 35 | chainId, 36 | address(this) 37 | ) 38 | ); 39 | } 40 | 41 | function _mint(address to, uint value) internal { 42 | totalSupply = totalSupply.add(value); 43 | balanceOf[to] = balanceOf[to].add(value); 44 | emit Transfer(address(0), to, value); 45 | } 46 | 47 | function _burn(address from, uint value) internal { 48 | balanceOf[from] = balanceOf[from].sub(value); 49 | totalSupply = totalSupply.sub(value); 50 | emit Transfer(from, address(0), value); 51 | } 52 | 53 | function _approve(address owner, address spender, uint value) private { 54 | allowance[owner][spender] = value; 55 | emit Approval(owner, spender, value); 56 | } 57 | 58 | function _transfer(address from, address to, uint value) private { 59 | balanceOf[from] = balanceOf[from].sub(value); 60 | balanceOf[to] = balanceOf[to].add(value); 61 | emit Transfer(from, to, value); 62 | } 63 | 64 | function approve(address spender, uint value) external returns (bool) { 65 | _approve(msg.sender, spender, value); 66 | return true; 67 | } 68 | 69 | function transfer(address to, uint value) external returns (bool) { 70 | _transfer(msg.sender, to, value); 71 | return true; 72 | } 73 | 74 | function transferFrom(address from, address to, uint value) external returns (bool) { 75 | if (allowance[from][msg.sender] != uint(-1)) { 76 | allowance[from][msg.sender] = allowance[from][msg.sender].sub(value); 77 | } 78 | _transfer(from, to, value); 79 | return true; 80 | } 81 | 82 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external { 83 | require(deadline >= block.timestamp, 'UniswapV2: EXPIRED'); 84 | bytes32 digest = keccak256( 85 | abi.encodePacked( 86 | '\x19\x01', 87 | DOMAIN_SEPARATOR, 88 | keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)) 89 | ) 90 | ); 91 | address recoveredAddress = ecrecover(digest, v, r, s); 92 | require(recoveredAddress != address(0) && recoveredAddress == owner, 'UniswapV2: INVALID_SIGNATURE'); 93 | _approve(owner, spender, value); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /contracts/uniswap/v2-periphery/interfaces/IUniswapV2Router01.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2; 3 | 4 | interface IUniswapV2Router01 { 5 | function factory() external pure returns (address); 6 | function WETH() external pure returns (address); 7 | 8 | function addLiquidity( 9 | address tokenA, 10 | address tokenB, 11 | uint amountADesired, 12 | uint amountBDesired, 13 | uint amountAMin, 14 | uint amountBMin, 15 | address to, 16 | uint deadline 17 | ) external returns (uint amountA, uint amountB, uint liquidity); 18 | function addLiquidityETH( 19 | address token, 20 | uint amountTokenDesired, 21 | uint amountTokenMin, 22 | uint amountETHMin, 23 | address to, 24 | uint deadline 25 | ) external payable returns (uint amountToken, uint amountETH, uint liquidity); 26 | function removeLiquidity( 27 | address tokenA, 28 | address tokenB, 29 | uint liquidity, 30 | uint amountAMin, 31 | uint amountBMin, 32 | address to, 33 | uint deadline 34 | ) external returns (uint amountA, uint amountB); 35 | function removeLiquidityETH( 36 | address token, 37 | uint liquidity, 38 | uint amountTokenMin, 39 | uint amountETHMin, 40 | address to, 41 | uint deadline 42 | ) external returns (uint amountToken, uint amountETH); 43 | function removeLiquidityWithPermit( 44 | address tokenA, 45 | address tokenB, 46 | uint liquidity, 47 | uint amountAMin, 48 | uint amountBMin, 49 | address to, 50 | uint deadline, 51 | bool approveMax, uint8 v, bytes32 r, bytes32 s 52 | ) external returns (uint amountA, uint amountB); 53 | function removeLiquidityETHWithPermit( 54 | address token, 55 | uint liquidity, 56 | uint amountTokenMin, 57 | uint amountETHMin, 58 | address to, 59 | uint deadline, 60 | bool approveMax, uint8 v, bytes32 r, bytes32 s 61 | ) external returns (uint amountToken, uint amountETH); 62 | function swapExactTokensForTokens( 63 | uint amountIn, 64 | uint amountOutMin, 65 | address[] calldata path, 66 | address to, 67 | uint deadline 68 | ) external returns (uint[] memory amounts); 69 | function swapTokensForExactTokens( 70 | uint amountOut, 71 | uint amountInMax, 72 | address[] calldata path, 73 | address to, 74 | uint deadline 75 | ) external returns (uint[] memory amounts); 76 | function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) 77 | external 78 | payable 79 | returns (uint[] memory amounts); 80 | function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) 81 | external 82 | returns (uint[] memory amounts); 83 | function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) 84 | external 85 | returns (uint[] memory amounts); 86 | function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) 87 | external 88 | payable 89 | returns (uint[] memory amounts); 90 | 91 | function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); 92 | function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); 93 | function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); 94 | function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); 95 | function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); 96 | } 97 | -------------------------------------------------------------------------------- /scripts/set-global-variables/001_SetRelay.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import { BigNumber, BigNumberish } from "ethers"; 5 | const logger = require('node-color-log'); 6 | 7 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 8 | const {deployments, getNamedAccounts, network} = hre; 9 | const {deploy} = deployments; 10 | const { deployer } = await getNamedAccounts(); 11 | let tx 12 | 13 | logger.color('blue').log("-------------------------------------------------") 14 | logger.color('blue').bold().log("Set relay globally...") 15 | 16 | const relay = await deployments.get("BitcoinRelay") 17 | 18 | // set relay in cc transfer router 19 | const ccTransferRouter = await deployments.get("CCTransferRouter") 20 | const ccTransferRouterFactory = await ethers.getContractFactory("CCTransferRouter") 21 | const ccTransferRouterInstance = await ccTransferRouterFactory.attach( 22 | ccTransferRouter.address 23 | ) 24 | 25 | const checkRelayInCCTransfer = await ccTransferRouterInstance.relay() 26 | 27 | if (checkRelayInCCTransfer != relay.address) { 28 | tx = await ccTransferRouterInstance.setRelay( 29 | relay.address 30 | ) 31 | tx.wait(1) 32 | console.log("set relay in CCtransfer router: ", tx.hash) 33 | } else { 34 | console.log("relay is already settled in CCtransfer router") 35 | } 36 | 37 | 38 | 39 | // set relay in cc burn router 40 | const ccBurnRouter = await deployments.get("CCBurnRouter") 41 | const ccBurnRouterFactory = await ethers.getContractFactory("CCBurnRouter") 42 | const ccBurnRouterInstance = await ccBurnRouterFactory.attach( 43 | ccBurnRouter.address 44 | ) 45 | 46 | const checkRelayInCCBurn = await ccBurnRouterInstance.relay() 47 | 48 | if (checkRelayInCCBurn != relay.address) { 49 | tx = await ccBurnRouterInstance.setRelay( 50 | relay.address 51 | ) 52 | tx.wait(1) 53 | console.log("set relay in CCburn router: ", tx.hash) 54 | } else { 55 | console.log("relay is already settled in CCburn router") 56 | } 57 | 58 | 59 | 60 | // set relay in cc exchange router 61 | const ccExchangeRouter = await deployments.get("CCExchangeRouter") 62 | const ccExchangeRouterFactory = await ethers.getContractFactory("CCExchangeRouter") 63 | const ccExchangeRouterInstance = await ccExchangeRouterFactory.attach( 64 | ccExchangeRouter.address 65 | ) 66 | 67 | const checkRelayInCCExchange = await ccExchangeRouterInstance.relay() 68 | 69 | if (checkRelayInCCExchange != relay.address) { 70 | tx = await ccExchangeRouterInstance.setRelay( 71 | relay.address 72 | ) 73 | tx.wait(1) 74 | console.log("set relay in CCexchange router: ", tx.hash) 75 | } else { 76 | console.log("relay is already settled in CCexchange router: ") 77 | } 78 | 79 | 80 | 81 | // set relay in instant router 82 | const instantRouter = await deployments.get("InstantRouter") 83 | const instantRouterFactory = await ethers.getContractFactory("InstantRouter") 84 | const instantRouterInstance = await instantRouterFactory.attach( 85 | instantRouter.address 86 | ) 87 | 88 | const checkRelayInInstantRouter = await instantRouterInstance.relay() 89 | 90 | if (checkRelayInInstantRouter != relay.address) { 91 | tx = await instantRouterInstance.setRelay( 92 | relay.address 93 | ) 94 | tx.wait(1) 95 | console.log("set relay in instant router: ", tx.hash) 96 | } else { 97 | console.log("relay is already settled in instant router") 98 | } 99 | 100 | 101 | }; 102 | 103 | export default func; 104 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 105 | -------------------------------------------------------------------------------- /contracts/oracle/interfaces/IPriceOracle.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.8.4; 3 | 4 | interface IPriceOracle { 5 | 6 | /// @notice Emits when new exchange router is added 7 | /// @param exchangeRouter Address of new exchange router 8 | /// @param exchangeConnector Address of exchange connector 9 | event ExchangeConnectorAdded(address indexed exchangeRouter, address indexed exchangeConnector); 10 | 11 | /// @notice Emits when an exchange router is removed 12 | /// @param exchangeRouter Address of removed exchange router 13 | event ExchangeConnectorRemoved(address indexed exchangeRouter); 14 | 15 | /// @notice Emits when a price proxy is set 16 | /// @param _token Address of the token 17 | /// @param _priceProxyAddress Address of price proxy contract 18 | event SetPriceProxy(address indexed _token, address indexed _priceProxyAddress); 19 | 20 | /// @notice Emits when changes made to acceptable delay 21 | event NewAcceptableDelay(uint oldAcceptableDelay, uint newAcceptableDelay); 22 | 23 | /// @notice Emits when changes made to oracle native token 24 | event NewOracleNativeToken(address indexed oldOracleNativeToken, address indexed newOracleNativeToken); 25 | 26 | // Read-only functions 27 | 28 | /// @notice Gives USD price proxy address for a token 29 | /// @param _token Address of the token 30 | /// @return Address of price proxy contract 31 | function ChainlinkPriceProxy(address _token) external view returns (address); 32 | 33 | /// @notice Gives exchange connector address for an exchange router 34 | /// @param _exchangeRouter Address of exchange router 35 | /// @return Address of exchange connector 36 | function exchangeConnector(address _exchangeRouter) external view returns (address); 37 | 38 | /// @notice Gives address of an exchange router from exchange routers list 39 | /// @param _index Index of exchange router 40 | /// @return Address of exchange router 41 | function exchangeRoutersList(uint _index) external view returns (address); 42 | 43 | function getExchangeRoutersListLength() external view returns (uint); 44 | 45 | function acceptableDelay() external view returns (uint); 46 | 47 | function oracleNativeToken() external view returns (address); 48 | 49 | function equivalentOutputAmountByAverage( 50 | uint _inputAmount, 51 | uint _inputDecimals, 52 | uint _outputDecimals, 53 | address _inputToken, 54 | address _outputToken 55 | ) external view returns (uint); 56 | 57 | function equivalentOutputAmount( 58 | uint _inputAmount, 59 | uint _inputDecimals, 60 | uint _outputDecimals, 61 | address _inputToken, 62 | address _outputToken 63 | ) external view returns (uint); 64 | 65 | function equivalentOutputAmountFromOracle( 66 | uint _inputAmount, 67 | uint _inputDecimals, 68 | uint _outputDecimals, 69 | address _inputToken, 70 | address _outputToken 71 | ) external view returns (uint); 72 | 73 | function equivalentOutputAmountFromExchange( 74 | address _exchangeRouter, 75 | uint _inputAmount, 76 | address _inputToken, 77 | address _outputToken 78 | ) external view returns (uint); 79 | 80 | // State-changing functions 81 | 82 | function addExchangeConnector(address _exchangeRouter, address _exchangeConnector) external; 83 | 84 | function removeExchangeConnector(uint _exchangeRouterIndex) external; 85 | 86 | function setPriceProxy(address _token, address _priceProxyAddress) external; 87 | 88 | function setAcceptableDelay(uint _acceptableDelay) external; 89 | 90 | function setOracleNativeToken(address _oracleNativeToken) external; 91 | } -------------------------------------------------------------------------------- /scripts/add-price-proxy-to-oracle/001_AddPriceProxies.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import config from 'config' 5 | const logger = require('node-color-log'); 6 | 7 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 8 | const {deployments, getNamedAccounts, network} = hre; 9 | const {deploy, log} = deployments; 10 | const { deployer } = await getNamedAccounts(); 11 | let tx 12 | 13 | logger.color('blue').log("-------------------------------------------------") 14 | logger.color('blue').bold().log("add price proxies to price oracle...") 15 | 16 | const priceOracle = await deployments.get("PriceOracle") 17 | const priceOracleFactory = await ethers.getContractFactory("PriceOracle") 18 | const priceOracleInstance = await priceOracleFactory.attach( 19 | priceOracle.address 20 | ) 21 | 22 | const wrappedMatic = config.get("wrapped_matic") 23 | const maticUSDOracle = config.get("chain_link_oracles.matic_usd"); 24 | 25 | const checkMaticUSDTx = await priceOracleInstance.ChainlinkPriceProxy( 26 | wrappedMatic 27 | ) 28 | 29 | if (checkMaticUSDTx != maticUSDOracle) { 30 | tx = await priceOracleInstance.setPriceProxy( 31 | wrappedMatic, 32 | maticUSDOracle 33 | ) 34 | tx.wait(1) 35 | console.log("set matic/usd in pricie oracle: ", tx.hash) 36 | } else { 37 | console.log("matic/usd is already settled in price oracle") 38 | } 39 | 40 | 41 | const oneAddress = "0x0000000000000000000000000000000000000001" 42 | const checkMaticUSDTx2 = await priceOracleInstance.ChainlinkPriceProxy( 43 | oneAddress 44 | ) 45 | 46 | if (checkMaticUSDTx2 != maticUSDOracle) { 47 | tx = await priceOracleInstance.setPriceProxy( 48 | oneAddress, 49 | maticUSDOracle 50 | ) 51 | tx.wait(1) 52 | console.log("set matic/usd in pricie oracle: ", tx.hash) 53 | } else { 54 | console.log("matic/usd (one_address) is already settled in pricie oracle: ") 55 | } 56 | 57 | 58 | 59 | const tBTC = await deployments.get("TeleBTC") 60 | const btcUSDOracle = config.get("chain_link_oracles.btc_usd"); 61 | 62 | const checkBitcoinUSDTx = await priceOracleInstance.ChainlinkPriceProxy( 63 | tBTC.address 64 | ) 65 | 66 | if (checkBitcoinUSDTx != btcUSDOracle) { 67 | tx = await priceOracleInstance.setPriceProxy( 68 | tBTC.address, 69 | btcUSDOracle 70 | ) 71 | tx.wait(1) 72 | console.log("set btc/usd in pricie oracle: ", tx.hash) 73 | } else { 74 | console.log("btc/usd is already settled in pricie oracle") 75 | } 76 | 77 | const usdt = config.get("usdt_token") 78 | const usdtUSDOracle = config.get("chain_link_oracles.usdt_usd"); 79 | 80 | const checkUsdtUSDTx = await priceOracleInstance.ChainlinkPriceProxy( 81 | usdt 82 | ) 83 | 84 | if (checkUsdtUSDTx != usdtUSDOracle) { 85 | tx = await priceOracleInstance.setPriceProxy( 86 | usdt, 87 | usdtUSDOracle 88 | ) 89 | tx.wait(1) 90 | console.log("set usdt/usd in pricie oracle: ", tx.hash) 91 | } else { 92 | console.log("usdt/usd is already settled in pricie oracle") 93 | } 94 | 95 | const usdc = config.get("usdc_token") 96 | const usdcUSDOracle = config.get("chain_link_oracles.usdc_usd"); 97 | 98 | const checkUsdcUSDTx = await priceOracleInstance.ChainlinkPriceProxy( 99 | usdc 100 | ) 101 | 102 | if (checkUsdcUSDTx != usdcUSDOracle) { 103 | tx = await priceOracleInstance.setPriceProxy( 104 | usdc, 105 | usdcUSDOracle 106 | ) 107 | tx.wait(1) 108 | console.log("set usdc/usd in pricie oracle: ", tx.hash) 109 | } else { 110 | console.log("usdc/usd is already settled in pricie oracle") 111 | } 112 | 113 | 114 | logger.color('blue').log("-------------------------------------------------") 115 | }; 116 | 117 | export default func; 118 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 119 | -------------------------------------------------------------------------------- /contracts/routers/interfaces/ICCTransferRouter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.8.4; 3 | 4 | interface ICCTransferRouter { 5 | 6 | // Structures 7 | 8 | /// @notice Structure for recording cross-chain transfer requests 9 | /// @param inputAmount Amount of locked BTC on source chain 10 | /// @param recipientAddress Address of transfer recipient 11 | /// @param fee Amount of fee that is paid to Teleporter (tx, relayer and teleporter fees) 12 | /// @param speed Speed of the request (normal or instant) 13 | /// @param isUsed Whether the tx is used or not 14 | struct ccTransferRequest { 15 | uint inputAmount; 16 | address recipientAddress; 17 | uint fee; 18 | uint256 speed; 19 | bool isUsed; 20 | } 21 | 22 | // Events 23 | 24 | /// @notice Emits when a cc transfer request gets done 25 | /// @param lockerLockingScript Locking script of the locker on bitcoin network 26 | /// @param lockerScriptType Script type of the locker locking script 27 | /// @param lockerTargetAddress Address of the locker on EVM based target chain 28 | /// @param user Address of teleBTC recipient 29 | /// @param inputAmount Amount of tokens that user locked on source chain 30 | /// @param receivedAmount Amount of tokens that user receives 31 | /// @param speed Speed of the request (normal or instant) 32 | /// @param teleporter Address of teleporter who submitted the request 33 | /// @param teleporterFee Amount of fee that is paid to Teleporter (tx, relayer and teleporter fees) 34 | /// @param relayFee Amount of fee that is paid to relay contract 35 | /// @param protocolFee Amount of fee that is paid to the protocol 36 | /// @param bitcoinTxId Address of teleporter who submitted the request 37 | event CCTransfer( 38 | bytes indexed lockerLockingScript, 39 | uint lockerScriptType, 40 | address lockerTargetAddress, 41 | address indexed user, 42 | uint inputAmount, 43 | uint receivedAmount, 44 | uint indexed speed, 45 | address teleporter, 46 | uint teleporterFee, 47 | uint relayFee, 48 | uint protocolFee, 49 | bytes32 bitcoinTxId 50 | ); 51 | 52 | /// @notice Emits when changes made to relay address 53 | event NewRelay ( 54 | address oldRelay, 55 | address newRelay 56 | ); 57 | 58 | /// @notice Emits when changes made to InstantRouter address 59 | event NewInstantRouter ( 60 | address oldInstantRouter, 61 | address newInstantRouter 62 | ); 63 | 64 | /// @notice Emits when changes made to Lockers address 65 | event NewLockers ( 66 | address oldLockers, 67 | address newLockers 68 | ); 69 | 70 | /// @notice Emits when changes made to TeleBTC address 71 | event NewTeleBTC ( 72 | address oldTeleBTC, 73 | address newTeleBTC 74 | ); 75 | 76 | /// @notice Emits when changes made to protocol percentage fee 77 | event NewProtocolPercentageFee ( 78 | uint oldProtocolPercentageFee, 79 | uint newProtocolPercentageFee 80 | ); 81 | 82 | /// @notice Emits when changes made to Treasury address 83 | event NewTreasury ( 84 | address oldTreasury, 85 | address newTreasury 86 | ); 87 | 88 | // Read-only functions 89 | 90 | function startingBlockNumber() external view returns (uint); 91 | 92 | function protocolPercentageFee() external view returns (uint); 93 | 94 | function chainId() external view returns (uint); 95 | 96 | function appId() external view returns (uint); 97 | 98 | function relay() external view returns (address); 99 | 100 | function instantRouter() external view returns (address); 101 | 102 | function lockers() external view returns (address); 103 | 104 | function teleBTC() external view returns (address); 105 | 106 | function treasury() external view returns (address); 107 | 108 | function isRequestUsed(bytes32 _txId) external view returns (bool); 109 | 110 | // State-changing functions 111 | 112 | function setRelay(address _relay) external; 113 | 114 | function setInstantRouter(address _instantRouter) external; 115 | 116 | function setLockers(address _lockers) external; 117 | 118 | function setTeleBTC(address _teleBTC) external; 119 | 120 | function setTreasury(address _treasury) external; 121 | 122 | function setProtocolPercentageFee(uint _protocolPercentageFee) external; 123 | 124 | function ccTransfer( 125 | // Bitcoin tx 126 | bytes4 _version, 127 | bytes memory _vin, 128 | bytes calldata _vout, 129 | bytes4 _locktime, 130 | // Bitcoin block number 131 | uint256 _blockNumber, 132 | // Merkle proof 133 | bytes calldata _intermediateNodes, 134 | uint _index, 135 | bytes calldata _lockerLockingScript 136 | ) external payable returns (bool); 137 | } -------------------------------------------------------------------------------- /contracts/uniswap/v2-periphery/libraries/UniswapV2Library.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.5.0; 3 | 4 | import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol'; 5 | import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol'; 6 | 7 | import "./SafeMath.sol"; 8 | 9 | library UniswapV2Library { 10 | using SafeMath for uint; 11 | 12 | // returns sorted token addresses, used to handle return values from pairs sorted in this order 13 | function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { 14 | require(tokenA != tokenB, 'UniswapV2Library: IDENTICAL_ADDRESSES'); 15 | (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); 16 | require(token0 != address(0), 'UniswapV2Library: ZERO_ADDRESS'); 17 | } 18 | 19 | // // calculates the CREATE2 address for a pair without making any external calls 20 | // function pairFor(address factory, address tokenA, address tokenB) internal pure returns (address pair) { 21 | // (address token0, address token1) = sortTokens(tokenA, tokenB); 22 | // pair = address(uint(keccak256(abi.encodePacked( 23 | // hex'ff', 24 | // factory, 25 | // keccak256(abi.encodePacked(token0, token1)), 26 | // hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' // init code hash 27 | // )))); 28 | // } 29 | 30 | // Added 31 | function pairFor(address factory, address tokenA, address tokenB) internal view returns (address pair) { 32 | pair = IUniswapV2Factory(factory).getPair(tokenA, tokenB); 33 | } 34 | 35 | // fetches and sorts the reserves for a pair 36 | function getReserves(address factory, address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) { 37 | (address token0,) = sortTokens(tokenA, tokenB); 38 | (uint reserve0, uint reserve1,) = IUniswapV2Pair(pairFor(factory, tokenA, tokenB)).getReserves(); 39 | (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0); 40 | } 41 | 42 | // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset 43 | function quote(uint amountA, uint reserveA, uint reserveB) internal pure returns (uint amountB) { 44 | require(amountA > 0, 'UniswapV2Library: INSUFFICIENT_AMOUNT'); 45 | require(reserveA > 0 && reserveB > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); 46 | amountB = amountA.mul(reserveB) / reserveA; 47 | } 48 | 49 | // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset 50 | function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) { 51 | require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT'); 52 | require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); 53 | uint amountInWithFee = amountIn.mul(997); 54 | uint numerator = amountInWithFee.mul(reserveOut); 55 | uint denominator = reserveIn.mul(1000).add(amountInWithFee); 56 | amountOut = numerator / denominator; 57 | } 58 | 59 | // given an output amount of an asset and pair reserves, returns a required input amount of the other asset 60 | function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) internal pure returns (uint amountIn) { 61 | require(amountOut > 0, 'UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT'); 62 | require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); 63 | uint numerator = reserveIn.mul(amountOut).mul(1000); 64 | uint denominator = reserveOut.sub(amountOut).mul(997); 65 | amountIn = (numerator / denominator).add(1); 66 | } 67 | 68 | // performs chained getAmountOut calculations on any number of pairs 69 | function getAmountsOut(address factory, uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) { 70 | require(path.length >= 2, 'UniswapV2Library: INVALID_PATH'); 71 | amounts = new uint[](path.length); 72 | amounts[0] = amountIn; 73 | for (uint i; i < path.length - 1; i++) { 74 | (uint reserveIn, uint reserveOut) = getReserves(factory, path[i], path[i + 1]); 75 | amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut); 76 | } 77 | } 78 | 79 | // performs chained getAmountIn calculations on any number of pairs 80 | function getAmountsIn(address factory, uint amountOut, address[] memory path) internal view returns (uint[] memory amounts) { 81 | require(path.length >= 2, 'UniswapV2Library: INVALID_PATH'); 82 | amounts = new uint[](path.length); 83 | amounts[amounts.length - 1] = amountOut; 84 | for (uint i = path.length - 1; i > 0; i--) { 85 | (uint reserveIn, uint reserveOut) = getReserves(factory, path[i - 1], path[i]); 86 | amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hardhat-project", 3 | "devDependencies": { 4 | "@commitlint/cli": "^17.4.4", 5 | "@commitlint/config-conventional": "^17.4.4", 6 | "@nomicfoundation/hardhat-chai-matchers": "^1.0.5", 7 | "@nomiclabs/hardhat-ethers": "^2.0.6", 8 | "@nomiclabs/hardhat-etherscan": "^3.0.4", 9 | "@nomiclabs/hardhat-waffle": "^2.0.3", 10 | "@typechain/ethers-v5": "^7.2.0", 11 | "@typechain/hardhat": "^2.3.1", 12 | "@types/chai": "^4.3.1", 13 | "@types/config": "^0.0.39", 14 | "@types/mocha": "^9.1.1", 15 | "@types/node": "^12.20.54", 16 | "@typescript-eslint/eslint-plugin": "^4.33.0", 17 | "@typescript-eslint/parser": "^4.33.0", 18 | "chai": "^4.3.6", 19 | "dotenv": "^16.0.1", 20 | "eslint": "^7.32.0", 21 | "eslint-config-prettier": "^8.5.0", 22 | "eslint-config-standard": "^16.0.3", 23 | "eslint-plugin-import": "^2.26.0", 24 | "eslint-plugin-node": "^11.1.0", 25 | "eslint-plugin-prettier": "^3.4.1", 26 | "eslint-plugin-promise": "^5.2.0", 27 | "ethereum-waffle": "^3.4.4", 28 | "ethers": "^5.6.8", 29 | "hardhat": "^2.9.9", 30 | "hardhat-contract-sizer": "^2.6.1", 31 | "hardhat-deploy": "^0.11.10", 32 | "hardhat-deploy-tenderly": "^0.1.1", 33 | "hardhat-gas-reporter": "^1.0.8", 34 | "husky": "^8.0.3", 35 | "prettier": "^2.6.2", 36 | "prettier-plugin-solidity": "^1.0.0-beta.19", 37 | "solhint": "^3.3.7", 38 | "solidity-coverage": "^0.7.21", 39 | "ts-node": "^10.8.1", 40 | "typechain": "^5.2.0", 41 | "typescript": "^4.7.3" 42 | }, 43 | "dependencies": { 44 | "@chainlink/contracts": "^0.4.2", 45 | "@liquality/bitcoin-rpc-provider": "^1.13.0", 46 | "@liquality/client": "^1.13.0", 47 | "@openzeppelin/contracts": "4.3.3", 48 | "@openzeppelin/contracts-upgradeable": "^4.7.3", 49 | "@openzeppelin/hardhat-upgrades": "1.12.0", 50 | "@remix-project/remixd": "^0.6.5", 51 | "@uniswap/v2-core": "^1.0.1", 52 | "base58check": "^2.0.0", 53 | "bech32-buffer": "^0.2.0", 54 | "bitcoin-address-validation": "^2.2.1", 55 | "bitcoin_rest_api": "^1.0.1", 56 | "bitcoind-rpc": "^0.9.1", 57 | "bitcoinjs-lib": "^6.0.1", 58 | "config": "^3.3.6", 59 | "deasync": "^0.1.23", 60 | "ecpair": "^2.0.1", 61 | "envkey": "^1.3.2", 62 | "js-sha256": "^0.9.0", 63 | "merkle-patricia-tree": "2.3.2", 64 | "merkletreejs": "^0.2.24", 65 | "node-color-log": "^10.0.2", 66 | "ripemd160-js": "^1.2.0", 67 | "sinon": "^14.0.0", 68 | "truffle-assertions": "^0.9.2", 69 | "truffle-contract-size": "^2.0.1", 70 | "ts-node": "^10.3.0" 71 | }, 72 | "scripts": { 73 | "build": "hardhat compile && tsc", 74 | "clean": "rimraf artifacts && rimraf cache && rimraf deployments/localhost && rimraf src/types/*", 75 | "deploy:local": "hardhat deploy --network hardhat --tags BitcoinMainnet --export export/abi/local.json", 76 | "deploy:bsc_testnet": "hardhat deploy --network bsc_testnet --export export/abi/bsc_testnet.json", 77 | "deploy:polygon": "NODE_ENV=polygon hardhat deploy --network polygon --export export/abi/polygon.json", 78 | "settlement:polygon": "NODE_ENV=polygon hardhat deploy --network polygon --export export/abi/polygon.json --deploy-scripts scripts/settlement-scripts", 79 | "lockers_settlement:polygon": "NODE_ENV=polygon hardhat deploy --network polygon --export export/abi/polygon.json --deploy-scripts scripts/locker-settlement-script", 80 | "update_lockers_logic:polygon": "NODE_ENV=polygon hardhat deploy --network polygon --export export/abi/polygon.json --deploy-scripts scripts/locker-logic-update-script", 81 | "global_variables_settlement:polygon": "NODE_ENV=polygon hardhat deploy --network polygon --export export/abi/polygon.json --deploy-scripts scripts/set-global-variables", 82 | "collateral_pool_scripts:polygon": "NODE_ENV=polygon hardhat deploy --network polygon --export export/abi/polygon.json --deploy-scripts scripts/collateralPool-script", 83 | "add_chainlink_to_price_oracle:polygon": "NODE_ENV=polygon hardhat deploy --network polygon --export export/abi/polygon.json --deploy-scripts scripts/add-price-proxy-to-oracle", 84 | "deploy:mumbai": "NODE_ENV=mumbai hardhat deploy --network mumbai --export export/abi/mumbai.json", 85 | "settlement:mumbai": "NODE_ENV=mumbai hardhat deploy --network mumbai --export export/abi/mumbai.json --deploy-scripts scripts/settlement-scripts", 86 | "lockers_settlement:mumbai": "NODE_ENV=mumbai hardhat deploy --network mumbai --export export/abi/mumbai.json --deploy-scripts scripts/locker-settlement-script", 87 | "update_lockers_logic:mumbai": "NODE_ENV=mumbai hardhat deploy --network mumbai --export export/abi/mumbai.json --deploy-scripts scripts/locker-logic-update-script", 88 | "global_variables_settlement:mumbai": "NODE_ENV=mumbai hardhat deploy --network mumbai --export export/abi/mumbai.json --deploy-scripts scripts/set-global-variables", 89 | "collateral_pool_scripts:mumbai": "NODE_ENV=mumbai hardhat deploy --network mumbai --export export/abi/mumbai.json --deploy-scripts scripts/collateralPool-script", 90 | "add_chainlink_to_price_oracle:mumbai": "NODE_ENV=mumbai hardhat deploy --network mumbai --export export/abi/mumbai.json --deploy-scripts scripts/add-price-proxy-to-oracle", 91 | "test": "hardhat test" 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /scripts/set-global-variables/003_SetTeleBTC.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import { BigNumber, BigNumberish } from "ethers"; 5 | const logger = require('node-color-log'); 6 | 7 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 8 | const {deployments, getNamedAccounts, network} = hre; 9 | const {deploy} = deployments; 10 | const { deployer } = await getNamedAccounts(); 11 | let tx 12 | 13 | logger.color('blue').log("-------------------------------------------------") 14 | logger.color('blue').bold().log("Set telebtc globally...") 15 | 16 | const telebtc = await deployments.get("TeleBTC") 17 | 18 | // set relay in cc transfer router 19 | const ccTransferRouter = await deployments.get("CCTransferRouter") 20 | const ccTransferRouterFactory = await ethers.getContractFactory("CCTransferRouter") 21 | const ccTransferRouterInstance = await ccTransferRouterFactory.attach( 22 | ccTransferRouter.address 23 | ) 24 | 25 | const checkTeleBTCInCCTransfer = await ccTransferRouterInstance.teleBTC() 26 | 27 | if (checkTeleBTCInCCTransfer != telebtc.address) { 28 | tx = await ccTransferRouterInstance.setTeleBTC( 29 | telebtc.address 30 | ) 31 | tx.wait(1) 32 | console.log("set teleBTC in CCtransfer router: ", tx.hash) 33 | } else { 34 | console.log("teleBTC is already settled in CCtransfer router") 35 | } 36 | 37 | 38 | 39 | // set relay in cc burn router 40 | const ccBurnRouter = await deployments.get("CCBurnRouter") 41 | const ccBurnRouterFactory = await ethers.getContractFactory("CCBurnRouter") 42 | const ccBurnRouterInstance = await ccBurnRouterFactory.attach( 43 | ccBurnRouter.address 44 | ) 45 | 46 | const checkTeleBTCInCCBurn = await ccBurnRouterInstance.teleBTC() 47 | 48 | if (checkTeleBTCInCCBurn != telebtc.address) { 49 | tx = await ccBurnRouterInstance.setTeleBTC( 50 | telebtc.address 51 | ) 52 | tx.wait(1) 53 | console.log("set telebtc in CCburn router: ", tx.hash) 54 | } else { 55 | console.log("telebtc is already settled in CCburn router") 56 | } 57 | 58 | // set telebtc in cc exchange router 59 | const ccExchangeRouter = await deployments.get("CCExchangeRouter") 60 | const ccExchangeRouterFactory = await ethers.getContractFactory("CCExchangeRouter") 61 | const ccExchangeRouterInstance = await ccExchangeRouterFactory.attach( 62 | ccExchangeRouter.address 63 | ) 64 | 65 | const checkTeleBTCInCCExchange = await ccExchangeRouterInstance.teleBTC() 66 | 67 | if (checkTeleBTCInCCExchange != telebtc.address) { 68 | tx = await ccExchangeRouterInstance.setTeleBTC( 69 | telebtc.address 70 | ) 71 | tx.wait(1) 72 | console.log("set telebtc in CCexchange router: ", tx.hash) 73 | } else { 74 | console.log("telebtc is already settled in CCexchange router") 75 | } 76 | 77 | 78 | // set telebtc in instant router 79 | const instantRouter = await deployments.get("InstantRouter") 80 | const instantRouterFactory = await ethers.getContractFactory("InstantRouter") 81 | const instantRouterInstance = await instantRouterFactory.attach( 82 | instantRouter.address 83 | ) 84 | 85 | const checkTeleBTCInInstantRouter = await instantRouterInstance.teleBTC() 86 | 87 | if (checkTeleBTCInInstantRouter != telebtc.address) { 88 | tx = await instantRouterInstance.setTeleBTC( 89 | telebtc.address 90 | ) 91 | tx.wait(1) 92 | console.log("set telebtc in instant router: ", tx.hash) 93 | } else { 94 | console.log("telebtc is already settled in instant router") 95 | } 96 | 97 | // set telebtc in instant pool 98 | const instantPool = await deployments.get("InstantPool") 99 | const instantPoolFactory = await ethers.getContractFactory("InstantPool") 100 | const instantPoolInstance = await instantPoolFactory.attach( 101 | instantPool.address 102 | ) 103 | 104 | const checkTeleBTCInInstantPool = await instantPoolInstance.teleBTC() 105 | 106 | if (checkTeleBTCInInstantPool != telebtc.address) { 107 | tx = await instantPoolInstance.setTeleBTC( 108 | telebtc.address 109 | ) 110 | tx.wait(1) 111 | console.log("set telebtc in instant pool: ", tx.hash) 112 | } else { 113 | console.log("telebtc is already settled in instant pool") 114 | } 115 | 116 | // set telebtc in locker 117 | // const lockers = await deployments.get("LockersProxy") 118 | // const lockersLib = await deployments.get("LockersLib") 119 | // const lockersFactory = await ethers.getContractFactory( 120 | // "LockersLogicTestnet", 121 | // { 122 | // libraries: { 123 | // LockersLib: lockersLib.address 124 | // } 125 | // } 126 | // ); 127 | // const lockersInstance = await lockersFactory.attach( 128 | // lockers.address 129 | // ) 130 | 131 | // tx = await lockersInstance.setTeleBTC( 132 | // telebtc.address 133 | // ) 134 | // tx.wait(1) 135 | // console.log("set telebtc in lockers: ", tx.hash) 136 | 137 | 138 | logger.color('blue').log("-------------------------------------------------") 139 | 140 | }; 141 | 142 | export default func; 143 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 144 | -------------------------------------------------------------------------------- /scripts/locker-settlement-script/001_SetTeleBTCInLocker.ts: -------------------------------------------------------------------------------- 1 | import {HardhatRuntimeEnvironment} from 'hardhat/types'; 2 | import {DeployFunction} from 'hardhat-deploy/types'; 3 | import { ethers } from "hardhat"; 4 | import { BigNumber, BigNumberish } from "ethers"; 5 | import config from 'config' 6 | const logger = require('node-color-log'); 7 | 8 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 9 | const {deployments, getNamedAccounts, network} = hre; 10 | const {deploy, log} = deployments; 11 | const { deployer } = await getNamedAccounts(); 12 | 13 | logger.color('blue').log("-------------------------------------------------") 14 | logger.color('blue').bold().log("Set teleBTC in Locker...") 15 | 16 | const one = BigNumber.from(10).pow(18).mul(1) 17 | 18 | const lockersLib = await deployments.get("LockersLib") 19 | const lockersProxy = await deployments.get("LockersProxy") 20 | 21 | const ccTransferRouter = await deployments.get("CCTransferRouter") 22 | const ccExchangeRouter = await deployments.get("CCExchangeRouter") 23 | const ccBurnRouter = await deployments.get("CCBurnRouter") 24 | 25 | const teleDAOToken = await deployments.get("ERC20") 26 | const teleBTC = await deployments.get("TeleBTC") 27 | const exchangeConnector = await deployments.get("UniswapV2Connector") 28 | const priceOracle = await deployments.get("PriceOracle") 29 | const minTDTLockedAmount = 0; 30 | 31 | const minNativeLockedAmount = config.get("lockers_contract.minimum_native_locked_amount"); 32 | const collateralRatio = config.get("lockers_contract.collateral_ratio"); 33 | const liquidationRatio = config.get("lockers_contract.liquidation_ratio"); 34 | const lockerPercentageFee = config.get("lockers_contract.locker_percentage_fee"); 35 | const priceWithDiscountRatio = config.get("lockers_contract.price_with_discount_ratio"); 36 | 37 | const lockersLogicFactory = await ethers.getContractFactory( 38 | "LockersLogic", 39 | { 40 | libraries: { 41 | LockersLib: lockersLib.address 42 | } 43 | } 44 | ); 45 | const lockersInstance = await lockersLogicFactory.attach( 46 | lockersProxy.address 47 | ); 48 | 49 | 50 | const teleDAOTokenAddress = await lockersInstance.TeleportDAOToken() 51 | 52 | if (teleDAOTokenAddress == "0x0000000000000000000000000000000000000000") { 53 | const initializeTx = await lockersInstance.initialize( 54 | teleBTC.address, 55 | teleDAOToken.address, 56 | exchangeConnector.address, 57 | priceOracle.address, 58 | ccBurnRouter.address, 59 | minTDTLockedAmount, 60 | minNativeLockedAmount, 61 | collateralRatio, 62 | liquidationRatio, 63 | lockerPercentageFee, 64 | priceWithDiscountRatio 65 | ) 66 | 67 | await initializeTx.wait(1) 68 | console.log("initialize locker: ", initializeTx.hash) 69 | } else { 70 | console.log("locker is already initialized") 71 | } 72 | 73 | const setTeleBTCTx = await lockersInstance.setTeleBTC( 74 | teleBTC.address 75 | ) 76 | 77 | await setTeleBTCTx.wait(1) 78 | console.log("set telebtc in locker: ", setTeleBTCTx.hash) 79 | 80 | 81 | const isCCTransferMinter = await lockersInstance.isMinter( 82 | ccTransferRouter.address 83 | ) 84 | 85 | if (!isCCTransferMinter) { 86 | const addCCTransferAsMinter = await lockersInstance.addMinter( 87 | ccTransferRouter.address 88 | ) 89 | 90 | await addCCTransferAsMinter.wait(1) 91 | console.log("add CC transfer router as minter: ", addCCTransferAsMinter.hash) 92 | } else { 93 | console.log("CC transfer router is already a minter") 94 | } 95 | 96 | const isCCExchangeMinter = await lockersInstance.isMinter( 97 | ccExchangeRouter.address 98 | ) 99 | 100 | if (!isCCExchangeMinter) { 101 | const addCCExchangeAsMinter = await lockersInstance.addMinter( 102 | ccExchangeRouter.address 103 | ) 104 | 105 | await addCCExchangeAsMinter.wait(1) 106 | console.log("add CC exchange router as minter: ", addCCExchangeAsMinter.hash) 107 | } else { 108 | console.log("CC exchange router is already a minter") 109 | } 110 | 111 | 112 | const isCCBurnerBurner = await lockersInstance.isBurner( 113 | ccBurnRouter.address 114 | ) 115 | 116 | if (!isCCBurnerBurner) { 117 | const addCCBurnerAsBurner = await lockersInstance.addBurner( 118 | ccBurnRouter.address 119 | ) 120 | 121 | await addCCBurnerAsBurner.wait(1) 122 | console.log("add CC burn router router as burner: ", addCCBurnerAsBurner.hash) 123 | } else { 124 | console.log("CC burn router router is already a burner: ") 125 | } 126 | 127 | 128 | // const ccBurnerRouterFromContract = await lockersInstance.ccBurnRouter() 129 | 130 | // if (ccBurnerRouterFromContract != ccBurnRouter.address) { 131 | // const addCCBurnRouter = await lockersInstance.setCCBurnRouter( 132 | // ccBurnRouter.address 133 | // ) 134 | 135 | // await addCCBurnRouter.wait(1) 136 | // console.log("add CC burn router in locker: ", addCCBurnRouter.hash) 137 | // } 138 | 139 | logger.color('blue').log("-------------------------------------------------") 140 | 141 | }; 142 | 143 | export default func; 144 | // func.tags = ["PriceOracle", "BitcoinTestnet"]; 145 | -------------------------------------------------------------------------------- /contracts/pools/CollateralPoolFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.8.4; 3 | 4 | import "./interfaces/ICollateralPoolFactory.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 6 | import "./CollateralPool.sol"; 7 | import "@openzeppelin/contracts/access/Ownable.sol"; 8 | import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; 9 | 10 | contract CollateralPoolFactory is ICollateralPoolFactory, Ownable, ReentrancyGuard { 11 | 12 | modifier nonZeroAddress(address _address) { 13 | require(_address != address(0), "CollateralPoolFactory: zero address"); 14 | _; 15 | } 16 | 17 | modifier nonZeroValue(uint _value) { 18 | require(_value > 0, "CollateralPoolFactory: zero value"); 19 | _; 20 | } 21 | 22 | // Public variables 23 | mapping(address => address) public override getCollateralPoolByToken; // collateral token => collateral pool 24 | address[] public override allCollateralPools; // List of all collateral pools 25 | 26 | /// @notice This contract creates collateral pool for tokens 27 | constructor() {} 28 | 29 | function renounceOwnership() public virtual override onlyOwner {} 30 | 31 | /// @return Total number of collateral pools 32 | function allCollateralPoolsLength() public override view returns (uint) { 33 | return allCollateralPools.length; 34 | } 35 | 36 | /// @notice Checks whether the token is accepted as collateral or not 37 | /// @param _collateralToken Address of collateral token 38 | /// @return True if the corresponding collateral pool exists 39 | function isCollateral(address _collateralToken) external override view returns (bool) { 40 | return getCollateralPoolByToken[_collateralToken] == address(0) ? false : true; 41 | } 42 | 43 | /// @notice Creates a new collateral pool 44 | /// @dev Only owner can call this 45 | /// @param _collateralToken Address of underlying collateral token 46 | /// @param _collateralizationRatio The ratio of over collateralization 47 | /// @return Address of newly created collateral pool 48 | function createCollateralPool( 49 | address _collateralToken, 50 | uint _collateralizationRatio 51 | ) external nonZeroAddress(_collateralToken) nonZeroValue(_collateralizationRatio) 52 | nonReentrant onlyOwner override returns (address) { 53 | // Checks that collateral pool for the token doesn't exist 54 | require( 55 | getCollateralPoolByToken[_collateralToken] == address(0), 56 | "CollateralPoolFactory: collateral pool already exists" 57 | ); 58 | 59 | require( 60 | _collateralizationRatio >= 10000, 61 | "CollateralPoolFactory: low amount" 62 | ); 63 | 64 | // Creates collateral pool 65 | CollateralPool pool; 66 | string memory name; 67 | string memory symbol; 68 | uint8 decimals; 69 | 70 | name = string(abi.encodePacked(ERC20(_collateralToken).name(), "-", "Collateral-Pool")); 71 | symbol = string(abi.encodePacked(ERC20(_collateralToken).symbol(), "CP")); 72 | decimals = ERC20(_collateralToken).decimals(); 73 | pool = new CollateralPool(name, symbol, _collateralToken, _collateralizationRatio, decimals); 74 | 75 | // Transfers ownership of collateral pool to owner of this contract 76 | CollateralPool(address(pool)).transferOwnership(_msgSender()); 77 | 78 | // Stores collateral pool address 79 | getCollateralPoolByToken[_collateralToken] = address(pool); 80 | allCollateralPools.push(address(pool)); 81 | emit CreateCollateralPool(name, _collateralToken, _collateralizationRatio, address(pool)); 82 | 83 | return address(pool); 84 | } 85 | 86 | /// @notice Removes an existing collateral pool 87 | /// @dev Only owner can call this 88 | /// @param _collateralToken Address of underlying collateral token 89 | /// @param _index Index of collateral pool in allCollateralPools 90 | /// @return True if collateral pool is removed successfully 91 | function removeCollateralPool( 92 | address _collateralToken, 93 | uint _index 94 | ) external nonReentrant nonZeroAddress(_collateralToken) onlyOwner override returns (bool) { 95 | // Checks that collateral pool exists 96 | address collateralPool = getCollateralPoolByToken[_collateralToken]; 97 | require(collateralPool != address(0), "CollateralPoolFactory: collateral pool does not exist"); 98 | 99 | // Removes collateral pool address 100 | require(_index < allCollateralPoolsLength(), "CollateralPoolFactory: index is out of range"); 101 | require(collateralPool == allCollateralPools[_index], "CollateralPoolFactory: index is not correct"); 102 | getCollateralPoolByToken[_collateralToken] = address(0); 103 | _removeElement(_index); 104 | emit RemoveCollateralPool(_collateralToken, collateralPool); 105 | 106 | return true; 107 | } 108 | 109 | /// @notice Removes an element of allCollateralPools 110 | /// @dev Deletes and shifts the array 111 | /// @param _index Index of the element that is deleted 112 | function _removeElement(uint _index) private { 113 | allCollateralPools[_index] = allCollateralPools[allCollateralPoolsLength() - 1]; 114 | allCollateralPools.pop(); 115 | } 116 | } -------------------------------------------------------------------------------- /contracts/libraries/RequestHelper.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.8.4; 3 | 4 | // A library for parsing cc transfer and cc exchange requests 5 | library RequestHelper { 6 | 7 | /// @notice Returns chain id of the request 8 | /// @dev Determines the chain that request belongs to 9 | /// @param _arbitraryData Data written in Bitcoin tx 10 | /// @return parsedValue The parsed value of chain id 11 | function parseChainId(bytes memory _arbitraryData) internal pure returns (uint8 parsedValue) { 12 | bytes memory slicedBytes = sliceBytes(_arbitraryData, 0, 0); 13 | assembly { 14 | parsedValue := mload(add(slicedBytes, 1)) 15 | } 16 | } 17 | 18 | /// @notice Returns app id of the request 19 | /// @dev Determines the app that request belongs to (e.g. cross-chain transfer app id is 0) 20 | /// @param _arbitraryData Data written in Bitcoin tx 21 | /// @return parsedValue The parsed value of app id 22 | function parseAppId(bytes memory _arbitraryData) internal pure returns (uint16 parsedValue) { 23 | bytes memory slicedBytes = sliceBytes(_arbitraryData, 1, 2); 24 | assembly { 25 | parsedValue := mload(add(slicedBytes, 2)) 26 | } 27 | } 28 | 29 | /// @notice Returns recipient address 30 | /// @dev Minted TeleBTC or exchanged tokens will be sent to this address 31 | /// @param _arbitraryData Data written in Bitcoin tx 32 | /// @return parsedValue The parsed value of recipient address 33 | function parseRecipientAddress(bytes memory _arbitraryData) internal pure returns (address parsedValue) { 34 | bytes memory slicedBytes = sliceBytes(_arbitraryData, 3, 22); 35 | assembly { 36 | parsedValue := mload(add(slicedBytes, 20)) 37 | } 38 | } 39 | 40 | /// @notice Returns percentage fee (from total minted TeleBTC) 41 | /// @dev This fee goes to Teleporter who submitted the request 42 | /// @param _arbitraryData Data written in Bitcoin tx 43 | /// @return parsedValue The parsed value of percentage fee 44 | function parsePercentageFee(bytes memory _arbitraryData) internal pure returns (uint16 parsedValue) { 45 | bytes memory slicedBytes = sliceBytes(_arbitraryData, 23, 24); 46 | assembly { 47 | parsedValue := mload(add(slicedBytes, 2)) 48 | } 49 | } 50 | 51 | /// @notice Returns speed of request 52 | /// @dev 0 for normal requests, 1 for instant requests 53 | /// Instant requests are used to pay back an instant loan 54 | /// @param _arbitraryData Data written in Bitcoin tx 55 | /// @return parsedValue The parsed value of speed parameter 56 | function parseSpeed(bytes memory _arbitraryData) internal pure returns (uint8 parsedValue) { 57 | bytes memory slicedBytes = sliceBytes(_arbitraryData, 25, 25); 58 | assembly { 59 | parsedValue := mload(add(slicedBytes, 1)) 60 | } 61 | } 62 | 63 | /// @notice Returns address of exchange token 64 | /// @dev Minted TeleBTC will be exchanged to this token 65 | /// @param _arbitraryData Data written in Bitcoin tx 66 | /// @return parsedValue The parsed value of exchange token 67 | function parseExchangeToken(bytes memory _arbitraryData) internal pure returns (address parsedValue){ 68 | bytes memory slicedBytes = sliceBytes(_arbitraryData, 26, 45); 69 | assembly { 70 | parsedValue := mload(add(slicedBytes, 20)) 71 | } 72 | } 73 | 74 | /// @notice Returns amount of output (exchange) token 75 | /// @dev If input token is fixed, outputAmount means the min expected output amount 76 | /// If output token is fixed, outputAmount is desired output amount 77 | /// @param _arbitraryData Data written in Bitcoin tx 78 | /// @return parsedValue The parsed value of exchange output amount 79 | function parseExchangeOutputAmount(bytes memory _arbitraryData) internal pure returns (uint224 parsedValue){ 80 | bytes memory slicedBytes = sliceBytes(_arbitraryData, 46, 73); 81 | assembly { 82 | parsedValue := mload(add(slicedBytes, 28)) 83 | } 84 | } 85 | 86 | /// @notice Returns deadline of executing exchange request 87 | /// @dev This value is compared to block.timestamp 88 | /// @param _arbitraryData Data written in Bitcoin tx 89 | /// @return parsedValue The parsed value of deadline 90 | function parseDeadline(bytes memory _arbitraryData) internal pure returns (uint32 parsedValue){ 91 | bytes memory slicedBytes = sliceBytes(_arbitraryData, 74, 77); 92 | assembly { 93 | parsedValue := mload(add(slicedBytes, 4)) 94 | } 95 | } 96 | 97 | /// @notice Returns true if input token is fixed 98 | /// @param _arbitraryData Data written in Bitcoin tx 99 | /// @return parsedValue The parsed value of is-fixed-token 100 | function parseIsFixedToken(bytes memory _arbitraryData) internal pure returns (uint8 parsedValue){ 101 | bytes memory slicedBytes = sliceBytes(_arbitraryData, 78, 78); 102 | assembly { 103 | parsedValue := mload(add(slicedBytes, 1)) 104 | } 105 | } 106 | 107 | /// @notice Returns a sliced bytes 108 | /// @param _data Data that is sliced 109 | /// @param _start Start index of slicing 110 | /// @param _end End index of slicing 111 | /// @return _result The result of slicing 112 | function sliceBytes( 113 | bytes memory _data, 114 | uint _start, 115 | uint _end 116 | ) internal pure returns (bytes memory _result) { 117 | bytes1 temp; 118 | for (uint i = _start; i < _end + 1; i++) { 119 | temp = _data[i]; 120 | _result = abi.encodePacked(_result, temp); 121 | } 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /contracts/erc20/TeleBTC.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.8.4; 3 | 4 | import "./interfaces/ITeleBTC.sol"; 5 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 6 | import "@openzeppelin/contracts/access/Ownable.sol"; 7 | import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; 8 | 9 | contract TeleBTC is ITeleBTC, ERC20, Ownable, ReentrancyGuard { 10 | 11 | modifier onlyMinter() { 12 | require(isMinter(_msgSender()), "TeleBTC: only minters can mint"); 13 | _; 14 | } 15 | 16 | modifier onlyBurner() { 17 | require(isBurner(_msgSender()), "TeleBTC: only burners can burn"); 18 | _; 19 | } 20 | 21 | modifier nonZeroValue(uint _value) { 22 | require(_value > 0, "TeleBTC: value is zero"); 23 | _; 24 | } 25 | 26 | // Public variables 27 | mapping(address => bool) public minters; 28 | mapping(address => bool) public burners; 29 | 30 | uint public maxMintLimit; // Maximum mint limit per epoch 31 | uint public lastMintLimit; // Current mint limit in last epoch, decrease by minting in an epoch 32 | uint public epochLength; // Number of blocks in every epoch 33 | uint public lastEpoch; // Epoch number of last mint transaction 34 | 35 | 36 | constructor( 37 | string memory _name, 38 | string memory _symbol 39 | ) ERC20(_name, _symbol) { 40 | maxMintLimit = 10 ** 8; 41 | lastMintLimit = 10 ** 8; 42 | epochLength = 2000; 43 | } 44 | 45 | function renounceOwnership() public virtual override onlyOwner {} 46 | 47 | function decimals() public view virtual override(ERC20, ITeleBTC) returns (uint8) { 48 | return 8; 49 | } 50 | 51 | /** 52 | * @dev change maximum mint limit per epoch. 53 | */ 54 | function setMaxMintLimit(uint _mintLimit) public override onlyOwner { 55 | emit NewMintLimit(maxMintLimit, _mintLimit); 56 | maxMintLimit = _mintLimit; 57 | } 58 | 59 | /** 60 | * @dev change blocks number per epoch. 61 | */ 62 | function setEpochLength(uint _length) public override onlyOwner nonZeroValue(_length) { 63 | emit NewEpochLength(epochLength, _length); 64 | epochLength = _length; 65 | } 66 | 67 | /** 68 | * @dev Check if an account is minter. 69 | * @return bool 70 | */ 71 | function isMinter(address account) internal view returns (bool) { 72 | require(account != address(0), "TeleBTC: account is the zero address"); 73 | return minters[account]; 74 | } 75 | 76 | /// @notice Check if an account is burner 77 | /// @param account The account which intended to be checked 78 | /// @return bool 79 | function isBurner(address account) internal view returns (bool) { 80 | require(account != address(0), "TeleBTC: account is the zero address"); 81 | return burners[account]; 82 | } 83 | 84 | /// @notice Adds a minter 85 | /// @dev Only owner can call this function 86 | /// @param account The account which intended to be added to minters 87 | function addMinter(address account) external override onlyOwner { 88 | require(!isMinter(account), "TeleBTC: account already has role"); 89 | minters[account] = true; 90 | emit MinterAdded(account); 91 | } 92 | 93 | /// @notice Removes a minter 94 | /// @dev Only owner can call this function 95 | /// @param account The account which intended to be removed from minters 96 | function removeMinter(address account) external override onlyOwner { 97 | require(isMinter(account), "TeleBTC: account does not have role"); 98 | minters[account] = false; 99 | emit MinterRemoved(account); 100 | } 101 | 102 | /// @notice Adds a burner 103 | /// @dev Only owner can call this function 104 | /// @param account The account which intended to be added to burners 105 | function addBurner(address account) external override onlyOwner { 106 | require(!isBurner(account), "TeleBTC: account already has role"); 107 | burners[account] = true; 108 | emit BurnerAdded(account); 109 | } 110 | 111 | /// @notice Removes a burner 112 | /// @dev Only owner can call this function 113 | /// @param account The account which intended to be removed from burners 114 | function removeBurner(address account) external override onlyOwner { 115 | require(isBurner(account), "TeleBTC: account does not have role"); 116 | burners[account] = false; 117 | emit BurnerRemoved(account); 118 | } 119 | 120 | /// @notice Burns TeleBTC tokens of msg.sender 121 | /// @dev Only burners can call this 122 | /// @param _amount Amount of burnt tokens 123 | function burn(uint _amount) external nonReentrant onlyBurner override returns (bool) { 124 | _burn(_msgSender(), _amount); 125 | emit Burn(_msgSender(), _msgSender(), _amount); 126 | return true; 127 | } 128 | 129 | /// @notice Mints TeleBTC tokens for _receiver 130 | /// @dev Only minters can call this 131 | /// @param _receiver Address of token's receiver 132 | /// @param _amount Amount of minted tokens 133 | function mint(address _receiver, uint _amount) external nonReentrant onlyMinter override returns (bool) { 134 | require(_amount <= maxMintLimit, "TeleBTC: mint amount is more than maximum mint limit"); 135 | require(checkAndReduceMintLimit(_amount), "TeleBTC: reached maximum mint limit"); 136 | 137 | _mint(_receiver, _amount); 138 | emit Mint(_msgSender(), _receiver, _amount); 139 | return true; 140 | } 141 | 142 | /// @notice Check if can mint new tokens and update mint limit 143 | /// @param _amount Desired mint amount 144 | function checkAndReduceMintLimit(uint _amount) private returns (bool) { 145 | uint currentEpoch = block.number / epochLength; 146 | 147 | if (currentEpoch == lastEpoch) { 148 | if (_amount > lastMintLimit) 149 | return false; 150 | lastMintLimit -= _amount; 151 | } else { 152 | lastEpoch = currentEpoch; 153 | lastMintLimit = maxMintLimit - _amount; 154 | } 155 | return true; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /test/test_fixtures/headersReorgAndRetarget.json: -------------------------------------------------------------------------------- 1 | { 2 | "orphan_437478": { 3 | "digest": "0x0000000000000000011da79d23e40a8360ed09d7f7e67e85e5fcf14377694df2", 4 | "digest_le": "0xf24d697743f1fce5857ee6f7d709ed60830ae4239da71d010000000000000000", 5 | "hex": "0x00000020e156ef206dc738dbe7b7bd449f90b65771292f146213fb000000000000000000c52c39a4e31158ff7c34417c9750038b27c9a94dc08210e53ba624667c9310973d161e5874510418a9f7e0d0", 6 | "height": 437478 7 | }, 8 | "oldPeriodStart": { 9 | "digest": "0x00000000000000000082ed5c599748dbaf59b084445c3f0c107fef194fe9009b", 10 | "digest_le": "0x9b00e94f19ef7f100c3f5c4484b059afdb4897595ced82000000000000000000", 11 | "hex": "0x00000020a32e8e27455216a02d4704b3a3c4731cf34117d468d97f020000000000000000948fa46542c2d31a37733dca03b2cc82ffadc067fd603479f64d773fcfc13801d2a90b58d25504183d4ee3b4", 12 | "height": 435456 13 | }, 14 | "genesis": { 15 | "digest": "0x00000000000000000073a63eb7045711d8b7d27f2a13948cd70a858980acd416", 16 | "digest_le": "0x16d4ac8089850ad78c94132a7fd2b7d8115704b73ea673000000000000000000", 17 | "hex": "0x00000020d0eb8cc9a5668ddabb83e6f657d940fd56902ceb039f200000000000000000005e407cf51ee81930145648d1e72c1caeafa6f6bfc4a7ec3988bcb7cf69a1594af3fe1d58d2550418e90ec632", 18 | "height": 437466 19 | }, 20 | "preRetargetChain": [ 21 | { 22 | "digest": "0x0000000000000000033c5bbb5aa43f276e3701168b7e43b40a41dd960101bc58", 23 | "digest_le": "0x58bc010196dd410ab4437e8b1601376e273fa45abb5b3c030000000000000000", 24 | "hex": "0x0000002016d4ac8089850ad78c94132a7fd2b7d8115704b73ea673000000000000000000993956e6dbdabd742e9078408e4a5a75e3760d18a24cc6b18e65b6bb3b15ed0f5b001e58d2550418183b1b41", 25 | "height": 437467 26 | }, 27 | { 28 | "digest": "0x0000000000000000039c463b6149a95a3ba6e0d39aa90755f56477bbd9711901", 29 | "digest_le": "0x011971d9bb7764f55507a99ad3e0a63b5aa949613b469c030000000000000000", 30 | "hex": "0x0000002058bc010196dd410ab4437e8b1601376e273fa45abb5b3c03000000000000000035092ae7558bab7b92b811bd07bd3a5a3c16a84e37a67e47817e813728f6f5e612011e58d255041805ebb671", 31 | "height": 437468 32 | }, 33 | { 34 | "digest": "0x0000000000000000020daace431ae4ab0509e877c069fb35d98a190af3df1473", 35 | "digest_le": "0x7314dff30a198ad935fb69c077e80905abe41a43ceaa0d020000000000000000", 36 | "hex": "0x00000020011971d9bb7764f55507a99ad3e0a63b5aa949613b469c030000000000000000ea0ac12b8c46d54d1eac6637b916ae7775aad858dc1c8a43cff50c40bb51a3bc2c081e58d255041859d608ec", 37 | "height": 437469 38 | }, 39 | { 40 | "digest": "0x000000000000000003f58f0d85e555bc292b518fa012a90c8b5e45d24993fff2", 41 | "digest_le": "0xf2ff9349d2455e8b0ca912a08f512b29bc55e5850d8ff5030000000000000000", 42 | "hex": "0x000000207314dff30a198ad935fb69c077e80905abe41a43ceaa0d020000000000000000d3439b160498d4464fcb6eee7ac75e801933067932f30234e3b924e2671e31a4e1091e58d25504188ccd158e", 43 | "height": 437470 44 | }, 45 | { 46 | "digest": "0x00000000000000000364a23184b8a2c009d13172094421c22e4d9bc85dcf90a5", 47 | "digest_le": "0xa590cf5dc89b4d2ec22144097231d109c0a2b88431a264030000000000000000", 48 | "hex": "0x00000020f2ff9349d2455e8b0ca912a08f512b29bc55e5850d8ff503000000000000000051aa623be08b19c2a6984e0c229bbffce20673675267eab5bf09a963b0547c673c0c1e58d25504183e20ab5b", 49 | "height": 437471 50 | } 51 | ], 52 | "postRetargetChain": [ 53 | { 54 | "digest": "0x000000000000000003c75c23f1444676c6832d45badd6ae89b8d1903d92563b7", 55 | "digest_le": "0xb76325d903198d9be86addba452d83c6764644f1235cc7030000000000000000", 56 | "hex": "0x00000020a590cf5dc89b4d2ec22144097231d109c0a2b88431a264030000000000000000a37e2d39aaf31d8bd7c00a07fa9784fee88ab361082f03601119dac4a0d87c8d020d1e58745104189b665b65", 57 | "height": 437472 58 | }, 59 | { 60 | "digest": "0x0000000000000000006084d9f6fb8b81349fcde72e85ab5e39e9d0b728f32b61", 61 | "digest_le": "0x612bf328b7d0e9395eab852ee7cd9f34818bfbf6d98460000000000000000000", 62 | "hex": "0x00000020b76325d903198d9be86addba452d83c6764644f1235cc70300000000000000001d9e6cc2b0871a8f88db857db870dfa7000f80f3c89c7a0eaaa925974fc392459e111e5874510418f4dcbaed", 63 | "height": 437473 64 | }, 65 | { 66 | "digest": "0x000000000000000003a15741d88dcbdab6c39b17dddf4829b6b8b509313bb14d", 67 | "digest_le": "0x4db13b3109b5b8b62948dfdd179bc3b6dacb8dd84157a1030000000000000000", 68 | "hex": "0x00000020612bf328b7d0e9395eab852ee7cd9f34818bfbf6d984600000000000000000001698022f9aeaccae63250f24ad66093504b088686d2e307bf7653c700b7e23d1e2111e5874510418914866a7", 69 | "height": 437474 70 | }, 71 | { 72 | "digest": "0x000000000000000000a024f601c50d9da8c3f09cc8feba477dd11370756fcda8", 73 | "digest_le": "0xa8cd6f757013d17d47bafec89cf0c3a89d0dc501f624a0000000000000000000", 74 | "hex": "0x000000204db13b3109b5b8b62948dfdd179bc3b6dacb8dd84157a10300000000000000005c93b3ce08ce22ba64fb26b8e75d695ac8c2bea0badd34200e698ccc73ca421b97121e58745104183ded0054", 75 | "height": 437475 76 | }, 77 | { 78 | "digest": "0x000000000000000003464978084011690021563526c9a5e2cbb17fbb76073adb", 79 | "digest_le": "0xdb3a0776bb7fb1cbe2a5c9263556210069114008784946030000000000000000", 80 | "hex": "0x00000020a8cd6f757013d17d47bafec89cf0c3a89d0dc501f624a00000000000000000004d7fd5d8c9984f2be03a80a75a4b6fe02dfda894181fcab0b6beb60698c7d6f0db121e587451041816e7fbbd", 81 | "height": 437476 82 | }, 83 | { 84 | "digest": "0x000000000000000000fb1362142f297157b6909f44bdb7e7db38c76d20ef56e1", 85 | "digest_le": "0xe156ef206dc738dbe7b7bd449f90b65771292f146213fb000000000000000000", 86 | "hex": "0x00000020db3a0776bb7fb1cbe2a5c9263556210069114008784946030000000000000000c8cbccf35d668296e8da72aed974983a8679e5077445b79d1e3e6c4d1bbff2c730161e58745104188674ac6f", 87 | "height": 437477 88 | }, 89 | { 90 | "digest": "0x0000000000000000013f1f231297f03c154bf918650793a786b3468ab9c339d3", 91 | "digest_le": "0xd339c3b98a46b386a793076518f94b153cf09712231f3f010000000000000000", 92 | "hex": "0x00000020e156ef206dc738dbe7b7bd449f90b65771292f146213fb000000000000000000f7e22ae2e5442bac43e18fc032dafd058fbdf886e33a3330e7597ce6eb4c073347161e58745104186cff9846", 93 | "height": 437478 94 | }, 95 | { 96 | "digest": "0x000000000000000003a243f554646535630675ac1fb5a922a5bacc4df24d77a0", 97 | "digest_le": "0xa0774df24dccbaa522a9b51fac75066335656454f543a2030000000000000000", 98 | "hex": "0x00000020d339c3b98a46b386a793076518f94b153cf09712231f3f01000000000000000018f078c9c73734d892fef90854381524f30017370d12dfa8319313c5729dbf85b8191e58745104187d43c005", 99 | "height": 437479 100 | } 101 | ] 102 | } 103 | -------------------------------------------------------------------------------- /contracts/routers/interfaces/ICCExchangeRouter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.8.4; 3 | 4 | interface ICCExchangeRouter { 5 | // Structures 6 | 7 | /// @notice Structure for recording cross-chain exchange requests 8 | /// @param appId Application id that user wants to use (defines the exchange that user wants to use) 9 | /// @param inputAmount Amount of locked BTC on source chain 10 | /// @param outputAmount Amount of output token 11 | /// @param isFixedToken True if amount of input token is fixed 12 | /// @param recipientAddress Address of exchange recipient 13 | /// @param fee Amount of fee that is paid to Teleporter (tx, relayer and teleporter fees) 14 | /// @param isUsed Whether the tx is used or not 15 | /// @param path Path from input token to output token 16 | /// @param deadline Deadline of exchanging tokens 17 | /// @param speed Speed of the request (normal or instant) 18 | struct ccExchangeRequest { 19 | uint appId; 20 | uint inputAmount; 21 | uint outputAmount; 22 | bool isFixedToken; 23 | address recipientAddress; 24 | uint fee; 25 | bool isUsed; 26 | address[] path; 27 | uint deadline; 28 | uint speed; 29 | } 30 | 31 | // Events 32 | 33 | /// @notice Emits when a cc exchange request gets done 34 | /// @param user Exchange recipient address 35 | /// @param speed Speed of the request (normal or instant) 36 | /// @param teleporter Address of teleporter who submitted the request 37 | /// @param teleporterFee Amount of fee that is paid to Teleporter (tx, relayer and teleporter fees) 38 | event CCExchange( 39 | bytes lockerLockingScript, 40 | uint lockerScriptType, 41 | address lockerTargetAddress, 42 | address indexed user, 43 | address[2] inputAndOutputToken, 44 | uint[2] inputAndOutputAmount, 45 | uint indexed speed, 46 | address indexed teleporter, 47 | uint teleporterFee, 48 | bytes32 bitcoinTxId, 49 | uint appId 50 | ); 51 | 52 | /// @notice Emits when a cc exchange request fails 53 | /// @dev In this case, instead of excahnging tokens, 54 | /// we mint teleBTC and send it to the user 55 | /// @param recipientAddress Exchange recipient address 56 | /// @param speed Speed of the request (normal or instant) 57 | /// @param teleporter Address of teleporter who submitted the request 58 | /// @param teleporterFee Amount of fee that is paid to Teleporter (tx, relayer and teleporter fees) 59 | event FailedCCExchange( 60 | bytes lockerLockingScript, 61 | uint lockerScriptType, 62 | address lockerTargetAddress, 63 | address indexed recipientAddress, 64 | address[2] inputAndOutputToken, 65 | uint[2] inputAndOutputAmount, 66 | uint indexed speed, 67 | address indexed teleporter, 68 | uint teleporterFee, 69 | bytes32 bitcoinTxId, 70 | uint appId 71 | ); 72 | 73 | /// @notice Emits when appId for an exchange connector is set 74 | /// @param appId Assigned application id to exchange 75 | /// @param exchangeConnector Address of exchange connector contract 76 | event SetExchangeConnector( 77 | uint appId, 78 | address exchangeConnector 79 | ); 80 | 81 | /// @notice Emits when changes made to relay address 82 | event NewRelay ( 83 | address oldRelay, 84 | address newRelay 85 | ); 86 | 87 | /// @notice Emits when changes made to InstantRouter address 88 | event NewInstantRouter ( 89 | address oldInstantRouter, 90 | address newInstantRouter 91 | ); 92 | 93 | /// @notice Emits when changes made to Lockers address 94 | event NewLockers ( 95 | address oldLockers, 96 | address newLockers 97 | ); 98 | 99 | /// @notice Emits when changes made to TeleBTC address 100 | event NewTeleBTC ( 101 | address oldTeleBTC, 102 | address newTeleBTC 103 | ); 104 | 105 | /// @notice Emits when changes made to protocol percentage fee 106 | event NewProtocolPercentageFee ( 107 | uint oldProtocolPercentageFee, 108 | uint newProtocolPercentageFee 109 | ); 110 | 111 | /// @notice Emits when changes made to Treasury address 112 | event NewTreasury ( 113 | address oldTreasury, 114 | address newTreasury 115 | ); 116 | 117 | // Read-only functions 118 | 119 | function startingBlockNumber() external view returns (uint); 120 | 121 | function protocolPercentageFee() external view returns (uint); 122 | 123 | function chainId() external view returns (uint); 124 | 125 | function relay() external view returns (address); 126 | 127 | function instantRouter() external view returns (address); 128 | 129 | function lockers() external view returns (address); 130 | 131 | function teleBTC() external view returns (address); 132 | 133 | function isRequestUsed(bytes32 _txId) external view returns (bool); 134 | 135 | function exchangeConnector(uint appId) external view returns (address); 136 | 137 | function treasury() external view returns (address); 138 | 139 | // State-changing functions 140 | 141 | function setRelay(address _relay) external; 142 | 143 | function setInstantRouter(address _instantRouter) external; 144 | 145 | function setLockers(address _lockers) external; 146 | 147 | function setTeleBTC(address _teleBTC) external; 148 | 149 | function setExchangeConnector(uint _appId, address _exchangeConnector) external; 150 | 151 | function setTreasury(address _treasury) external; 152 | 153 | function setProtocolPercentageFee(uint _protocolPercentageFee) external; 154 | 155 | function ccExchange( 156 | // Bitcoin tx 157 | bytes4 _version, 158 | bytes memory _vin, 159 | bytes calldata _vout, 160 | bytes4 _locktime, 161 | // Bitcoin block number 162 | uint256 _blockNumber, 163 | // Merkle proof 164 | bytes calldata _intermediateNodes, 165 | uint _index, 166 | bytes calldata _lockerLockingScript 167 | ) external payable returns(bool); 168 | } -------------------------------------------------------------------------------- /contracts/relay/interfaces/IBitcoinRelay.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.0 <0.8.4; 3 | 4 | interface IBitcoinRelay { 5 | // Structures 6 | 7 | /// @notice Structure for recording block header 8 | /// @param selfHash Hash of block header 9 | /// @param parentHash Hash of parent block header 10 | /// @param merkleRoot Merkle root of transactions in the block 11 | /// @param relayer Address of relayer who submitted the block header 12 | /// @param gasPrice Gas price of tx that relayer submitted the block header 13 | struct blockHeader { 14 | bytes32 selfHash; 15 | bytes32 parentHash; 16 | bytes32 merkleRoot; 17 | address relayer; 18 | uint gasPrice; 19 | } 20 | 21 | // Events 22 | 23 | /// @notice Emits when a block header is added 24 | /// @param height Height of submitted header 25 | /// @param selfHash Hash of submitted header 26 | /// @param parentHash Parent hash of submitted header 27 | /// @param relayer Address of relayer who submitted the block header 28 | event BlockAdded( 29 | uint indexed height, 30 | bytes32 selfHash, 31 | bytes32 indexed parentHash, 32 | address indexed relayer 33 | ); 34 | 35 | /// @notice Emits when a block header gets finalized 36 | /// @param height Height of the header 37 | /// @param selfHash Hash of the header 38 | /// @param parentHash Parent hash of the header 39 | /// @param relayer Address of relayer who submitted the block header 40 | /// @param rewardAmountTNT Amount of reward that the relayer receives in target native token 41 | /// @param rewardAmountTDT Amount of reward that the relayer receives in TDT 42 | event BlockFinalized( 43 | uint indexed height, 44 | bytes32 selfHash, 45 | bytes32 parentHash, 46 | address indexed relayer, 47 | uint rewardAmountTNT, 48 | uint rewardAmountTDT 49 | ); 50 | 51 | 52 | /// @notice Emits when changes made to reward amount in TDT 53 | event NewRewardAmountInTDT ( 54 | uint oldRewardAmountInTDT, 55 | uint newRewardAmountInTDT 56 | ); 57 | 58 | /// @notice Emits when changes made to finalization parameter 59 | event NewFinalizationParameter ( 60 | uint oldFinalizationParameter, 61 | uint newFinalizationParameter 62 | ); 63 | 64 | /// @notice Emits when changes made to relayer percentage fee 65 | event NewRelayerPercentageFee ( 66 | uint oldRelayerPercentageFee, 67 | uint newRelayerPercentageFee 68 | ); 69 | 70 | /// @notice Emits when changes made to teleportDAO token 71 | event NewTeleportDAOToken ( 72 | address oldTeleportDAOToken, 73 | address newTeleportDAOToken 74 | ); 75 | 76 | /// @notice Emits when changes made to epoch length 77 | event NewEpochLength( 78 | uint oldEpochLength, 79 | uint newEpochLength 80 | ); 81 | 82 | /// @notice Emits when changes made to base queries 83 | event NewBaseQueries( 84 | uint oldBaseQueries, 85 | uint newBaseQueries 86 | ); 87 | 88 | /// @notice Emits when changes made to submission gas used 89 | event NewSubmissionGasUsed( 90 | uint oldSubmissionGasUsed, 91 | uint newSubmissionGasUsed 92 | ); 93 | 94 | // Read-only functions 95 | 96 | function relayGenesisHash() external view returns (bytes32); 97 | 98 | function initialHeight() external view returns(uint); 99 | 100 | function lastSubmittedHeight() external view returns(uint); 101 | 102 | function finalizationParameter() external view returns(uint); 103 | 104 | function TeleportDAOToken() external view returns(address); 105 | 106 | function relayerPercentageFee() external view returns(uint); 107 | 108 | function epochLength() external view returns(uint); 109 | 110 | function lastEpochQueries() external view returns(uint); 111 | 112 | function currentEpochQueries() external view returns(uint); 113 | 114 | function baseQueries() external view returns(uint); 115 | 116 | function submissionGasUsed() external view returns(uint); 117 | 118 | function getBlockHeaderHash(uint height, uint index) external view returns(bytes32); 119 | 120 | function getBlockHeaderFee(uint _height, uint _index) external view returns(uint); 121 | 122 | function getNumberOfSubmittedHeaders(uint height) external view returns (uint); 123 | 124 | function availableTDT() external view returns(uint); 125 | 126 | function availableTNT() external view returns(uint); 127 | 128 | function findHeight(bytes32 _hash) external view returns (uint256); 129 | 130 | function findAncestor(bytes32 _hash, uint256 _offset) external view returns (bytes32); 131 | 132 | function isAncestor(bytes32 _ancestor, bytes32 _descendant, uint256 _limit) external view returns (bool); 133 | 134 | function rewardAmountInTDT() external view returns (uint); 135 | 136 | // State-changing functions 137 | 138 | function pauseRelay() external; 139 | 140 | function unpauseRelay() external; 141 | 142 | function setRewardAmountInTDT(uint _rewardAmountInTDT) external; 143 | 144 | function setFinalizationParameter(uint _finalizationParameter) external; 145 | 146 | function setRelayerPercentageFee(uint _relayerPercentageFee) external; 147 | 148 | function setTeleportDAOToken(address _TeleportDAOToken) external; 149 | 150 | function setEpochLength(uint _epochLength) external; 151 | 152 | function setBaseQueries(uint _baseQueries) external; 153 | 154 | function setSubmissionGasUsed(uint _submissionGasUsed) external; 155 | 156 | function checkTxProof( 157 | bytes32 txid, 158 | uint blockHeight, 159 | bytes calldata intermediateNodes, 160 | uint index 161 | ) external payable returns (bool); 162 | 163 | function addHeaders(bytes calldata _anchor, bytes calldata _headers) external returns (bool); 164 | 165 | function addHeadersWithRetarget( 166 | bytes calldata _oldPeriodStartHeader, 167 | bytes calldata _oldPeriodEndHeader, 168 | bytes calldata _headers 169 | ) external returns (bool); 170 | 171 | function ownerAddHeaders(bytes calldata _anchor, bytes calldata _headers) external returns (bool); 172 | 173 | function ownerAddHeadersWithRetarget( 174 | bytes calldata _oldPeriodStartHeader, 175 | bytes calldata _oldPeriodEndHeader, 176 | bytes calldata _headers 177 | ) external returns (bool); 178 | } -------------------------------------------------------------------------------- /test/test_fixtures/ccTransferRequests.json: -------------------------------------------------------------------------------- 1 | { 2 | "normalCCTransfer": { 3 | "txId": "0x1130749bc5d0ff46388cfdaf0b27cb24938dbbc1c25165dd852594139aeb102c", 4 | "version": "0x02000000", 5 | "vin": "0x0168cc0ef5ffb948080a79d85b5ffda89092921e2d776f7eb864cbbbea4271e2a90200000000feffffff", 6 | "vout": "0x03102700000000000017a9144062c8aeed4f81c2d73ff854a2957021191e20b68700000000000000001c6a1a01000082492cAFDD0BA0F68dec07Da75C28Fdb9d07447d006400533b0000000000001600140c92227de5c4bbe76247335b078cf2de137285db", 7 | "opReturn": "01000082492cAFDD0BA0F68dec07Da75C28Fdb9d07447d006400", 8 | "locktime": "0x00000000", 9 | "blockNumber": 497, 10 | "intermediateNodes": "0x545d893c5311b44ea319e27e53d9d7d2725882cb194a782be75c4da6c71ce0f8", 11 | "index": 1, 12 | "bitcoinAmount": 10000, 13 | "recipientAddress":"0x82492cAFDD0BA0F68dec07Da75C28Fdb9d07447d", 14 | "teleporterFee": 100, 15 | "speed": 0, 16 | "desiredRecipient": "0x4062c8aeed4f81c2d73ff854a2957021191e20b6" 17 | }, 18 | "normalCCTransfer_zeroFee": { 19 | "txId": "0x62286179273c5ee1718cea9f2632b820f810195aa03fb6af321ba5b643d8206d", 20 | "version": "0x02000000", 21 | "vin": "0x0168cc0ef5ffb948080a79d85b5ffda89092921e2d776f7eb864cbbbea4271e2a90200000000feffffff", 22 | "vout": "0x03102700000000000017a9144062c8aeed4f81c2d73ff854a2957021191e20b68700000000000000001c6a1a01000082492cAFDD0BA0F68dec07Da75C28Fdb9d07447d000000533b0000000000001600140c92227de5c4bbe76247335b078cf2de137285db", 23 | "opReturn": "01000082492cAFDD0BA0F68dec07Da75C28Fdb9d07447d000000", 24 | "locktime": "0x00000000", 25 | "blockNumber": 497, 26 | "intermediateNodes": "0x545d893c5311b44ea319e27e53d9d7d2725882cb194a782be75c4da6c71ce0f8", 27 | "index": 1, 28 | "bitcoinAmount": 10000, 29 | "recipientAddress":"0x82492cAFDD0BA0F68dec07Da75C28Fdb9d07447d", 30 | "teleporterFee": 0, 31 | "speed": 0, 32 | "desiredRecipient": "0x4062c8aeed4f81c2d73ff854a2957021191e20b6" 33 | }, 34 | "normalCCTransfer_invalidFee": { 35 | "txId": "0xf1ae8a09ca38078b2881a9ea5991441d9d71e10b72c4cd2f461d5269a615d4b9", 36 | "version": "0x02000000", 37 | "vin": "0x0168cc0ef5ffb948080a79d85b5ffda89092921e2d776f7eb864cbbbea4271e2a90200000000feffffff", 38 | "vout": "0x03102700000000000017a9144062c8aeed4f81c2d73ff854a2957021191e20b68700000000000000001c6a1a01000082492cAFDD0BA0F68dec07Da75C28Fdb9d07447dffff00533b0000000000001600140c92227de5c4bbe76247335b078cf2de137285db", 39 | "opReturn": "01000082492cAFDD0BA0F68dec07Da75C28Fdb9d07447dffff00", 40 | "locktime": "0x00000000", 41 | "blockNumber": 497, 42 | "intermediateNodes": "0x545d893c5311b44ea319e27e53d9d7d2725882cb194a782be75c4da6c71ce0f8", 43 | "index": 1, 44 | "bitcoinAmount": 10000, 45 | "recipientAddress":"0x82492cAFDD0BA0F68dec07Da75C28Fdb9d07447d", 46 | "teleporterFee": 65535, 47 | "speed": 0, 48 | "desiredRecipient": "0x4062c8aeed4f81c2d73ff854a2957021191e20b6" 49 | }, 50 | "normalCCTransfer_invalidAppId": { 51 | "txId": "0xf1ae8a09ca38078b2881a9ea5991441d9d71e10b72c4cd2f461d5269a615d4b9", 52 | "version": "0x02000000", 53 | "vin": "0x0168cc0ef5ffb948080a79d85b5ffda89092921e2d776f7eb864cbbbea4271e2a90200000000feffffff", 54 | "vout": "0x03102700000000000017a9144062c8aeed4f81c2d73ff854a2957021191e20b68700000000000000001c6a1a01ffff82492cAFDD0BA0F68dec07Da75C28Fdb9d07447d006400533b0000000000001600140c92227de5c4bbe76247335b078cf2de137285db", 55 | "opReturn": "01ffff82492cAFDD0BA0F68dec07Da75C28Fdb9d07447d006400", 56 | "locktime": "0x00000000", 57 | "blockNumber": 497, 58 | "intermediateNodes": "0x545d893c5311b44ea319e27e53d9d7d2725882cb194a782be75c4da6c71ce0f8", 59 | "index": 1, 60 | "bitcoinAmount": 10000, 61 | "appId": 65535, 62 | "recipientAddress":"0x82492cAFDD0BA0F68dec07Da75C28Fdb9d07447d", 63 | "teleporterFee": 100, 64 | "speed": 0, 65 | "desiredRecipient": "0x4062c8aeed4f81c2d73ff854a2957021191e20b6" 66 | }, 67 | "normalCCTransfer_invalidChainId": { 68 | "txId": "0xf1ae8a09ca38078b2881a9ea5991441d9d71e10b72c4cd2f461d5269a615d4b9", 69 | "version": "0x02000000", 70 | "vin": "0x0168cc0ef5ffb948080a79d85b5ffda89092921e2d776f7eb864cbbbea4271e2a90200000000feffffff", 71 | "vout": "0x03102700000000000017a9144062c8aeed4f81c2d73ff854a2957021191e20b68700000000000000001c6a1aff000082492cAFDD0BA0F68dec07Da75C28Fdb9d07447d006400533b0000000000001600140c92227de5c4bbe76247335b078cf2de137285db", 72 | "opReturn": "11000082492cAFDD0BA0F68dec07Da75C28Fdb9d07447d006400", 73 | "locktime": "0x00000000", 74 | "blockNumber": 497, 75 | "intermediateNodes": "0x545d893c5311b44ea319e27e53d9d7d2725882cb194a782be75c4da6c71ce0f8", 76 | "index": 1, 77 | "bitcoinAmount": 10000, 78 | "chainId": 255, 79 | "recipientAddress":"0x82492cAFDD0BA0F68dec07Da75C28Fdb9d07447d", 80 | "teleporterFee": 100, 81 | "speed": 0, 82 | "desiredRecipient": "0x4062c8aeed4f81c2d73ff854a2957021191e20b6" 83 | }, 84 | "normalCCTransfer_invalidSpeed": { 85 | "txId": "0xf1ae8a09ca38078b2881a9ea5991441d9d71e10b72c4cd2f461d5269a615d4b9", 86 | "version": "0x02000000", 87 | "vin": "0x0168cc0ef5ffb948080a79d85b5ffda89092921e2d776f7eb864cbbbea4271e2a90200000000feffffff", 88 | "vout": "0x03102700000000000017a9144062c8aeed4f81c2d73ff854a2957021191e20b68700000000000000001c6a1a01000082492cAFDD0BA0F68dec07Da75C28Fdb9d07447d006411533b0000000000001600140c92227de5c4bbe76247335b078cf2de137285db", 89 | "opReturn": "01000082492cAFDD0BA0F68dec07Da75C28Fdb9d07447d006400", 90 | "locktime": "0x00000000", 91 | "blockNumber": 497, 92 | "intermediateNodes": "0x545d893c5311b44ea319e27e53d9d7d2725882cb194a782be75c4da6c71ce0f8", 93 | "index": 1, 94 | "bitcoinAmount": 10000, 95 | "recipientAddress":"0x82492cAFDD0BA0F68dec07Da75C28Fdb9d07447d", 96 | "teleporterFee": 100, 97 | "speed": 17, 98 | "desiredRecipient": "0x4062c8aeed4f81c2d73ff854a2957021191e20b6" 99 | }, 100 | "normalCCTransfer_invalidLocker": { 101 | "txId": "0xf1ae8a09ca38078b2881a9ea5991441d9d71e10b72c4cd2f461d5269a615d4b9", 102 | "version": "0x02000000", 103 | "vin": "0x0168cc0ef5ffb948080a79d85b5ffda89092921e2d776f7eb864cbbbea4271e2a90200000000feffffff", 104 | "vout": "0x03102700000000000017a9144062c8aeed4f81c2d73ff854a2957021191e20b58700000000000000001c6a1a01000082492cAFDD0BA0F68dec07Da75C28Fdb9d07447d006400533b0000000000001600140c92227de5c4bbe76247335b078cf2de137285db", 105 | "opReturn": "01000082492cAFDD0BA0F68dec07Da75C28Fdb9d07447d006400", 106 | "locktime": "0x00000000", 107 | "blockNumber": 497, 108 | "intermediateNodes": "0x545d893c5311b44ea319e27e53d9d7d2725882cb194a782be75c4da6c71ce0f8", 109 | "index": 1, 110 | "bitcoinAmount": 10000, 111 | "recipientAddress":"0x82492cAFDD0BA0F68dec07Da75C28Fdb9d07447d", 112 | "teleporterFee": 100, 113 | "speed": 0, 114 | "desiredRecipient": "0x4062c8aeed4f81c2d73ff854a2957021191e20b5" 115 | }, 116 | "instantCCTransfer": { 117 | "txId": "0xc53aab7159a8dc218f57e5a744eea6c02b7ea30f5942903577c4e0925b3a9647", 118 | "version": "0x02000000", 119 | "vin": "0x0168cc0ef5ffb948080a79d85b5ffda89092921e2d776f7eb864cbbbea4271e2a90200000000feffffff", 120 | "vout": "0x03102700000000000017a9144062c8aeed4f81c2d73ff854a2957021191e20b68700000000000000001c6a1a01000082492cAFDD0BA0F68dec07Da75C28Fdb9d07447d006401533b0000000000001600140c92227de5c4bbe76247335b078cf2de137285db", 121 | "opReturn": "01000082492cAFDD0BA0F68dec07Da75C28Fdb9d07447d006401", 122 | "locktime": "0x00000000", 123 | "blockNumber": 497, 124 | "intermediateNodes": "0x545d893c5311b44ea319e27e53d9d7d2725882cb194a782be75c4da6c71ce0f8", 125 | "index": 1, 126 | "bitcoinAmount": 10000, 127 | "recipientAddress":"0x82492cAFDD0BA0F68dec07Da75C28Fdb9d07447d", 128 | "teleporterFee": 1, 129 | "speed": 1, 130 | "desiredRecipient": "0x4062c8aeed4f81c2d73ff854a2957021191e20b6" 131 | } 132 | } 133 | --------------------------------------------------------------------------------