Omniscia Swisscoast Audit
HLQTYToken Manual Review Findings
HLQTYToken Manual Review Findings
HLQ-01M: Inexistent Restrictions of Multi-Signature Wallet
Type | Severity | Location |
---|---|---|
Logical Fault | HLQTYToken.sol:L196 |
Description:
The original LQTY
implementation implements a one-year restriction before the multi-signature wallet behind the HLiquity
team can transact tokens, however, this restriction has been eliminated from the HLQTYToken
.
Impact:
Transfer restrictions in relation to the multi-signature wallet are not in place in the HLQTYToken
implementation which we consider incorrect.
Example:
186function _transfer(address sender, address recipient, uint256 amount) internal {187 require(sender != address(0), "ERC20: transfer from the zero address");188 require(recipient != address(0), "ERC20: transfer to the zero address");189
190 require(amount <= uint256(type(int64).max), "Amount exceeds int64 limits");191
192 int64 safeAmount = int64(amount);193
194 address currentTokenAddress = _getTokenAddress();195
196 int responseCode = HederaTokenService.transferToken(currentTokenAddress, sender, recipient, safeAmount);197
198 _checkResponse(responseCode);199
200 emit TokenTransfer(currentTokenAddress, sender, recipient, safeAmount);201}
Recommendation:
We advise this restriction to be imposed by deferring the actual minting of tokens until after a year has elapsed.
Alternatively, we advise the tokens to be escrowed by the HLQTYToken
itself to permit staking and to be withdrawable after one year.
Alleviation (04618e407bddce5b22e9cadd787fd3334bd3afe6):
The Swisscoast team has specified that no approach suits their intended business case, and as such they have opted to lock the tokens on a trust basis.
We consider this exhibit acknowledged as a result.
HLQ-02M: Inefficient Auto-Renewal Period
Type | Severity | Location |
---|---|---|
Language Specific | HLQTYToken.sol:L111 |
Description:
The period in which the contract's rent will auto-renew is inefficient as it is not a whole time unit (i.e. X days
).
Impact:
Due to the imprecise renew period of 8_000_000
presently defined, it might be difficult to properly synchronize funding the HLQTYToken
account to pay for its rent.
Example:
111token.expiry = createAutoRenewExpiry(address(this), 8000000);
Recommendation:
We advise the defaultAutoRenewPeriod
as defined in the SafeHTS
contract to be utilized which is equivalent to 7_776_000
, ensuring that the auto-renewal period cycles every 90 days in accordance to the Hedera blockchain limitation.
Alleviation (04618e407bddce5b22e9cadd787fd3334bd3afe6):
The auto-renewal period has been configured to 7_776_000
per our recommendation, optimizing the system's rent efficiency.
HLQ-03M: Inexistent Enforcement of Transfer-Related Restrictions
Type | Severity | Location |
---|---|---|
Logical Fault | HLQTYToken.sol:L264-L275, L277-L280, L286-L288 |
Description:
Due to the usage of the Hedera Token Service, the transfer-related restrictions that the original LQTYToken
implemented cannot be replicated in the HLQTYToken
or its underlying HTS implementation.
Impact:
Safety precautions presently imposed by the original LQTY
token implementation are not imposed on the HLQTY
token.
Example:
186function _transfer(address sender, address recipient, uint256 amount) internal {187 require(sender != address(0), "ERC20: transfer from the zero address");188 require(recipient != address(0), "ERC20: transfer to the zero address");189
190 require(amount <= uint256(type(int64).max), "Amount exceeds int64 limits");191
192 int64 safeAmount = int64(amount);193
194 address currentTokenAddress = _getTokenAddress();195
196 int responseCode = HederaTokenService.transferToken(currentTokenAddress, sender, recipient, safeAmount);197
198 _checkResponse(responseCode);199
200 emit TokenTransfer(currentTokenAddress, sender, recipient, safeAmount);201}
Recommendation:
We advise the restrictions to be imposed via the HLQTYToken::_tranfser
function. While these restrictions will not apply to interactions with the HTS token directly, they are meant to prevent accidental transfer of funds rather than secure the prohibited recipients.
Alleviation (04618e407b):
The Swisscoast team has not supplied an alleviation for this exhibit whereas their response document implies it has been fixed but contains incorrect content that relates to HLQ-02M
.
We advise the Swisscoast team to revisit this exhibit and specify whether they intend to acknowledge or alleviate it.
Alleviation (30f7253f63):
The Swisscoast team re-evaluated this exhibit and opted to acknowledge it, stating that the token adheres to the same restrictions as the LQTY
token.
This is not correct, as the transfer and transfer-from implementations of the LQTYToken
apply different restrictions.
In any case, we consider this exhibit acknowledged as these restrictions cannot be reliably replicated due to usage of the Hedera Token Service and we consider this exhibit safely acknowledged based on the fact that the Swisscoast team will honestly operate the token.
HLQ-04M: Insecure Subtraction of Balances
Type | Severity | Location |
---|---|---|
Mathematical Operations | HLQTYToken.sol:L230 |
Description:
The referenced subtraction performed will be unchecked due to the pragma
version of the codebase.
Impact:
Although unlikely, any reduction of the address(this)
balance will not be handled and will result in an overflow. While the transaction will properly revert in such a case, we still advise the overflow to be handled distinctly from the treasury-related error.
Example:
229if (230 !((_balanceOf(address(this)) - balance) ==231 amount)232) revert('The smart contract is not the treasury account');
Recommendation:
We advise it to be safely performed by utilizing the SafeMath::sub
function as exposed by the uint256
data type.
Alleviation (04618e407bddce5b22e9cadd787fd3334bd3afe6):
The codebase employs the SafeMath::sub
function albeit using non-standard syntax (i.e. directly invoking the library
function).
While the exhibit is addressed, we advise the using SafeMath for uint256
syntax to be employed increasing the legibility of the code.
HLQ-05M: Inexistent Bypass of Authorization
Type | Severity | Location |
---|---|---|
Logical Fault | HLQTYToken.sol:L179 |
Description:
The original LQTY
token implementation permitted the LQTYStaking
implementation to bypass approvals by performing a direct transfer in the HLQTYToken::sendToHLQTYStaking
function, however, the HLQTY
implementation requires an approval due to the usage of the underlying HTS token system.
Impact:
A functional discrepancy can be observed between the HLiquity implementation and its Liquity equivalent whereby an extra authorization is required for staking operations.
Example:
176function sendToHLQTYStaking(address _sender, uint256 _amount) external override {177 _requireCallerIsHLQTYStaking();178 if (_isFirstYear()) { _requireSenderIsNotMultisig(_sender); } // Prevent the multisig from staking HLQTY179 _transfer(_sender, hlqtyStakingAddress, _amount);180}
Recommendation:
We advise this trait to be evaluated, and different balance transfer mechanisms to be utilized such as burn and mint operations that would not require authorization.
Alleviation (04618e407bddce5b22e9cadd787fd3334bd3afe6):
The Swisscoast team has opted to retain the current behaviour of the code in place as they do not consider the surplus approvals required to be disruptive for users or system contracts.
We would like to clarify that the burn / mint capabilities inferred by the exhibit's recommendation allude to the native Hedera token's burn and mint capabilities rather than the token implementation's.
HLQ-06M: Inexistent Acceptance of Native Funds
Type | Severity | Location |
---|---|---|
Logical Fault | HLQTYToken.sol:L111 |
Description:
The HLQTYToken
will set itself as responsible for auto-renewing its rent, however, it is not capable of accepting native funds (HBAR
) to fund the rent during its auto renewal.
Impact:
When rent is enabled for smart contracts on the Hedera blockchain, the HLQTYToken
will be unable to pay its rent and thus may become disabled unless special mechanisms are used to transfer funds to the contract directly.
Example:
84constructor85(86 address _communityIssuanceAddress,87 address _hlqtyStakingAddress,88 address _lockupFactoryAddress,89 address _multisigAddress90) 91 payable public92{93 checkContract(_communityIssuanceAddress);94 checkContract(_hlqtyStakingAddress);95 checkContract(_lockupFactoryAddress);96
97 multisigAddress = _multisigAddress;98 deploymentStartTime = block.timestamp;99 100 communityIssuanceAddress = _communityIssuanceAddress;101 hlqtyStakingAddress = _hlqtyStakingAddress;102 lockupContractFactory = ILockupContractFactory(_lockupFactoryAddress);103
104 // --- Deploy Hedera HTS ---105
106 IHederaTokenService.HederaToken memory token;107 token.name = _NAME;108 token.symbol = _SYMBOL;109 token.treasury = address(this);110
111 token.expiry = createAutoRenewExpiry(address(this), 8000000);112
113 IHederaTokenService.TokenKey[] memory keys = new IHederaTokenService.TokenKey[](1);114 keys[0] = getSingleKey(KeyType.SUPPLY, KeyValueType.INHERIT_ACCOUNT_KEY, bytes(""));115
116 token.tokenKeys = keys;117
118 (int responseCode, address createdTokenAddress) =119 HederaTokenService.createFungibleToken(token, 0, _DECIMALS);120
121 _checkResponse(responseCode);122 tokenAddress = createdTokenAddress;123
124 uint _lpRewardsEntitlement = _1_MILLION.mul(4).div(3); // Allocate 1.33 million for LP rewards125 lpRewardsEntitlement = _lpRewardsEntitlement;126}
Recommendation:
We advise the contract to have an HLQTYToken::receive
function introduced, permitting it to be funded with the necessary funds to auto-renew its rent.
Alleviation (04618e407bddce5b22e9cadd787fd3334bd3afe6):
The Swisscoast team clarified that the account responsible for paying the contract's rent is distinct from its contract instance and attached to the same account ID.
It is possible to fund the account directly without executing code on its contract counterpart effectively funding rent costs without a receive
function in the contract involved.
We consider the exhibit invalid in light of this information and thus have marked it as nullified.