Skip to content

Commit

Permalink
audit repair & deploy on sepolia testnet
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoch05 committed Jan 10, 2024
1 parent 2659678 commit 291310c
Show file tree
Hide file tree
Showing 14 changed files with 1,066 additions and 1,015 deletions.
35 changes: 30 additions & 5 deletions helix-contract/address/ln-dev.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,24 @@
{
"chains": {
"sepolia": {
"name": "sepolia",
"url": "https://rpc2.sepolia.org",
"dao": "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4",
"chainId": 11155111,
"lzChainId": 10161,
"lzEndpoint": "0xae92d5aD7583AD66E49A0c67BAd18F6ba52dDDc1",
"deployer": "0x80D4c766C5142D1313D531Afe7384D0D5E108Db3"
},
"arbitrum-sepolia": {
"name": "arbitrum-sepolia",
"url": "https://sepolia-rollup.arbitrum.io/rpc",
"dao": "0x88a39B052d477CfdE47600a7C9950a441Ce61cb4",
"chainId": 421614,
"lzChainId": 10231,
"lzEndpoint": "0x6098e96a28E02f27B1e6BD381f870F1C8Bd169d3",
"deployer": "0x80D4c766C5142D1313D531Afe7384D0D5E108Db3"
}
},
"messagers": {
"zksync-goerli": {
"layerzeroMessager": "0x7e303b0A3F08F9fa5F5629Abb998B8Deba89049B"
Expand All @@ -11,7 +31,9 @@
"debugMessager": "0x2e8D237226041FAFe3F66b6cfc54b064923D454E"
},
"sepolia": {
"Eth2ScrollSendService": "0x89AF830781A2C1d3580Db930bea11094F55AfEae"
"chainId": 11155111,
"Eth2ScrollSendService": "0x89AF830781A2C1d3580Db930bea11094F55AfEae",
"layerzeroMessager": "0x33C9916a43507aa0a89a3e889522f840aa1245fE"
},
"arbitrum-goerli": {
"Eth2ArbReceiveService": "0x102F8D7Cfe692AA79c17E3958aB00D060Df0B88f",
Expand All @@ -34,7 +56,9 @@
"layerzeroMessager": "0x463D1730a8527CA58d48EF70C7460B9920346567"
},
"arbitrum-sepolia": {
"darwiniaMsglineMessager": "0xCddD3e43dA1e9485d4FcD3782DFba04aADCfC9B2"
"chainId": "421614",
"darwiniaMsglineMessager": "0xCddD3e43dA1e9485d4FcD3782DFba04aADCfC9B2",
"layerzeroMessager": "0x87A649246974732f7AbBe01F2DD81E3D829EF0B7"
}
},
"ProxyAdmin": {
Expand All @@ -53,11 +77,11 @@
"LnOppositeBridgeProxy": "0x4C538EfA6e3f9Dfb939AA4F0B224577DA665923a",
"LnV3BridgeLogic": {
"zkSync": "0xa480d54af27d65cc485f7c11ec2F072F2d671863",
"others": "0x3B3Ad62319CAc1C1872C0370d84C60F816d4B69B"
"others": "0xC4Cecb7d4c0eA6c7AA88CbdE56612Cdc2DE2E756"
},
"LnV3BridgeProxy": {
"zkSync": "0xab38D0030cC28e413C4DD2B7D0ac2b6984e6d3f0",
"others": "0xb0Ce2498C2526cceA1D7792e4B62C3066Eb5529B"
"others": "0x38627Cb033De66a1E07e73f5D0a7a7adFB6741fa"
},
"deployer": "0xbe6b2860d3c17a719be0A4911EA0EE689e8357f3",
"usdt": {
Expand All @@ -68,7 +92,8 @@
"zksync-goerli": "0xb5372ed3bb2CbA63e7908066ac10ee94d30eA839",
"base-goerli": "0x876A4f6eCF13EEb101F9E75FCeF58f19Ff383eEB",
"sepolia": "0x876A4f6eCF13EEb101F9E75FCeF58f19Ff383eEB",
"scroll-sepolia": "0x9C80EdD342b5D179c3a87946fC1F0963BfcaAa09"
"scroll-sepolia": "0x9C80EdD342b5D179c3a87946fC1F0963BfcaAa09",
"arbitrum-sepolia": "0x3b8Bb7348D4F581e67E2498574F73e4B9Fc51855"
},
"usdc": {
"goerli": "0xe9784E0d9A939dbe966b021DE3cd877284DB1B99",
Expand Down
57 changes: 26 additions & 31 deletions helix-contract/contracts/ln/base/LnBridgeSourceV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import "../../utils/TokenTransferHelper.sol";
/// @notice LnBridgeSourceV3 is a contract to help user lock token and then trigger remote chain relay
/// @dev See https://github.com/helix-bridge/contracts/tree/master/helix-contract
contract LnBridgeSourceV3 is Pausable, AccessController {
uint256 constant public SLASH_EXPIRE_TIME = 60 * 60;
uint256 constant public LOCK_TIME_DISTANCE = 15 minutes;
uint256 constant public SLASH_EXPIRE_TIME = 1 hours;
uint256 constant public MAX_TRANSFER_AMOUNT = type(uint112).max;
// liquidity fee base rate
// liquidityFee = liquidityFeeRate / LIQUIDITY_FEE_RATE_BASE * sendAmount
Expand Down Expand Up @@ -46,7 +47,10 @@ contract LnBridgeSourceV3 is Pausable, AccessController {
uint112 totalFee;
uint112 amount;
address receiver;
uint256 nonce;
// use this timestamp as the lock time
// can't be too far from the block that the transaction confirmed
// This timestamp can also be adjusted to produce different transferId
uint256 timestamp;
}
// hash(remoteChainId, sourceToken, targetToken) => TokenInfo
mapping(bytes32=>TokenInfo) public tokenInfos;
Expand All @@ -62,7 +66,6 @@ contract LnBridgeSourceV3 is Pausable, AccessController {
// when we wan't to get tokenInfo from lockInfo, we should get the key(bytes32) from tokenIndex, then get tokenInfo from key
struct LockInfo {
uint112 amountWithFeeAndPenalty;
uint64 timestamp;
uint32 tokenIndex;
uint8 status;
}
Expand Down Expand Up @@ -100,8 +103,7 @@ contract LnBridgeSourceV3 is Pausable, AccessController {
TransferParams params,
bytes32 transferId,
uint112 targetAmount,
uint112 fee,
uint64 timestamp
uint112 fee
);
event LnProviderUpdated(
uint256 remoteChainId,
Expand All @@ -115,7 +117,7 @@ contract LnBridgeSourceV3 is Pausable, AccessController {
event PenaltyReserveUpdated(address provider, address sourceToken, uint256 updatedPanaltyReserve);
event LiquidityWithdrawn(bytes32[] transferIds, address provider, uint256 amount);
event TransferSlashed(bytes32 transferId, address provider, address slasher, uint112 slashAmount);
event LnProviderPaused(address provider, uint256 remoteChainId, address sourceToken, address targetToken, bool paused);
event LnProviderPaused(address provider, uint256 remoteChainId, address sourceToken, address targetToken, bool paused);

modifier allowRemoteCall(uint256 _remoteChainId) {
_verifyRemote(_remoteChainId);
Expand Down Expand Up @@ -320,6 +322,12 @@ contract LnBridgeSourceV3 is Pausable, AccessController {
}

function lockAndRemoteRelease(TransferParams calldata _params) whenNotPaused external payable {
// timestamp must be close to the block time
require(
_params.timestamp >= block.timestamp - LOCK_TIME_DISTANCE && _params.timestamp <= block.timestamp + LOCK_TIME_DISTANCE,
"timestamp is too far from block time"
);

// check transfer info
bytes32 tokenKey = getTokenKey(_params.remoteChainId, _params.sourceToken, _params.targetToken);
TokenInfo memory tokenInfo = tokenInfos[tokenKey];
Expand All @@ -344,8 +352,8 @@ contract LnBridgeSourceV3 is Pausable, AccessController {
require(remoteAmount < MAX_TRANSFER_AMOUNT && remoteAmount > 0, "overflow amount");
bytes32 transferId = getTransferId(_params, uint112(remoteAmount));
require(lockInfos[transferId].status == 0, "transferId exist");
lockInfos[transferId] = LockInfo(amountWithFeeAndPenalty, uint64(block.timestamp), tokenInfo.index, LOCK_STATUS_LOCKED);
emit TokenLocked(_params, transferId, uint112(remoteAmount), uint112(providerFee), uint64(block.timestamp));
lockInfos[transferId] = LockInfo(amountWithFeeAndPenalty, tokenInfo.index, LOCK_STATUS_LOCKED);
emit TokenLocked(_params, transferId, uint112(remoteAmount), uint112(providerFee));

// update protocol fee income
// leave the protocol fee into contract, and admin can withdraw this fee anytime
Expand Down Expand Up @@ -413,40 +421,27 @@ contract LnBridgeSourceV3 is Pausable, AccessController {
uint256 _remoteChainId,
bytes32 _transferId,
// slasher, amount and lnProvider is verified on the target chain
uint112 _sourceAmount,
address _lnProvider,
uint64 _timestamp,
address _slasher
) external allowRemoteCall(_remoteChainId) {
LockInfo memory lockInfo = lockInfos[_transferId];
require(lockInfo.status == LOCK_STATUS_LOCKED, "invalid lock status");
require(lockInfo.amountWithFeeAndPenalty >= _sourceAmount, "invalid amount");
bytes32 tokenKey = tokenIndexer[lockInfo.tokenIndex];
TokenInfo memory tokenInfo = tokenInfos[tokenKey];
lockInfos[_transferId].status = LOCK_STATUS_SLASHED;

uint112 slashAmount = _sourceAmount;
// recheck the timestamp
// expired
if (_timestamp == lockInfo.timestamp && lockInfo.timestamp + SLASH_EXPIRE_TIME < block.timestamp) {
slashAmount = lockInfo.amountWithFeeAndPenalty;
// pause this provider if slashed
bytes32 providerKey = getProviderKey(_remoteChainId, _lnProvider, tokenInfo.sourceToken, tokenInfo.targetToken);
srcProviders[providerKey].pause = true;
emit LnProviderPaused(_lnProvider, _remoteChainId, tokenInfo.sourceToken, tokenInfo.targetToken, true);
} else {
// this means the slasher help the provider relay message and get no reward
// redeposit penalty(the fee and penalty) for lnProvider
bytes32 key = getProviderStateKey(tokenInfo.sourceToken, _lnProvider);
penaltyReserves[key] = penaltyReserves[key] + lockInfo.amountWithFeeAndPenalty - slashAmount;
}
// transfer slashAmount to slasher
// pause this provider if slashed
bytes32 providerKey = getProviderKey(_remoteChainId, _lnProvider, tokenInfo.sourceToken, tokenInfo.targetToken);
srcProviders[providerKey].pause = true;
emit LnProviderPaused(_lnProvider, _remoteChainId, tokenInfo.sourceToken, tokenInfo.targetToken, true);

// transfer token to slasher
if (tokenInfo.sourceToken == address(0)) {
TokenTransferHelper.safeTransferNative(_slasher, slashAmount);
TokenTransferHelper.safeTransferNative(_slasher, lockInfo.amountWithFeeAndPenalty);
} else {
TokenTransferHelper.safeTransfer(tokenInfo.sourceToken, _slasher, slashAmount);
TokenTransferHelper.safeTransfer(tokenInfo.sourceToken, _slasher, lockInfo.amountWithFeeAndPenalty);
}
emit TransferSlashed(_transferId, _lnProvider, _slasher, slashAmount);
emit TransferSlashed(_transferId, _lnProvider, _slasher, lockInfo.amountWithFeeAndPenalty);
}

function getProviderKey(uint256 _remoteChainId, address _provider, address _sourceToken, address _targetToken) pure public returns(bytes32) {
Expand Down Expand Up @@ -474,7 +469,7 @@ contract LnBridgeSourceV3 is Pausable, AccessController {
_params.receiver,
_params.amount,
_remoteAmount,
_params.nonce
_params.timestamp
));
}

Expand Down
17 changes: 5 additions & 12 deletions helix-contract/contracts/ln/base/LnBridgeTargetV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ contract LnBridgeTargetV3 {
// sourceAmount: the send amount on source chain
struct SlashInfo {
uint256 remoteChainId;
uint64 lockTimestamp;
uint112 sourceAmount;
address slasher;
}

Expand All @@ -32,7 +30,7 @@ contract LnBridgeTargetV3 {
uint112 sourceAmount;
uint112 targetAmount;
address receiver;
uint256 nonce;
uint256 timestamp;
}

// transferId => FillTransfer
Expand Down Expand Up @@ -65,7 +63,7 @@ contract LnBridgeTargetV3 {
_params.receiver,
_params.sourceAmount,
_params.targetAmount,
_params.nonce
_params.timestamp
));
require(_expectedTransferId == transferId, "check expected transferId failed");
FillTransfer memory fillTransfer = fillTransfers[transferId];
Expand All @@ -89,7 +87,6 @@ contract LnBridgeTargetV3 {
// 3. send a cross-chain message to source chain to withdraw the amount, fee and penalty from lnProvider
function requestSlashAndRemoteRelease(
RelayParams calldata _params,
uint64 _timestamp,
bytes32 _expectedTransferId,
uint256 _feePrepaid,
bytes memory _extParams
Expand All @@ -103,7 +100,7 @@ contract LnBridgeTargetV3 {
_params.receiver,
_params.sourceAmount,
_params.targetAmount,
_params.nonce
_params.timestamp
));
require(_expectedTransferId == transferId, "check expected transferId failed");

Expand All @@ -112,9 +109,9 @@ contract LnBridgeTargetV3 {

// suppose source chain and target chain has the same block timestamp
// event the timestamp is not sync exactly, this TIMEOUT is also verified on source chain
require(_timestamp < block.timestamp - LnBridgeHelper.SLASH_EXPIRE_TIME, "time not expired");
require(_params.timestamp < block.timestamp - LnBridgeHelper.SLASH_EXPIRE_TIME, "time not expired");
fillTransfers[transferId] = FillTransfer(uint64(block.timestamp), _params.provider);
slashInfos[transferId] = SlashInfo(_params.remoteChainId, _timestamp, _params.sourceAmount, msg.sender);
slashInfos[transferId] = SlashInfo(_params.remoteChainId, msg.sender);

if (_params.targetToken == address(0)) {
require(msg.value == _params.targetAmount + _feePrepaid, "invalid value");
Expand All @@ -127,9 +124,7 @@ contract LnBridgeTargetV3 {
ILnBridgeSourceV3.slash.selector,
block.chainid,
transferId,
_params.sourceAmount,
_params.provider,
_timestamp,
msg.sender
);
_sendMessageToSource(_params.remoteChainId, message, _feePrepaid, _extParams);
Expand All @@ -148,9 +143,7 @@ contract LnBridgeTargetV3 {
ILnBridgeSourceV3.slash.selector,
block.chainid,
transferId,
slashInfo.sourceAmount,
fillTransfer.provider,
slashInfo.lockTimestamp,
slashInfo.slasher
);
_sendMessageToSource(slashInfo.remoteChainId, message, msg.value, _extParams);
Expand Down
2 changes: 0 additions & 2 deletions helix-contract/contracts/ln/interface/ILnBridgeSourceV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ interface ILnBridgeSourceV3 {
function slash(
uint256 _remoteChainId,
bytes32 _transferId,
uint112 _sourceAmount,
address _lnProvider,
uint64 _timestamp,
address _slasher
) external;
function withdrawLiquidity(
Expand Down
4 changes: 2 additions & 2 deletions helix-contract/deploy/create2.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ var Create2 = {
const bytecode = `${factory.bytecode}${encodedParams.slice(2)}`;
return bytecode;
},
deploy: async function(deployAddress, wallet, bytecode, salt) {
deploy: async function(deployAddress, wallet, bytecode, salt, gasLimit) {
const hexSalt = ethers.utils.id(salt.toString());
const deployer = await ethers.getContractAt("Create2Deployer", deployAddress, wallet);
const result = await (await deployer.deploy(bytecode, hexSalt)).wait();
const result = await (await deployer.deploy(bytecode, hexSalt, {gasLimit: gasLimit})).wait();
const targetEvent = result.events.find((e) => e.event == 'Deployed');
const abiCoder = ethers.utils.defaultAbiCoder;
const eventParams = abiCoder.decode(["address", "uint256"], targetEvent.data);
Expand Down
24 changes: 11 additions & 13 deletions helix-contract/deploy/deploy_ln_create2.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const ethUtil = require('ethereumjs-util');
const abi = require('ethereumjs-abi');
const secp256k1 = require('secp256k1');
const fs = require("fs");

var Create2 = require("./create2.js");

Expand All @@ -21,8 +22,9 @@ async function deployCreate2Deployer(networkUrl, version) {
from: w.address,
to: "0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7",
data: `${salt}${bytecode.slice(2)}`,
gasPrice: 2100000000,
nonce: 0,
gasLimit: 2000000,
//gasPrice: 2100000000,
//nonce: 0,
};
const tx = await w.sendTransaction(unsignedTransaction);
console.log(`deploy create2 tx: ${tx.hash}, salt: ${salt}`);
Expand All @@ -31,17 +33,13 @@ async function deployCreate2Deployer(networkUrl, version) {

// 2. deploy mapping token factory
async function main() {
//await deployCreate2Deployer('https://rpc.ankr.com/eth_goerli', 'v1.0.0');
//await deployCreate2Deployer('https://goerli-rollup.arbitrum.io/rpc', 'v1.0.0');
//await deployCreate2Deployer('https://rpc.testnet.mantle.xyz', 'v1.0.0');
//await deployCreate2Deployer('https://rpc.goerli.linea.build', 'v1.0.0');
//await deployCreate2Deployer('https://arb1.arbitrum.io/rpc', 'v1.0.0');
//await deployCreate2Deployer('https://rpc.mantle.xyz', 'v1.0.0');
//await deployCreate2Deployer('https://crab-rpc.darwinia.network', 'v1.0.0');
//await deployCreate2Deployer('https://binance.llamarpc.com', 'v1.0.0');
//await deployCreate2Deployer('https://mainnet.base.org', 'v1.0.0');
//await deployCreate2Deployer('https://optimism.llamarpc.com', 'v1.0.0');
await deployCreate2Deployer('https://rpc.linea.build', 'v1.0.0');
const pathConfig = "./address/ln-dev.json";
const configure = JSON.parse(
fs.readFileSync(pathConfig, "utf8")
);

const network = configure.chains['arbitrum-sepolia'];
await deployCreate2Deployer(network.url, 'v1.0.0');
}

main()
Expand Down
Loading

0 comments on commit 291310c

Please sign in to comment.