Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor and fix: addressing recent changes #62

Merged
merged 4 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
26 changes: 13 additions & 13 deletions audit/internal2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ next
} - skip
5. pass
```
[]
[x] Outdated due to design change

#### Medium. _calculatePayment not update collectedFees;
```
Expand All @@ -57,15 +57,15 @@ function _calculatePayment(
uint256 payment
) internal virtual returns (uint256 mechPayment, uint256 marketplaceFee) {
```
[]
[x] Outdated due to design change

#### Medium. payable fallback()
```
Must be payable.
fallback() external {
// solhint-disable-next-line avoid-low-level-calls
```
[]
[x] Fixed

#### Medium. Typo in check.
```
Expand All @@ -78,10 +78,10 @@ constructor(address _mechMarketplace, address _serviceRegistry, uint256 _service
revert ZeroValue();
}
```
[]
[x] Outdated due to design change

#### Low? Notices? OlasMech.setUp(bytes) event
[]
[x] Noticed, internal storage writing

#### Low? Notices? Karma.sol Uniform approach to location getImplementation() (proxy/implementation)
```
Expand All @@ -95,7 +95,7 @@ Depending on what they understand better for etherscan. Probably in proxy better
}
}
```
[]
[x] Noticed

### Low? improvement create2(), due to unpredictability.
```
Expand Down Expand Up @@ -125,7 +125,7 @@ bytes32 salt = keccak256(abi.encode(nonce, block.timestamp, msg.sender, serviceI
same for contracts\integrations\nevermined\MechFactorySubscription.sol
```
[]
[x] Fixed

### Notices
#### Low? Notices? No issue? initialize and constructor on MechMarketplace + frontrunning (?!) To discussion
Expand All @@ -148,7 +148,7 @@ function initialize(uint256 _fee, uint256 _minResponseTimeout, uint256 _maxRespo
Frontrunning is possible : between constructor() -> initialize() : No issue!
Changing the storage of implementation has no effect on changing the storage of proxy!
```
[]
[x] Noticed

#### Low? Notices? No issue? frontrunning initialize() in Karma.sol. To discussion
```
Expand All @@ -168,22 +168,22 @@ Example:
}
Changing the storage of implementation has no effect on changing the storage of proxy!
```
[]
[x] Noticed, already initialized

### Notices. Variable "price". Problem of terminology
```
Problem of terminology. Price is usually expressed as amount0/amount1
if (amount < price) {}
```
[]
[x] Outdated

### Notices. for design createMech()
```
Can be called by anyone, a small limitation is that it is called from the marketPlace?
function createMech()
-> callback IMechMarketplace(mechMarketplace).mapMechFactories[mechFactory] == address(this)
```
[]
[x] Fixed

### Notices. Pure? _calculatePayment()
```
Expand All @@ -193,12 +193,12 @@ function _calculatePayment(
) internal virtual returns (uint256 mechPayment, uint256 marketplaceFee)
-> pure?
```
[]
[x] Outdated

### Notices. Low/Notices
```
uint256 private constant FEE_BASIS_POINTS = 10_000; // 100% в bps
```
[]
[x] Fixed


9 changes: 5 additions & 4 deletions audit/internal3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,29 @@ Most of the issues raised by instrumental analysis are outside the scope of the

### Issue
#### Medium. Make sure that the previous comments (internal - internal2) have been addressed.
[]
[x] Addressed

#### Critical/Medium. checkAndRecordDeliveryRate() for native token
```
function checkAndRecordDeliveryRate()
This is not the right behavior for a case msg.value > 0 and native token contracts.
```
[x] Fixed

#### Low. More Reentrancy protection
```
function checkAndRecordDeliveryRate()
function finalizeDeliveryRate()
+ Reentrancy protection agains IMech(mech).maxDeliveryRate()
```
[]
[x] Fixed

#### Notices. unintuitive name vs action
```
function _checkNativeValue() internal virtual override
The function name is very unintuitive. In reality, it just does a revert if the contract type is token.
```
[]
[x] Fixed

#### Notices. checkAndRecordDeliveryRate why are uint256 parameters needed
```
Expand All @@ -53,4 +54,4 @@ Why unused params?
uint256
If this is abstract data for the future, it is better to replace it with bytes payload.
```
[]
[x] Fixed
24 changes: 13 additions & 11 deletions contracts/BalanceTrackerFixedPriceBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@
uint256 public constant FEE_BASE = 10_000;

// Mech marketplace address
address public immutable mechMarketplace;

Check warning on line 59 in contracts/BalanceTrackerFixedPriceBase.sol

View workflow job for this annotation

GitHub Actions / build

Immutable variables name are set to be in capitalized SNAKE_CASE
// Buy back burner address
address public immutable buyBackBurner;

Check warning on line 61 in contracts/BalanceTrackerFixedPriceBase.sol

View workflow job for this annotation

GitHub Actions / build

Immutable variables name are set to be in capitalized SNAKE_CASE
// Collected fees
uint256 public collectedFees;
// Reentrancy lock
Expand All @@ -82,7 +82,7 @@
buyBackBurner = _buyBackBurner;
}

function _checkNativeValue() internal virtual;
function _getOrRestrictNativeValue() internal virtual returns (uint256);

function _getRequiredFunds(address requester, uint256 balanceDiff) internal virtual returns (uint256);

Expand All @@ -92,26 +92,26 @@
address requester,
bytes memory
) external payable {
// Reentrancy guard
if (_locked > 1) {
revert ReentrancyGuard();
}
_locked = 2;

// Check for marketplace access
if (msg.sender != mechMarketplace) {
revert MarketplaceOnly(msg.sender, mechMarketplace);
}

// Check for native value
_checkNativeValue();
uint256 initAmount = _getOrRestrictNativeValue();

// Get account balance
uint256 balance = mapRequesterBalances[requester] + initAmount;

// Get mech max delivery rate
uint256 maxDeliveryRate = IMech(mech).maxDeliveryRate();

// Get account balance
uint256 balance = mapRequesterBalances[requester];

// Update balance with native value
if (msg.value > 0) {
balance += msg.value;
emit Deposit(msg.sender, address(0), msg.value);
}

// Check the request delivery rate for a fixed price
if (balance < maxDeliveryRate) {
// Get balance difference
Expand All @@ -127,6 +127,8 @@
// Adjust account balance
balance -= maxDeliveryRate;
mapRequesterBalances[requester] = balance;

_locked = 1;
}

/// @dev Finalizes mech delivery rate based on requested and actual ones.
Expand Down
9 changes: 8 additions & 1 deletion contracts/BalanceTrackerFixedPriceNative.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {BalanceTrackerFixedPriceBase, ZeroAddress, InsufficientBalance, TransferFailed} from "./BalanceTrackerFixedPriceBase.sol";

Check warning on line 4 in contracts/BalanceTrackerFixedPriceNative.sol

View workflow job for this annotation

GitHub Actions / build

imported name InsufficientBalance is not used
import {IMech} from "./interfaces/IMech.sol";

Check warning on line 5 in contracts/BalanceTrackerFixedPriceNative.sol

View workflow job for this annotation

GitHub Actions / build

imported name IMech is not used

interface IToken {
/// @dev Transfers the token amount.
Expand All @@ -18,7 +18,7 @@

contract BalanceTrackerFixedPriceNative is BalanceTrackerFixedPriceBase {
// Wrapped native token address
address public immutable wrappedNativeToken;

Check warning on line 21 in contracts/BalanceTrackerFixedPriceNative.sol

View workflow job for this annotation

GitHub Actions / build

Immutable variables name are set to be in capitalized SNAKE_CASE

/// @dev BalanceTrackerFixedPrice constructor.
/// @param _mechMarketplace Mech marketplace address.
Expand All @@ -35,7 +35,14 @@
wrappedNativeToken = _wrappedNativeToken;
}

function _checkNativeValue() internal virtual override {}
function _getOrRestrictNativeValue() internal virtual override returns (uint256) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is the current refactor of incoming payment.

// Update balance with native value
if (msg.value > 0) {
emit Deposit(msg.sender, address(0), msg.value);
}

return msg.value;
}

function _getRequiredFunds(address, uint256) internal virtual override returns (uint256) {
return 0;
Expand Down Expand Up @@ -67,7 +74,7 @@
}

// Deposits funds for requester.
receive() external payable {

Check warning on line 77 in contracts/BalanceTrackerFixedPriceNative.sol

View workflow job for this annotation

GitHub Actions / build

Fallback function must be simple
// Update account balances
mapRequesterBalances[msg.sender] += msg.value;

Expand Down
22 changes: 20 additions & 2 deletions contracts/BalanceTrackerFixedPriceToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity ^0.8.28;

import {BalanceTrackerFixedPriceBase, ZeroAddress, NoDepositAllowed, TransferFailed} from "./BalanceTrackerFixedPriceBase.sol";
import {IMech} from "./interfaces/IMech.sol";

Check warning on line 5 in contracts/BalanceTrackerFixedPriceToken.sol

View workflow job for this annotation

GitHub Actions / build

imported name IMech is not used

interface IToken {
/// @dev Transfers the token amount.
Expand All @@ -17,11 +17,16 @@
/// @param amount Amount to transfer to.
/// @return True if the function execution is successful.
function transferFrom(address from, address to, uint256 amount) external returns (bool);

/// @dev Gets the amount of tokens owned by a specified account.
/// @param account Account address.
/// @return Amount of tokens owned.
function balanceOf(address account) external view returns (uint256);
}

contract BalanceTrackerFixedPriceNative is BalanceTrackerFixedPriceBase {
// OLAS token address
address public immutable olas;

Check warning on line 29 in contracts/BalanceTrackerFixedPriceToken.sol

View workflow job for this annotation

GitHub Actions / build

Immutable variables name are set to be in capitalized SNAKE_CASE

/// @dev BalanceTrackerFixedPrice constructor.
/// @param _mechMarketplace Mech marketplace address.
Expand All @@ -38,16 +43,29 @@
olas = _olas;
}

function _checkNativeValue() internal virtual override {
function _getOrRestrictNativeValue() internal virtual override returns (uint256) {
// Check for msg.value
if (msg.value > 0) {
revert NoDepositAllowed(msg.value);
}

return 0;
}

function _getRequiredFunds(address requester, uint256 balanceDiff) internal virtual override returns (uint256) {
// TODO check balances before and after
uint256 balanceBefore = IToken(olas).balanceOf(address(this));
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Additional check, although with OLAS it's pretty much safe by default.

// Get tokens from requester
IToken(olas).transferFrom(requester, address(this), balanceDiff);
uint256 balanceAfter = IToken(olas).balanceOf(address(this));

// Check the balance
uint256 diff = balanceAfter - balanceBefore;
if (diff != balanceDiff) {
revert TransferFailed(olas, requester, address(this), balanceDiff);
}

emit Deposit(msg.sender, olas, balanceDiff);

return balanceDiff;
}

Expand Down
24 changes: 22 additions & 2 deletions contracts/MechFactoryFixedPriceNative.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,22 @@ import {MechFixedPriceNative} from "./MechFixedPriceNative.sol";
/// @param expected Expected data length.
error IncorrectDataLength(uint256 provided, uint256 expected);

/// @dev Only `marketplace` has a privilege, but the `sender` was provided.
/// @param sender Sender address.
/// @param marketplace Required marketplace address.
error MarketplaceOnly(address sender, address marketplace);

/// @dev Provided zero address.
error ZeroAddress();

/// @title Mech Factory Basic - Periphery smart contract for managing basic mech creation
contract MechFactoryFixedPriceNative {
event CreateFixedPriceMech(address indexed mech, uint256 indexed serviceId, uint256 maxDeliveryRate);

// Agent factory version number
string public constant VERSION = "0.1.0";
// Nonce
uint256 internal _nonce;

/// @dev Registers service as a mech.
/// @param mechMarketplace Mech marketplace address.
Expand All @@ -27,7 +37,10 @@ contract MechFactoryFixedPriceNative {
uint256 serviceId,
bytes memory payload
) external returns (address mech) {
// TODO: restrict all factories to be called from marketplace only - makes it easier to monitor the system
// Check for marketplace access
if (msg.sender != mechMarketplace) {
revert MarketplaceOnly(msg.sender, mechMarketplace);
}

// Check payload length
if (payload.length != 32) {
Expand All @@ -37,12 +50,19 @@ contract MechFactoryFixedPriceNative {
// Decode max delivery rate
uint256 maxDeliveryRate = abi.decode(payload, (uint256));

uint256 localNonce = _nonce;
// Get salt
bytes32 salt = keccak256(abi.encode(block.timestamp, msg.sender, serviceId));
bytes32 salt = keccak256(abi.encode(block.timestamp, msg.sender, serviceId, localNonce));
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Adding nonce as per audit suggestion

_nonce = localNonce + 1;

// Service multisig is isOperator() for the mech
mech = address((new MechFixedPriceNative){salt: salt}(mechMarketplace, serviceRegistry, serviceId, maxDeliveryRate));

// Check for zero address
if (mech == address(0)) {
revert ZeroAddress();
}

emit CreateFixedPriceMech(mech, serviceId, maxDeliveryRate);
}
}
24 changes: 23 additions & 1 deletion contracts/MechFactoryFixedPriceToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,22 @@ import {MechFixedPriceToken} from "./MechFixedPriceToken.sol";
/// @param expected Expected data length.
error IncorrectDataLength(uint256 provided, uint256 expected);

/// @dev Only `marketplace` has a privilege, but the `sender` was provided.
/// @param sender Sender address.
/// @param marketplace Required marketplace address.
error MarketplaceOnly(address sender, address marketplace);

/// @dev Provided zero address.
error ZeroAddress();

/// @title Mech Factory Basic - Periphery smart contract for managing basic mech creation
contract MechFactoryFixedPriceNative {
event CreateFixedPriceMech(address indexed mech, uint256 indexed serviceId, uint256 maxDeliveryRate);

// Agent factory version number
string public constant VERSION = "0.1.0";
// Nonce
uint256 internal _nonce;

/// @dev Registers service as a mech.
/// @param mechMarketplace Mech marketplace address.
Expand All @@ -27,6 +37,11 @@ contract MechFactoryFixedPriceNative {
uint256 serviceId,
bytes memory payload
) external returns (address mech) {
// Check for marketplace access
if (msg.sender != mechMarketplace) {
revert MarketplaceOnly(msg.sender, mechMarketplace);
}

// Check payload length
if (payload.length != 32) {
revert IncorrectDataLength(payload.length, 32);
Expand All @@ -35,12 +50,19 @@ contract MechFactoryFixedPriceNative {
// Decode max delivery rate
uint256 maxDeliveryRate = abi.decode(payload, (uint256));

uint256 localNonce = _nonce;
// Get salt
bytes32 salt = keccak256(abi.encode(block.timestamp, msg.sender, serviceId));
bytes32 salt = keccak256(abi.encode(block.timestamp, msg.sender, serviceId, localNonce));
_nonce = localNonce + 1;

// Service multisig is isOperator() for the mech
mech = address((new MechFixedPriceToken){salt: salt}(mechMarketplace, serviceRegistry, serviceId, maxDeliveryRate));

// Check for zero address
if (mech == address(0)) {
revert ZeroAddress();
}

emit CreateFixedPriceMech(mech, serviceId, maxDeliveryRate);
}
}
5 changes: 4 additions & 1 deletion contracts/MechFixedPriceNative.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@ import {OlasMech} from "./OlasMech.sol";

/// @title MechFixedPriceNative - Smart contract for OlasMech that accepts a fixed price payment for services in native token.
contract MechFixedPriceNative is OlasMech {
// keccak256(FixedPriceNative) = ba699a34be8fe0e7725e93dcbce1701b0211a8ca61330aaeb8a05bf2ec7abed1
bytes32 public constant PAYMENT_TYPE = 0xba699a34be8fe0e7725e93dcbce1701b0211a8ca61330aaeb8a05bf2ec7abed1;

/// @dev AgentMech constructor.
/// @param _mechMarketplace Mech marketplace address.
/// @param _serviceRegistry Address of the token contract.
/// @param _serviceId Service Id.
/// @param _maxDeliveryRate The maximum delivery rate.
constructor(address _mechMarketplace, address _serviceRegistry, uint256 _serviceId, uint256 _maxDeliveryRate)
OlasMech(_mechMarketplace, _serviceRegistry, _serviceId, _maxDeliveryRate, PaymentType.FixedPriceNative)
OlasMech(_mechMarketplace, _serviceRegistry, _serviceId, _maxDeliveryRate, PAYMENT_TYPE)
{}

/// @dev Performs actions before the delivery of a request.
Expand Down
Loading
Loading