Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions contracts/contracts/errors/IPCErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,6 @@ error InvalidFederationPayload();
error DuplicatedGenesisValidator();
error NotEnoughGenesisValidators();
error ValidatorPowerChangeDenied();
error IncreaseAllowanceFailed();
error Unreachable();

enum InvalidXnetMessageReason {
Sender,
Expand Down
31 changes: 16 additions & 15 deletions contracts/contracts/lib/AssetHelper.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.23;

import {NotEnoughBalance, IncreaseAllowanceFailed} from "../errors/IPCErrors.sol";
import {NotEnoughBalance} from "../errors/IPCErrors.sol";
import {Asset, AssetKind} from "../structs/Subnet.sol";
import {EMPTY_BYTES} from "../constants/Constants.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
Expand Down Expand Up @@ -205,21 +205,22 @@ library AssetHelper {
}
}

function native() internal pure returns (Asset memory) {
return Asset({kind: AssetKind.Native, tokenAddress: address(0)});
// @notice Makes the asset available for spending by the given spender, without actually sending it.
// @return msgValue The amount of msg.value that needs to be sent along with the subsequent call that will _actually_ spend that asset.
// Will be 0 if the asset is a token, since no native coins are to be sent.
function makeAvailable(Asset memory self, address spender, uint256 amount) internal returns (uint256 msgValue) {
if (self.kind == AssetKind.Native) {
msgValue = amount;
} else if (self.kind == AssetKind.ERC20) {
IERC20 token = IERC20(self.tokenAddress);
token.safeIncreaseAllowance(spender, amount);
msgValue = 0;
}
return msgValue;
}

function isNative(Asset memory self) internal pure returns(bool) {
return self.kind == AssetKind.Native;
function native() internal pure returns (Asset memory) {
return Asset({kind: AssetKind.Native, tokenAddress: address(0)});
}

function increaseAllowance(Asset memory self, address spender, uint256 amount) internal {
if (self.kind == AssetKind.ERC20) {
IERC20 token = IERC20(self.tokenAddress);
uint256 allowance = token.allowance(address(this), spender);
if (!token.approve(spender, allowance + amount)) {
revert IncreaseAllowanceFailed();
}
}
}
}
}
13 changes: 4 additions & 9 deletions contracts/contracts/lib/LibStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {LibMinPQ, MinPQ} from "./priority/LibMinPQ.sol";
import {LibStakingChangeLog} from "./LibStakingChangeLog.sol";
import {AssetHelper} from "./AssetHelper.sol";
import {PermissionMode, StakingReleaseQueue, StakingChangeLog, StakingChange, StakingChangeRequest, StakingOperation, StakingRelease, ValidatorSet, AddressStakingReleases, ParentValidatorsTracker, Validator, Asset} from "../structs/Subnet.sol";
import {WithdrawExceedingCollateral, NotValidator, CannotConfirmFutureChanges, NoCollateralToWithdraw, AddressShouldBeValidator, InvalidConfigurationNumber, Unreachable} from "../errors/IPCErrors.sol";
import {WithdrawExceedingCollateral, NotValidator, CannotConfirmFutureChanges, NoCollateralToWithdraw, AddressShouldBeValidator, InvalidConfigurationNumber} from "../errors/IPCErrors.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";

library LibAddressStakingReleases {
Expand Down Expand Up @@ -583,15 +583,10 @@ library LibStaking {
IGateway(gateway).releaseStake(amount);
} else if (change.op == StakingOperation.Deposit) {
s.validatorSet.confirmDeposit(validator, amount);

if (s.collateralSource.isNative()) {
IGateway(gateway).addStake{value: amount}(amount);
} else {
s.collateralSource.increaseAllowance(gateway, amount);
IGateway(gateway).addStake(amount);
}
uint256 msgValue = s.collateralSource.makeAvailable(gateway, amount);
IGateway(gateway).addStake{value: amount}(amount);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is not correct, it should be:

IGateway(gateway).addStake{value: msgValue}(amount);

Pushed a PR to this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well spotted! Copy pasta

} else {
revert Unreachable();
revert("Unknown staking operation");
}
}

Expand Down
21 changes: 2 additions & 19 deletions contracts/contracts/lib/LibSubnetActor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -161,26 +161,9 @@ library LibSubnetActor {

uint256 genesisCircSupply = s.genesisCircSupply;

bool supplySourceNative = s.supplySource.isNative();
bool collateralSourceNative = s.collateralSource.isNative();

// this method is unnecessarily handling different cases because subnet actor needs
// to "register" in gateway and different token types needs to be attached or approved.
// TODO: it's known that having gateway holding all subnets' funds is insecure, this
// TODO: can be removed once contract redesign is in place.
uint256 msgValue = 0;

if (!supplySourceNative) {
s.supplySource.increaseAllowance(s.ipcGatewayAddr, genesisCircSupply);
} else {
msgValue += genesisCircSupply;
}

if (!collateralSourceNative) {
s.collateralSource.increaseAllowance(s.ipcGatewayAddr, collateral);
} else {
msgValue += collateral;
}
msgValue += s.supplySource.makeAvailable(s.ipcGatewayAddr, genesisCircSupply);
msgValue += s.collateralSource.makeAvailable(s.ipcGatewayAddr, collateral);

IGateway(s.ipcGatewayAddr).register{value: msgValue}(genesisCircSupply, collateral);
}
Expand Down