Skip to content

Commit

Permalink
Merge pull request #19 from lombard-finance/feat/updates
Browse files Browse the repository at this point in the history
Feat/updates
  • Loading branch information
hashxtree authored Oct 5, 2024
2 parents bf0ba85 + 1bf6d1b commit db10466
Show file tree
Hide file tree
Showing 21 changed files with 518 additions and 297 deletions.
9 changes: 5 additions & 4 deletions addresses-gastald.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
},
"btcTestnet": {
"ThresholdKey": "0x91E5e2EFfFaB72e4368077F3B55f27fc95aeA8A5",
"LBTC": "0xD3f28A002EBA50315bFBd1880cf4511f34a94Fc6",
"LBTC": "0x107Fc7d90484534704dD2A9e24c7BD45DB4dD1B5",
"Owner": "0xB6BbA517f32C75bE36500c7134ec000CFEE0893f",
"Consortium": "0x38A13AB20D15ffbE5A7312d2336EF1552580a4E2",
"Consortium": "0x05B942b57162c8901798e23507442FFFff8Be2Cc",
"TimeLock": "",
"BTCBMock": "0xdd48f288874c7226603cCC98cab0661b3bd5721A",
"BTCPMM": "0xD7377db0dCBA2f5641F294e57c1E85Da47A34fa8"
"BTCB": "0xdd48f288874c7226603cCC98cab0661b3bd5721A",
"BTCBPMM": "0x63749Acfc2527A8406E8BC8c93A80f29FDD75e27",
"ProxyFactory": "0xF3518F0582fA818Fb1a5F07dDE4C8707558C250a"
}
}
12 changes: 7 additions & 5 deletions addresses-mainnet.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@
"LBTC": "0xED7bfd5C1790576105Af4649817f6d35A75CD818",
"Owner": "0x62F10cE5b727edf787ea45776bD050308A611508",
"Consortium": "0xF573F54b8f788BcA3846Cc961A8A5B3B32538550",
"TimeLock": ""
"TimeLock": "",
"ProxyFactory": "0xF3518F0582fA818Fb1a5F07dDE4C8707558C250a"
},
"bscTestnet": {
"ThresholdKey": "0xBF1eC504e525E1BdC2f0a9D3066F727b2fA6Fed9",
"LBTC": "0x045b61074568CD8a3210b3C634e5E5e647327dA6",
"LBTC": "0x731eFa688F3679688cf60A3993b8658138953ED6",
"Owner": "0x62F10cE5b727edf787ea45776bD050308A611508",
"Consortium": "0x0c5fF93c30c201756C8066c73Cab697DC90DE6F7",
"Consortium": "0xF6D5a96BE0F5f7Bb0ABa0A63B38B7Ee874F5fA1E",
"TimeLock": "",
"BTCBMock": "0xdd48f288874c7226603cCC98cab0661b3bd5721A",
"BTCPMM": "0x71162dCC16b321F9F2e321695e70d5774739f45C"
"BTCB": "0xdd48f288874c7226603cCC98cab0661b3bd5721A",
"BTCBPMM": "0x440362b55D4a255EBA3c27C650d2dC1a91Db85bA",
"ProxyFactory": "0xF3518F0582fA818Fb1a5F07dDE4C8707558C250a"
},
"scroll_testnet": {
"ThresholdKey": "0x1820b9218cb2D9a3790EDe3b5F20851BEc8971B0",
Expand Down
21 changes: 21 additions & 0 deletions contracts/Factory/ProxyFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {CREATE3} from "solmate/src/utils/CREATE3.sol";
import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";

contract ProxyFactory {
function createTransparentProxy(address implementation, address admin, bytes memory data, bytes32 salt) public returns (address) {
bytes memory bytecode = abi.encodePacked(
type(TransparentUpgradeableProxy).creationCode,
abi.encode(implementation, admin, data)
);

address proxy = CREATE3.deploy(salt, bytecode, 0);
return proxy;
}

function getDeployed(bytes32 salt) public view returns (address) {
return CREATE3.getDeployed(salt);
}
}
33 changes: 6 additions & 27 deletions contracts/LBTC/LBTC.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ import {ERC20PermitUpgradeable} from "@openzeppelin/contracts-upgradeable/token/
import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import { BitcoinUtils, OutputType } from "../libs/BitcoinUtils.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { IBascule } from "../bascule/interfaces/IBascule.sol";

import { FeeUtils } from "../libs/FeeUtils.sol";
import "./ILBTC.sol";
import "../libs/OutputCodec.sol";
import "../libs/BridgeDepositCodec.sol";
Expand Down Expand Up @@ -65,7 +64,6 @@ contract LBTC is ILBTC, ERC20PausableUpgradeable, Ownable2StepUpgradeable, Reent

// keccak256(abi.encode(uint256(keccak256("lombardfinance.storage.LBTC")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant LBTC_STORAGE_LOCATION = 0xa9a2395ec4edf6682d754acb293b04902817fdb5829dd13adb0367ab3a26c700;
uint16 public constant MAX_COMMISSION = 10000; // 100.00%

function _getLBTCStorage() private pure returns (LBTCStorage storage $) {
assembly {
Expand All @@ -85,11 +83,11 @@ contract LBTC is ILBTC, ERC20PausableUpgradeable, Ownable2StepUpgradeable, Reent
_changeBurnCommission(burnCommission_);
}

function initialize(address consortium_, uint64 burnCommission_) external initializer {
function initialize(address consortium_, uint64 burnCommission_, address owner) external initializer {
__ERC20_init("LBTC", "LBTC");
__ERC20Pausable_init();

__Ownable_init(_msgSender());
__Ownable_init(owner);
__Ownable2Step_init();

__ReentrancyGuard_init();
Expand Down Expand Up @@ -313,13 +311,7 @@ contract LBTC is ILBTC, ERC20PausableUpgradeable, Ownable2StepUpgradeable, Reent
function _deposit(bytes32 toChain, bytes32 toContract, bytes32 toAddress, uint64 amount) internal {

// relative fee
uint16 relativeComs = getDepositRelativeCommission(toChain);
if (amount < relativeComs) {
revert AmountTooSmallToPayRelativeFee();
}

uint256 fee = _calcRelativeFee(amount, relativeComs);

uint256 fee = FeeUtils.getRelativeFee(amount, getDepositRelativeCommission(toChain));
// absolute fee
fee += getDepositAbsoluteCommission(toChain);

Expand All @@ -335,15 +327,6 @@ contract LBTC is ILBTC, ERC20PausableUpgradeable, Ownable2StepUpgradeable, Reent
emit DepositToBridge(fromAddress, toAddress, toContract, toChain, uint64(amountWithoutFee));
}

function _calcRelativeFee(uint64 amount, uint16 commission) internal pure returns (uint256 fee) {
return Math.mulDiv(
amount,
commission,
MAX_COMMISSION,
Math.Rounding.Ceil
);
}

function withdrawFromBridge(
bytes calldata data,
bytes calldata proofSignature
Expand Down Expand Up @@ -416,9 +399,7 @@ contract LBTC is ILBTC, ERC20PausableUpgradeable, Ownable2StepUpgradeable, Reent
revert KnownDestination();
}
// do not allow 100% commission or higher values
if (relCommission >= MAX_COMMISSION) {
revert BadCommission();
}
FeeUtils.validateCommission(relCommission);

LBTCStorage storage $ = _getLBTCStorage();
$.destinations[toChain] = toContract;
Expand Down Expand Up @@ -491,9 +472,7 @@ contract LBTC is ILBTC, ERC20PausableUpgradeable, Ownable2StepUpgradeable, Reent
onlyOwner
{
// do not allow 100% commission
if (newValue >= MAX_COMMISSION) {
revert BadCommission();
}
FeeUtils.validateCommission(newValue);
LBTCStorage storage $ = _getLBTCStorage();
$.depositRelativeCommission[chain] = newValue;
emit DepositRelativeCommissionChanged(newValue, chain);
Expand Down
26 changes: 26 additions & 0 deletions contracts/libs/FeeUtils.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";

library FeeUtils {
uint256 constant MAX_COMMISSION = 10000; // 100%

error AmountTooSmallToPayRelativeFee();
error BadCommission();

function calcRelativeFee(uint256 amount, uint16 relativeComs) internal pure returns (uint256) {
return Math.mulDiv(amount, relativeComs, MAX_COMMISSION, Math.Rounding.Ceil);
}

function getRelativeFee(uint256 amount, uint16 relativeComs) internal pure returns (uint256) {
if(amount < relativeComs)
revert AmountTooSmallToPayRelativeFee();
return calcRelativeFee(amount, relativeComs);
}

function validateCommission(uint16 commission) internal pure {
if (commission >= MAX_COMMISSION)
revert BadCommission();
}
}
43 changes: 35 additions & 8 deletions contracts/pmm/BTCB/BTCB.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/acce
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {FeeUtils} from "../../../contracts/libs/FeeUtils.sol";

interface ILBTC {
function mint(address to, uint256 amount) external;
function transfer(address to, uint256 amount) external;
function decimals() external view returns (uint256);
}

Expand All @@ -21,10 +24,10 @@ contract BTCBPMM is PausableUpgradeable, AccessControlUpgradeable {
uint256 stakeLimit;
uint256 totalStake;
address withdrawAddress;
uint16 relativeFee;
}

bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
bytes32 public constant TIMELOCK_ROLE = keccak256("TIMELOCK_ROLE");

// keccak256(abi.encode(uint256(keccak256("lombardfinance.storage.BTCBPMM")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant PMM_STORAGE_LOCATION = 0x75814abe757fd1afd999e293d51fa6528839552b73d81c6cc151470e3106f500;
Expand All @@ -34,28 +37,30 @@ contract BTCBPMM is PausableUpgradeable, AccessControlUpgradeable {
error ZeroAmount();
event StakeLimitSet(uint256 newStakeLimit);
event WithdrawalAddressSet(address newWithdrawAddress);

event RelativeFeeChanged(uint16 oldRelativeFee, uint16 newRelativeFee);
/// @dev https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#initializing_the_implementation_contract
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}

function __BTCBPMM_init(address _lbtc, address _btcb, address admin, uint256 _stakeLimit, address withdrawAddress) internal onlyInitializing {
function __BTCBPMM_init(address _lbtc, address _btcb, address admin, uint256 _stakeLimit, address withdrawAddress, uint16 _relativeFee) internal onlyInitializing {
_grantRole(DEFAULT_ADMIN_ROLE, admin);
FeeUtils.validateCommission(_relativeFee);

PMMStorage storage $ = _getPMMStorage();
$.stakeLimit = _stakeLimit;
$.withdrawAddress = withdrawAddress;

$.lbtc = ILBTC(_lbtc);
$.btcb = IERC20Metadata(_btcb);
$.relativeFee = _relativeFee;
}

function initialize(address _lbtc, address _btcb, address admin,uint256 _stakeLimit, address withdrawAddress) external initializer {
function initialize(address _lbtc, address _btcb, address admin,uint256 _stakeLimit, address withdrawAddress, uint16 _relativeFee) external initializer {
__Pausable_init();
__AccessControl_init();
__BTCBPMM_init(_lbtc, _btcb, admin, _stakeLimit, withdrawAddress);
__BTCBPMM_init(_lbtc, _btcb, admin, _stakeLimit, withdrawAddress, _relativeFee);
}

function swapBTCBToLBTC(uint256 amount) external whenNotPaused {
Expand All @@ -67,28 +72,46 @@ contract BTCBPMM is PausableUpgradeable, AccessControlUpgradeable {
uint256 decimalsDifference = 10 ** (btcb.decimals() - lbtc.decimals());
uint256 amountLBTC = (amount / decimalsDifference);
if(amountLBTC == 0) revert ZeroAmount();

if ($.totalStake + amountLBTC > $.stakeLimit) revert StakeLimitExceeded();

// relative fee
uint256 fee = FeeUtils.getRelativeFee(amountLBTC, $.relativeFee);

$.totalStake += amountLBTC;
btcb.safeTransferFrom(_msgSender(), address(this), amountLBTC * decimalsDifference);
lbtc.mint(_msgSender(), amountLBTC);
lbtc.mint(_msgSender(), amountLBTC - fee);
lbtc.mint(address(this), fee);
}

function withdrawBTCB(uint256 amount) external whenNotPaused onlyRole(DEFAULT_ADMIN_ROLE) {
PMMStorage storage $ = _getPMMStorage();
$.btcb.transfer($.withdrawAddress, amount);
}

function setWithdrawalAddress(address newWithdrawAddress) external onlyRole(TIMELOCK_ROLE) {
function withdrawLBTC(uint256 amount) external whenNotPaused onlyRole(DEFAULT_ADMIN_ROLE) {
PMMStorage storage $ = _getPMMStorage();
$.lbtc.transfer($.withdrawAddress, amount);
}

function setWithdrawalAddress(address newWithdrawAddress) external onlyRole(DEFAULT_ADMIN_ROLE) {
_getPMMStorage().withdrawAddress = newWithdrawAddress;
emit WithdrawalAddressSet(newWithdrawAddress);
}

function setStakeLimit(uint256 newStakeLimit) external onlyRole(TIMELOCK_ROLE) {
function setStakeLimit(uint256 newStakeLimit) external onlyRole(DEFAULT_ADMIN_ROLE) {
_getPMMStorage().stakeLimit = newStakeLimit;
emit StakeLimitSet(newStakeLimit);
}

function setRelativeFee(uint16 newRelativeFee) external onlyRole(DEFAULT_ADMIN_ROLE) {
FeeUtils.validateCommission(newRelativeFee);
PMMStorage storage $ = _getPMMStorage();
uint16 oldRelativeFee = $.relativeFee;
$.relativeFee = newRelativeFee;
emit RelativeFeeChanged(oldRelativeFee, newRelativeFee);
}

function pause() external onlyRole(PAUSER_ROLE) {
_pause();
}
Expand All @@ -101,6 +124,10 @@ contract BTCBPMM is PausableUpgradeable, AccessControlUpgradeable {
return _getPMMStorage().stakeLimit;
}

function relativeFee() external view returns (uint16) {
return _getPMMStorage().relativeFee;
}

function remainingStake() external view returns (uint256) {
PMMStorage storage $ = _getPMMStorage();
if ($.totalStake > $.stakeLimit) return 0;
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@
"chai": "^4.2.0",
"dotenv": "^16.4.5",
"ethers": "^6.4.0",
"hardhat": "^2.22.2",
"hardhat": "^2.22.12",
"hardhat-gas-reporter": "^1.0.8",
"secp256k1": "^5.0.0",
"solidity-coverage": "^0.8.0",
"solmate": "https://github.com/transmissions11/solmate",
"ts-node": ">=8.0.0",
"typechain": "^8.3.0",
"typescript": ">=4.5.0",
Expand Down
77 changes: 77 additions & 0 deletions scripts/btcbpmm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { task, vars } from "hardhat/config";
import {verify, getAddresses, getProxyFactoryAt, getProxySalt} from "./helpers";
import {DEFAULT_PROXY_FACTORY} from "./helpers/constants";

/*
* After deployment:
* 1. Grant pauser role
* 2. Grant timelock role
*/

task("deploy-btcbpmm", "Deploys the LombardConsortium contract via create3")
.addParam("ledgerNetwork", "The network name of ledger", "mainnet")
.addParam("admin", "The address of the owner")
.addParam("proxyFactoryAddr", "The ProxyFactory address", DEFAULT_PROXY_FACTORY)
.addParam("lbtc", "The address of the LBTC contract")
.addParam("btcb", "The address of the BTCB contract")
.addParam("stakeLimit", "The stake limit", (30n*(10n**8n)).toString()) // default is 30 LBTC
.addParam("withdrawAddress", "The address to withdraw to")
.addParam("relativeFee", "The relative fee of the pmm", (10n).toString())
.setAction(async (taskArgs, hre) => {

const { ledgerNetwork, lbtc, btcb, admin, stakeLimit, withdrawAddress, proxyFactoryAddr, relativeFee } = taskArgs;
const { ethers, run, upgrades } = hre;

const factory = await getProxyFactoryAt(ethers, proxyFactoryAddr);
const saltHash = getProxySalt(ethers, ledgerNetwork, "BTCBPMM");

const btcpmmImpl = await ethers.deployContract("BTCBPMM");
await btcpmmImpl.waitForDeployment();

const data = btcpmmImpl.interface.encodeFunctionData("initialize", [lbtc, btcb, admin, stakeLimit, withdrawAddress, relativeFee]);

const tx = await factory.createTransparentProxy(await btcpmmImpl.getAddress(), admin, data, saltHash);
await tx.wait();

const proxy = await factory.getDeployed(saltHash);
console.log("Proxy address:", proxy);

const proxyAdmin = await upgrades.erc1967.getAdminAddress(proxy);
console.log("Proxy admin:", proxyAdmin);

await verify(run, await factory.getAddress());
await verify(run, await btcpmmImpl.getAddress());
await verify(run, proxyAdmin, {
contract: "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol:ProxyAdmin",
constructorArguments: [admin],
});
await verify(run, proxy, {
contract: "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol:TransparentUpgradeableProxy",
constructorArguments: [await btcpmmImpl.getAddress(), admin, data],
});
});

task("deploy-btcbpmm-vars", "Deploys the BTCBPMM contract with environment variables")
.addOptionalParam("lbtc", "The address of the LBTC contract")
.addOptionalParam("btcb", "The address of the BTCB contract")
.addOptionalParam("admin", "The address of the admin")
.addOptionalParam("stakeLimit", "The stake limit")
.addOptionalParam("withdrawAddress", "The address to withdraw to")
.setAction(async (taskArgs, hre) => {
const { run, network } = hre;
const { lbtc, btcb, admin, stakeLimit, withdrawAddress } = taskArgs;
const addresses = getAddresses(network.name);

const _lbtc = vars.get("LBTC_ADDRESS", lbtc || addresses.LBTC);
const _btcb = vars.get("BTCB_ADDRESS", btcb || addresses.BTCB);
const _admin = vars.get("ADMIN_ADDRESS", admin || addresses.Owner);
const _stakeLimit = vars.get("STAKE_LIMIT", stakeLimit);
const _withdrawAddress = vars.get("WITHDRAW_ADDRESS", withdrawAddress);
await run("deploy-btcbpmm", {
lbtc: _lbtc,
btcb: _btcb,
admin: _admin,
stakeLimit: _stakeLimit,
withdrawAddress: _withdrawAddress
});
});
Loading

0 comments on commit db10466

Please sign in to comment.