Marginswap contest - s1m0's results

Bringing margin trading to on-chain assets

General Information

Platform: Code4rena

Start Date: 02/04/2021

Pot Size: $50,000 USDC

Total HM: 20

Participants: 5

Period: 6 days

Judge: Zak Cole

Total Solo HM: 19

Id: 3

League: ETH

Marginswap

Findings Distribution

Researcher Performance

Rank: 4/5

Findings: 3

Award: $4,041.86

🌟 Selected for report: 3

🚀 Solo Findings: 1

Findings Information

🌟 Selected for report: gpersoon

Also found by: s1m0

Labels

bug
3 (High Risk)

Awards

2616.0889 USDC - $2,616.09

External Links

Handle

s1m0

Vulnerability details

Impact

The withdrawReward (https://github.com/code-423n4/marginswap/blob/main/contracts/IncentiveDistribution.sol#L224) fails due to the loop at https://github.com/code-423n4/marginswap/blob/main/contracts/IncentiveDistribution.sol#L269. From my testing the dayDiff would be 18724 and with a gasLimit of 9500000 it stops at iteration 270 due to the fact that lastUpdatedDay is not initialized so is 0. Other than that it could run out of gas also for the loop of allTranches (https://github.com/code-423n4/marginswap/blob/main/contracts/IncentiveDistribution.sol#L281) because it's an unbounded array.

Proof of Concept

This is a test with hardhat.

const { ethers } = require("hardhat");

describe("MarginSwap", function() { let IncentiveDistribution, incentiveDistribution; let owner;

before(async function() { [owner] = await ethers.getSigners(); IncentiveDistribution = await ethers.getContractFactory("IncentiveDistribution"); incentiveDistribution = await IncentiveDistribution.deploy(ethers.constants.AddressZero, 2); }); it("withdrawReward", async function() { await incentiveDistribution.initTranche(1, 23); await incentiveDistribution.addToClaimAmount(1, owner.address, 324234); await incentiveDistribution.withdrawReward([1], {gasLimit: 9500000}); });

});

Note: from the IncentiveDistribution contract i removed the inheritance of RoleAware and Ownable for convenience of testing and added some print with console.log() to check where it stops.

Tools Used

Manual analysis

I'm not sure of the logic behind the shrinking of the daily distribution but i think that maybe you just missed to initialize the lastUpdatedDay to the day of deployment? If that's the case it resolves partially the problem because allTranches is theoretically unbounded even though only the owner can add element to it and you should do deeply testing to understand how many elements it can have until it run out of gas. I read the comment that says you tried to shift the gas to the withdrawal people maybe you went too further and is it worth rethinking the design?

#0 - werg

2021-04-08T21:19:06Z

Exactly. we need to initialize lastUdpatedDay. Thanks for the report!

Findings Information

🌟 Selected for report: s1m0

Labels

bug
2 (Med Risk)

Awards

784.8267 USDC - $784.83

External Links

Handle

s1m0

Vulnerability details

Impact

Functions like setLeveragePercent and setLiquidationThresholdPercent for both IsolatedMarginTrading (https://github.com/code-423n4/marginswap/blob/main/contracts/IsolatedMarginTrading.sol) and CrossMarginTrading (https://github.com/code-423n4/marginswap/blob/main/contracts/CrossMarginTrading.sol) should be put behind a timelock because they would give more trust to users. Now the owner could call them whenever he wants and a position could become liquidable from a block to the other.

Proof of Concept

Tools Used

Manual analysis.

Add a timelock to setter functions of critical variables.

#0 - werg

2021-04-08T20:36:05Z

Timelock will be handled by governance

#1 - zscole

2021-04-22T15:30:03Z

Maintaining submission rating of 2 (Med Risk) because this presents a vulnerability at the time of review.

Findings Information

🌟 Selected for report: pauliax

Also found by: s1m0

Labels

bug
duplicate
1 (Low Risk)

Awards

117.724 USDC - $117.72

External Links

Email address

simomonica1997@gmail.com

Handle

s1m0

Eth address

0x9b3E9e3E4a174d59279FC7cd268e035992412384

Vulnerability details

The owner can initialize an already initialized tranche by calling setTranche https://github.com/code-423n4/marginswap/blob/main/contracts/IncentiveDistribution.sol#L78 with 0 as share argument and then calling initTranche https://github.com/code-423n4/marginswap/blob/main/contracts/IncentiveDistribution.sol#L101 bypassing the check require(tm.rewardShare == 0, "Tranche already initialized");

Recommended mitigation steps

Check share != 0 for setTrancheShare and initTranche

Impact

The state of the system would become not correct by inflating the allTranches variable and it would raise the gas cost for calling withdrawReward

Tools used

Manual analysis

Proof of concept

Assuming the 1 tranche is initialized.

  • call setTrancheShare(1, 0)
  • call initTranche(1, n)

#0 - zscole

2021-04-22T15:22:28Z

Duplicate of #35

Findings Information

🌟 Selected for report: s1m0

Labels

bug
1 (Low Risk)

Awards

261.6089 USDC - $261.61

External Links

Email address

simomonica1997@gmail.com

Handle

s1m0

Eth address

0x9b3E9e3E4a174d59279FC7cd268e035992412384

Vulnerability details

The constructor of IncentiveDistribution https://github.com/code-423n4/marginswap/blob/main/contracts/IncentiveDistribution.sol#L32 take as argument the address of MFI token but it doesn't check that is != address(0). Not worth an issue alone but IncentiveDistribution imports IERC20.sol and it never use it.

Impact

In case the address(0) is passed as arguement the withdrawReward woul fail https://github.com/code-423n4/marginswap/blob/main/contracts/IncentiveDistribution.sol#L261 and due to the fact that MFI is immutable the only solution would be to redeploy the contract meanwhile losing trust from the users.

Proof of concept

Deploy IncentiveDistribution with 0 as _MFI argument and then call withdrawReward.

Tools used

Manual analysis

Recommended mitigation steps

Check _MFI != address(0)

Findings Information

🌟 Selected for report: s1m0

Labels

bug
1 (Low Risk)

Awards

261.6089 USDC - $261.61

External Links

Email address

simomonica1997@gmail.com

Handle

s1m0

Eth address

0x9b3E9e3E4a174d59279FC7cd268e035992412384

Vulnerability details

When changing state variables events are not emitted. PriceAware (https://github.com/code-423n4/marginswap/blob/main/contracts/PriceAware.sol):

The events emitted by MarginRouter (https://github.com/code-423n4/marginswap/blob/main/contracts/MarginRouter.sol) don't have indexed parameter.

Proof of concept

Tools used

Manual analysis

Impact

The system doesn't record historical state changes.

Recommended mitigation steps

For set... function emit events with old and new value. For initTranche, event InitTranche(uint256 tranche, uint256 share) For activateIssuer, event ActivateIssuer(address issuer, address token) For deactivateIssuer, event DeactivateIssuer(address issuer) For events emitted by MarginRouter i would index the trader address to make it filterable.

#0 - werg

2021-04-08T21:24:38Z

We may sprinkle in a few more events before launch, but in the interest of gas savings we try not to emit events for state that can be queried using view functions.

#1 - zscole

2021-04-22T15:27:07Z

Reducing this from submitted rating of 2 (Med Risk) to 1 (Low Risk) since it presents no immediate risk to the security of the system, but could have implications on overall functionality.

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter