Submitted on Mon Jul 22 2024 07:57:32 GMT-0400 (Atlantic Standard Time) by @Minato7namikazi for Attackathon | Fuel Network
There is Silent Stack overflow on variables between cross-contract calls can happen
In large codebases and within complex functions that have many cross-contract calls u256 variables can overflow and cause critical damages
Copy before: variable: 6000000000000000000000000000000000 (u256)
after: variable: 294731856024973518640372915683249701534862079315
this happened while playing with large sway codebase for an exchange project .. i'm literally submitting this at the last minute of the attackathon : D .. so this report will be continued with another minimized PoC in the comments section
Copy it("increasePosition acceptablePrice short", async () => {
await USDC.functions.mint(contrToAccount(vault), expandDecimals(8000)).call()
await vault.functions.buy_rusd(toAsset(USDC), addrToAccount(user1)).addContracts(attachedContracts).call()
await router.as(user0).functions.set_approved_plugins(toContract(positionRouterBPM), true).call()
await BNB.functions.mint(addrToAccount(user0), expandDecimals(2)).call()
await BNB.functions.mint(addrToAccount(deployer), expandDecimals(2)).call()
const amountIn = expandDecimals(2)
await expect(
positionRouter
.as(user0)
.multiCall([
utils.functions.transfer_assets_to_contract(toAsset(BNB), amountIn, toContract(positionRouter)).callParams({
forward: [amountIn, getAssetId(BNB)],
}),
positionRouter.functions
.increase_position(
[toAsset(BNB), toAsset(USDC)], // path
toAsset(BNB), // index_asset
amountIn, // amountIn
expandDecimals(1), // minOut
toUsd(6000), // size_delta
false, // is_long
toUsd(310), // acceptablePrice
referralCode, // referralCode
)
.addContracts(attachedContracts),
])
.call(),
).to.be.revertedWith("BPMMarkPriceLtPrice")
})
it("maxGlobalShortSize", async () => {
await USDC.functions.mint(contrToAccount(vault), expandDecimals(8000)).call()
await vault.functions.buy_rusd(toAsset(USDC), addrToAccount(user1)).addContracts(attachedContracts).call()
await positionRouterBPM.functions
.set_max_global_sizes([toAsset(BNB), toAsset(USDC)], [0, 0], [toUsd(5000), toUsd(10000)])
.addContracts(attachedContracts)
.call()
await router.as(user0).functions.set_approved_plugins(toContract(positionRouterBPM), true).call()
await BNB.functions.mint(addrToAccount(user0), expandDecimals(2)).call()
await BNB.functions.mint(addrToAccount(deployer), expandDecimals(2)).call()
const amountIn = expandDecimals(2)
const tx = positionRouter.as(user0).multiCall([
utils.functions.transfer_assets_to_contract(toAsset(BNB), amountIn, toContract(positionRouter)).callParams({
forward: [amountIn, getAssetId(BNB)],
}),
positionRouter.functions
.increase_position(
[toAsset(BNB), toAsset(USDC)], // path
toAsset(BNB), // index_asset
amountIn, // amountIn
expandDecimals(1), // minOut
toUsd(6000), // size_delta
false, // is_long
toUsd(290), // acceptablePrice
referralCode, // referralCode
)
.addContracts(attachedContracts),
])
await expect(tx.call()).to.be.revertedWith("BPMMaxShortsExceeded")
await positionRouterBPM.functions
.set_max_global_sizes([toAsset(BNB), toAsset(USDC)], [0, 0], [toUsd(6000), toUsd(10000)])
.addContracts(attachedContracts)
.call()
expect(await getValStr(vaultUtils.functions.get_global_short_sizes(toAsset(BNB)))).eq("0")
await tx.call()
expect(await getValStr(vaultUtils.functions.get_global_short_sizes(toAsset(BNB)))).eq(
"6000000000000000000000000000000000",
)
})