My Coding Journey: From Finance to Smart Contract Auditor

Thanks for sharing, Jarrod. This guy's hourly rate is insane!

It's quite amazing how there are so many different avenues to pursue in the cryptocurrency/blockchain space, right?

It's possible to find a niche and escape the rat race so well done to Christoph ..

My pleasure!

Agreed on his hourly rate, he still didn't seem happy with that rate it either! Very envious of his work and time in the field

1 Like

Day 122

I've slightly delayed going back to my DAO testing but speaking of testing.....I can't talk to the specifics of my process during this audit, but I'd love to share a cool tool I came across in a recent newsletter. It's called Create Chimera App and its a Foundry template that spins up boilerplate code to create invariant tests for Echidna, Medusa, and Foundry.

In real simple terms, when using these different tools for stateful or stateless testing, its a timely process to install each and make sure they are configured in such a way they provide a useful output. For example, to install Echidna you need to make sure Slither is correctly installed (which for me meant Python also had to be installed properly). Although this doesn't sound particularly difficult at a higher level, things might get complex (increasing the chance of user error) if you are also like me and use WSL: Ubuntu in VS Code instead of Windows. The aim of this tool is to simplify this process so we can focus on the actual audit.

I'll be sure to give a more fulsome review of the tool once I've finished and provide a comparison between the various tools I'd used!

1 Like

Day 123

A higher-level sequence of events leading to the Sonne Finance USD$20m hack is as follows:

  • Sonne Finance passed a proposal via their DAO to add VELO markets to the Sonne platform. In other words, Sonne Finance maintains a DAO whereby 1 native Sonne token equates to a vote of Velodrome Finance (VELO) which is an automated market maker (AMM);
  • this transaction was scheduled via a multi sig wallet (i.e. a smart contract-based wallet that requires two or more digital signatures to validate transactions) containing a delay feature known as a timelock;
  • once the 2 day delay ended, the exploiter executed four transactions to create fake markets and added fake collateral. This was able to occur because the newly upgraded Sonne feature was rolled out on BASE but was not reflected on the Optimism network;
  • the attacker tricked users into thinking the rollout was asynchronous; and
  • the attacker was able to exploit the protocol for ~$20M with the known donation attack.

Post mortem here

What is a donation attack?

  • it is a type of exploit where an attacker manipulates the exchange rate of assets within a protocol to borrow more assets than they should be able to;
  • this type of exploit was a real risk in the early days of Defi applications (look no further than early compound or Uniswap protocols) where common exploit challenges like Ethernaut or Damn Vulnerable Defi are mapped off these types of manipulations;
  • the reason this attack could even take place to begin with was because it took place on Compound v2 forks created by Sonne;
  • the controversy with this is that Compound v2 is one of those early Defi use cases whereby bugs are known and Sonne still decided to use it; and
  • for extra reading I recommend this blog that showcases how an attacker may, for example, steal funds of the initial lenders of a Compound market.

The donation attack play-by-play
Knowing all the above let’s put it together:

  • the attacker deployed a contract targeting the VELO contract in the Sonne Finance protocol;
  • the attacker created a new borrower contract, minted collateral tokens in an empty market, and redeemed most of these tokens;
  • the attacker donated the redeemed asset tokens back to the protocol (inflating the exchange rate);
  • Using the manipulated exchange rate, they borrowed a different asset;
  • the attacker redeemed the collateral to recover their donation; and
  • they liquidated the borrower contract position with the borrowed funds and redeemed the collateral token to reset the market.

I think the lesson here is to beware of legacy bugs in older protocols, get audited and ensure that a rollout of such an upgrade to a protocol will be done so such that it is consistent across various protocols like Optimism and BASE.

Day 124

I have finally done it!!!!!!

The test for my DAO successfully runs:

Ran 2 tests for test/MyGovernorTest.t.sol:MyGovernorTest
[PASS] testCantUpdateBoxWithoutGovernance() (gas: 10461)
Traces:
  [10461] MyGovernorTest::testCantUpdateBoxWithoutGovernance()
    β”œβ”€ [0] VM::expectRevert(custom error f4844814:)
    β”‚   └─ ← [Return] 
    β”œβ”€ [2424] Box::store(1)
    β”‚   └─ ← [Revert] OwnableUnauthorizedAccount(0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496)
    └─ ← [Stop] 

[PASS] testGovernanceUpdatesBox() (gas: 456491)
Logs:
  Proposal State: 0
  Proposal State: 1
  Proposal State: 4

Traces:
  [456491] MyGovernorTest::testGovernanceUpdatesBox()
    β”œβ”€ [49467] MyGovernor::propose([0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9], [0], [0x6057361d0000000000000000000000000000000000000000000000000000000000000309], "Store 777 in Box")
    β”‚   β”œβ”€ [427] GovToken::clock() [staticcall]
    β”‚   β”‚   └─ ← [Return] 1
    β”‚   β”œβ”€ [3078] GovToken::getPastVotes(MyGovernorTest: [0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496], 0) [staticcall]
    β”‚   β”‚   └─ ← [Return] 0
    β”‚   β”œβ”€ [427] GovToken::clock() [staticcall]
    β”‚   β”‚   └─ ← [Return] 1
    β”‚   β”œβ”€ emit ProposalCreated(proposalId: 110528346033244033460686721661256806643835137280393385735339785765368263982323 [1.105e77], proposer: MyGovernorTest: [0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496], targets: [0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9], values: [0], signatures: [""], calldatas: [0x6057361d0000000000000000000000000000000000000000000000000000000000000309], voteStart: 2, voteEnd: 3, description: "Store 777 in Box")
    β”‚   └─ ← [Return] 110528346033244033460686721661256806643835137280393385735339785765368263982323 [1.105e77]
    β”œβ”€ [2114] MyGovernor::state(110528346033244033460686721661256806643835137280393385735339785765368263982323 [1.105e77]) [staticcall]
    β”‚   β”œβ”€ [427] GovToken::clock() [staticcall]
    β”‚   β”‚   └─ ← [Return] 1
    β”‚   └─ ← [Return] 0
    β”œβ”€ [0] console::log("Proposal State:", 0) [staticcall]
    β”‚   └─ ← [Stop] 
    β”œβ”€ [0] VM::warp(3)
    β”‚   └─ ← [Return] 
    β”œβ”€ [0] VM::roll(3)
    β”‚   └─ ← [Return] 
    β”œβ”€ [2500] MyGovernor::state(110528346033244033460686721661256806643835137280393385735339785765368263982323 [1.105e77]) [staticcall]
    β”‚   β”œβ”€ [427] GovToken::clock() [staticcall]
    β”‚   β”‚   └─ ← [Return] 3
    β”‚   └─ ← [Return] 1
    β”œβ”€ [0] console::log("Proposal State:", 1) [staticcall]
    β”‚   └─ ← [Stop] 
    β”œβ”€ [0] VM::prank(0x0000000000000000000000000000000000000001)
    β”‚   └─ ← [Return] 
    β”œβ”€ [57927] MyGovernor::castVoteWithReason(110528346033244033460686721661256806643835137280393385735339785765368263982323 [1.105e77], 1, "I like to yeet")
    β”‚   β”œβ”€ [427] GovToken::clock() [staticcall]
    β”‚   β”‚   └─ ← [Return] 3
    β”‚   β”œβ”€ [5894] GovToken::getPastVotes(0x0000000000000000000000000000000000000001, 2) [staticcall]
    β”‚   β”‚   └─ ← [Return] 100000000000000000000 [1e20]
    β”‚   β”œβ”€ emit VoteCast(voter: 0x0000000000000000000000000000000000000001, proposalId: 110528346033244033460686721661256806643835137280393385735339785765368263982323 [1.105e77], support: 1, weight: 100000000000000000000 [1e20], reason: "I like to yeet")
    β”‚   └─ ← [Return] 100000000000000000000 [1e20]
    β”œβ”€ [0] VM::warp(50404 [5.04e4])
    β”‚   └─ ← [Return] 
    β”œβ”€ [0] VM::roll(50404 [5.04e4])
    β”‚   └─ ← [Return] 
    β”œβ”€ [20619] MyGovernor::state(110528346033244033460686721661256806643835137280393385735339785765368263982323 [1.105e77]) [staticcall]
    β”‚   β”œβ”€ [427] GovToken::clock() [staticcall]
    β”‚   β”‚   └─ ← [Return] 50404 [5.04e4]
    β”‚   β”œβ”€ [5747] GovToken::getPastTotalSupply(2) [staticcall]
    β”‚   β”‚   └─ ← [Return] 100000000000000000000 [1e20]
    β”‚   └─ ← [Return] 4
    β”œβ”€ [0] console::log("Proposal State:", 4) [staticcall]
    β”‚   └─ ← [Stop] 
    β”œβ”€ [101188] MyGovernor::queue([0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9], [0], [0x6057361d0000000000000000000000000000000000000000000000000000000000000309], 0x2a57622cced9a84b44988815c815e9798736ec46e20c34a83c8535295aa40cd6)
    β”‚   β”œβ”€ [427] GovToken::clock() [staticcall]
    β”‚   β”‚   └─ ← [Return] 50404 [5.04e4]
    β”‚   β”œβ”€ [1747] GovToken::getPastTotalSupply(2) [staticcall]
    β”‚   β”‚   └─ ← [Return] 100000000000000000000 [1e20]
    β”‚   β”œβ”€ [2402] TimeLock::getMinDelay() [staticcall]
    β”‚   β”‚   └─ ← [Return] 7200
    β”‚   β”œβ”€ [2488] TimeLock::hashOperationBatch([0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9], [0], [0x6057361d0000000000000000000000000000000000000000000000000000000000000309], 0x0000000000000000000000000000000000000000000000000000000000000000, 0xdc7f2bd56e6c1762572b1e1c47699960322c6e4ce20c34a83c8535295aa40cd6) [staticcall]
    β”‚   β”‚   └─ ← [Return] 0x4d7da09af07cb2706f6f74c9c6b790d4355ccec3d060b15b2dba55a14a37e942
    β”‚   β”œβ”€ [33562] TimeLock::scheduleBatch([0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9], [0], [0x6057361d0000000000000000000000000000000000000000000000000000000000000309], 0x0000000000000000000000000000000000000000000000000000000000000000, 0xdc7f2bd56e6c1762572b1e1c47699960322c6e4ce20c34a83c8535295aa40cd6, 7200)
    β”‚   β”‚   β”œβ”€ emit CallScheduled(id: 0x4d7da09af07cb2706f6f74c9c6b790d4355ccec3d060b15b2dba55a14a37e942, index: 0, target: Box: [0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9], value: 0, data: 0x6057361d0000000000000000000000000000000000000000000000000000000000000309, predecessor: 0x0000000000000000000000000000000000000000000000000000000000000000, delay: 7200)
    β”‚   β”‚   β”œβ”€ emit CallSalt(id: 0x4d7da09af07cb2706f6f74c9c6b790d4355ccec3d060b15b2dba55a14a37e942, salt: 0xdc7f2bd56e6c1762572b1e1c47699960322c6e4ce20c34a83c8535295aa40cd6)
    β”‚   β”‚   └─ ← [Stop] 
    β”‚   β”œβ”€ emit ProposalQueued(proposalId: 110528346033244033460686721661256806643835137280393385735339785765368263982323 [1.105e77], etaSeconds: 57604 [5.76e4])
    β”‚   └─ ← [Return] 110528346033244033460686721661256806643835137280393385735339785765368263982323 [1.105e77]
    β”œβ”€ [0] VM::roll(57605 [5.76e4])
    β”‚   └─ ← [Return] 
    β”œβ”€ [0] VM::warp(57605 [5.76e4])
    β”‚   └─ ← [Return] 
    β”œβ”€ [56301] MyGovernor::execute([0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9], [0], [0x6057361d0000000000000000000000000000000000000000000000000000000000000309], 0x2a57622cced9a84b44988815c815e9798736ec46e20c34a83c8535295aa40cd6)
    β”‚   β”œβ”€ [427] GovToken::clock() [staticcall]
    β”‚   β”‚   └─ ← [Return] 57605 [5.76e4]
    β”‚   β”œβ”€ [1747] GovToken::getPastTotalSupply(2) [staticcall]
    β”‚   β”‚   └─ ← [Return] 100000000000000000000 [1e20]
    β”‚   β”œβ”€ [734] TimeLock::isOperationPending(0x4d7da09af07cb2706f6f74c9c6b790d4355ccec3d060b15b2dba55a14a37e942) [staticcall]
    β”‚   β”‚   └─ ← [Return] true
    β”‚   β”œβ”€ [38310] TimeLock::executeBatch([0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9], [0], [0x6057361d0000000000000000000000000000000000000000000000000000000000000309], 0x0000000000000000000000000000000000000000000000000000000000000000, 0xdc7f2bd56e6c1762572b1e1c47699960322c6e4ce20c34a83c8535295aa40cd6)
    β”‚   β”‚   β”œβ”€ [25531] Box::store(777)
    β”‚   β”‚   β”‚   β”œβ”€ emit numberChanged(newNumber: 777)
    β”‚   β”‚   β”‚   └─ ← [Stop] 
    β”‚   β”‚   β”œβ”€ emit CallExecuted(id: 0x4d7da09af07cb2706f6f74c9c6b790d4355ccec3d060b15b2dba55a14a37e942, index: 0, target: Box: [0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9], value: 0, data: 0x6057361d0000000000000000000000000000000000000000000000000000000000000309)
    β”‚   β”‚   └─ ← [Stop] 
    β”‚   β”œβ”€ emit ProposalExecuted(proposalId: 110528346033244033460686721661256806643835137280393385735339785765368263982323 [1.105e77])
    β”‚   └─ ← [Return] 110528346033244033460686721661256806643835137280393385735339785765368263982323 [1.105e77]
    └─ ← [Stop] 

Suite result: ok. 2 passed; 0 failed; 0 skipped; finished in 1.63ms (740.79Β΅s CPU time)

If you'll remember, the first error I was required to solve it was: GovernorInsufficientProposerVotes(0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496, 0, 10000000000000000000 [1e19]). I stripped it back to basics and started looking through the Governor contract that myGovernor contract inherited from, and I found the error parameters as follows: revert GovernorInsufficientProposerVotes(proposer, proposerVotes, votesThreshold);

When I had previously read the above, I had inadvertently flipped the parameters at the end. This meant that I was trying to look for ways to mint users tokens when really I should have been looking to decrease the voting threshold. So I turned back to my Governor contract and amended the setting such that the voting threshold at the end was set to 0:GovernorSettings(7200 /* 1 day */, 50400 /* 1 week */, 0)

The way this feature now works is that any user can vote irrespective of their token holdings. The obvious flaw being anyone can vote but I will be sure to change this in due course.

After this test passed I was met with this error:

[233924] MyGovernorTest::testGovernanceUpdatesBox()
    β”œβ”€ [49467] MyGovernor::propose([0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9], [0], [0x6057361d0000000000000000000000000000000000000000000000000000000000000309], "Store 777 in Box")
    β”‚   β”œβ”€ [427] GovToken::clock() [staticcall]
    β”‚   β”‚   └─ ← [Return] 1
    β”‚   β”œβ”€ [3078] GovToken::getPastVotes(MyGovernorTest: [0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496], 0) [staticcall]
    β”‚   β”‚   └─ ← [Return] 0
    β”‚   β”œβ”€ [427] GovToken::clock() [staticcall]
    β”‚   β”‚   └─ ← [Return] 1
    β”‚   β”œβ”€ emit ProposalCreated(proposalId: 110528346033244033460686721661256806643835137280393385735339785765368263982323 [1.105e77], proposer: MyGovernorTest: [0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496], targets: [0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9], values: [0], signatures: [""], calldatas: [0x6057361d0000000000000000000000000000000000000000000000000000000000000309], voteStart: 7201, voteEnd: 57601 [5.76e4], description: "Store 777 in Box")
    β”‚   └─ ← [Return] 110528346033244033460686721661256806643835137280393385735339785765368263982323 [1.105e77]
    β”œβ”€ [2114] MyGovernor::state(110528346033244033460686721661256806643835137280393385735339785765368263982323 [1.105e77]) [staticcall]
    β”‚   β”œβ”€ [427] GovToken::clock() [staticcall]
    β”‚   β”‚   └─ ← [Return] 1
    β”‚   └─ ← [Return] 0
    β”œβ”€ [0] console::log("Proposal State:", 0) [staticcall]
    β”‚   └─ ← [Stop] 
    β”œβ”€ [0] VM::warp(3)
    β”‚   └─ ← [Return] 
    β”œβ”€ [0] VM::roll(3)
    β”‚   └─ ← [Return] 
    β”œβ”€ [2114] 
MyGovernor::state(110528346033244033460686721661256806643835137280393385735339785765368263982323 [1.105e77]) [staticcall]
    β”‚   β”œβ”€ [427] GovToken::clock() [staticcall]
    β”‚   β”‚   └─ ← [Return] 3
    β”‚   └─ ← [Return] 0
    β”œβ”€ [0] console::log("Proposal State:", 0) [staticcall]
    β”‚   └─ ← [Stop] 
    β”œβ”€ [0] VM::prank(0x0000000000000000000000000000000000000001)
    β”‚   └─ ← [Return] 
    β”œβ”€ [3044] MyGovernor::castVoteWithReason(110528346033244033460686721661256806643835137280393385735339785765368263982323 [1.105e77], 1, "I like to yeet")
    β”‚   β”œβ”€ [427] GovToken::clock() [staticcall]
    β”‚   β”‚   └─ ← [Return] 3
    β”‚   └─ ← [Revert] GovernorUnexpectedProposalState(110528346033244033460686721661256806643835137280393385735339785765368263982323 [1.105e77], 0, 0x0000000000000000000000000000000000000000000000000000000000000002)
    └─ ← [Revert] GovernorUnexpectedProposalState(110528346033244033460686721661256806643835137280393385735339785765368263982323 [1.105e77], 0, 0x0000000000000000000000000000000000000000000000000000000000000002)

Noting that the error we are concern about is the GovernorUnexpectedProposalState at the bottom. As a result, I looked to the contracts being inherited by the Governor contract and found its parameters: error GovernorUnexpectedProposalState(uint256 proposalId, ProposalState current, bytes32 expectedStates);
I noticed the dev note above the error function:
The current state of a proposal is not the required for performing an operation. The expectedStates is a bitmap with the bits enabled for each ProposalState enum position counting from right to left.

This means we need to look to the enum position to see what’s going on with the bitmap (the last line of my test output). You’ll note that it ends in 02 meaning position two reading right from left and it is noting the status as expired. So I went back to the Governor settings and removed any sort of delay to ensure the test runs and it did such that: GovernorSettings(,, 0)

I can also appreciate that the amendment to these settings will mean there is no delay to proposals, so I will be turning back to the logic in my smart contracts once again. In the interim to going back over the contracts, I am taking the win and recognising this is a real tough test but my god it was satisfying to see that test run correctly. Thanks everyone for your patience whilst I solved for this one!!

1 Like

Day 125

I only discovered Predy Finance’s exploit (costing ~USD$460k) recently so let’s unpack it. For context, Predy Finance a DEX for perpetual trading (a derivative contract that allows speculation of an assets future price without an expiration date) and token swaps.
Postmortem Report can be found here.

What happened?

  1. An attacker contract was created;
  2. The contract added a new pair to the DEX pool similar to an existing pair (non-bridged USDC and wrapped ETH) – this was allowed and done via PredyPool.registerPair and PredyPool.registerPair;
  3. Provided the attacker has complete control over this crypto pair it has created, the trade function can be executed which executes TradeLogic.trade;
  4. This also calls to TradeLogic.callTradeAfterCallback but the attack contract is also called within this callback function;
  5. The practical effect of this is when the attack contract calls the PredyPool.take function, it specifies the amount of USDC in Predy Pool which is transferred to the Attacker Contract (noting this is the same amount as that contained in the legitimately similar training pair of USDC and wrapped ETH existing);
  6. The Attacker then calls PredyPool.supply, supplying the amount of USDC obtained by the take function to pair id 3 – this is the key point here because it is also done for wrapped ETH and the logic of the smart contract dictates that this is a normal transaction provided there is no difference in the amounts between the pools; and
  7. Finally, the attacker calls the withdraw function.

A cool diagram from the post-mortem is as follows:

Takeaways

I did wonder whether the following two security measures would be safe:

  • To ensure that not just anyone can create trading pairs, whether a KYC measure can ensure that a person’s identity may be known. This would also ensure that a malicious actor is identified more promptly given their identity is recorded to the database; and
  • If the above is not suitable, delay features implemented on creation of pairs or withdrawal. I’m conscious that a delay on the withdrawal function could be problematic for consumers. However, I do think the delay on the creation of pairs would allow the nodes to properly validate whether new trading pairs may abuse the inherit logic of the platform.

Sidenote

The post mortem for Bloom came out (I briefly went over on Day 120) ...2 days late from promised so I thought it must be a comprehensive report: see it here.

To round off that Day 120 analysis: the timestamp variable that updates a traders position was not updated properly, allowing an attacker to continuously withdraw USDB equivalent amounts of accrued yield on their positions.

In terms of breaking down the attack this report was underwhelming. However, I do think a positive is to further talks with the relevant auditing firm (Zellic) and take proactive measures to integrate better real-time detection systems with trusted third party providers.

2 Likes

Day 126

I have not forgotten about my Crytpohack challenges (see Day 113)! I have completed the introduction challenges via VS Code in WSL: Ubuntu.

Install python3 and be sure to run the following code for your first flag:


import sys

# import this

if sys.version_info.major == 2:

print("You are running Python 2, which is no longer supported. Please update to Python 3.")

ords = [81, 64, 75, 66, 70, 93, 73, 72, 1, 92, 109, 2, 84, 109, 66, 75, 70, 90, 2, 92, 79]

print("Here is your flag:")

print("".join(chr(o ^ 0x32) for o in ords))

This challenge ensures Python3 is being run by checking the system version of Python currently running, noting an error is flagged should you be using Python 2. The array of integers represents ASCII characters (with ASCII being a 7-bit encoding standard which allows the representation of text using the integers 0-127).

The line ("".join(chr(o ^ 0x32) for o in ords)) looks to each integer and converts to their corresponding ASCII characters via the chr(o ^ 32) portion of code noting for o in ords is doing this for each number in the array.

The flag I received for this challenge was: crypto{z3n_0f_pyth0n}

The second challenge also builds off this knowledge by providing the following array:

[99, 114, 121, 112, 116, 111, 123, 65, 83, 67, 73, 73, 95, 112, 114, 49, 110, 116, 52, 98, 108, 51, 125]

and providing the following hint: In Python, the chr() function can be used to convert an ASCII ordinal number to a character (the ord() function does the opposite).

The above hint made me think that each character is represented by an integer. As such using print(chr(99)) would provide the output for 99 (being β€˜c’). I did think there would have to be a faster way than individually going through each integer so I created the following script to cycle through the integers converting each to their respective characters, giving me the flag:


print("Here is your flag:")

for o in ords:

print(chr(o))

The flag I received was: crypto{ASCII_pr1nt4bl3} (note: this is printed vertically because I didn’t specify a format for the output).

You may be asking why are we worrying about ASCII? Well naturally the next step when encrypting data is what do you use when you can’t convert a character via ASCII or someone is using a different system to you so it can’t read those same bytes? Enter Hexadecimal.

This type of encoding can be used to represent ASCII strings. Again, building off the previous challenges, Hexadecimal strings convert ASCII characters (like the last challenge) but then go the step further of converting these to base-16 numbers (i.e. hexadecimal). I thought this clarified how a hash is represented (i.e. it is a deterministic hexadecimal number). This means that no matter how many characters the input has, the hash will always be the same number of characters.

In this challenge we are provided with the following hex: 63727970746f7b596f755f77696c6c5f62655f776f726b696e675f776974685f6865785f737472696e67735f615f6c6f747d

In Python there is a bytes.fromhex() function to convert hex to bytes. As a result I created the following:


hex = bytes.fromhex('63727970746f7b596f755f77696c6c5f62655f776f726b696e675f776974685f6865785f737472696e67735f615f6c6f747d')

print(hex)

The flag printed was: crypto{You_will_be_working_with_hex_strings_a_lot}

Day 127

Debugging my previously created DAO was super satisfying and is a skill I want to refine even further. So I’ve decided to revisit previous projects with the intention to further refine them and build a more comprehensive testing suite (in between audits ofc!).

The first project I will be starting with is my Defi Stablecoin. The failed testing results are as follows (you can see that of my 6 tests, 4 fail):

Ran 6 tests for test/unit/DSCEngineTest.t.sol:DSCEngineTest
[FAIL. Reason: assertion failed] testCanDepositCollateralAndGetAccountInfo() (gas: 133857)
Logs:
  Error: a == b not satisfied [uint]
        Left: 2000000000000000000000000000000
       Right: 0

Traces:
  [10556084] DSCEngineTest::setUp()
    β”œβ”€ [4763996] β†’ new DeployDSC@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f
    β”‚   └─ ← [Return] 23571 bytes of code
    β”œβ”€ [5591843] DeployDSC::run()
    β”‚   β”œβ”€ [3752859] β†’ new HelperConfig@0x104fBc016F4bb334D775a19E8A6510109AC63E00
    β”‚   β”‚   β”œβ”€ [0] VM::startBroadcast()
    β”‚   β”‚   β”‚   └─ ← [Return] 
    β”‚   β”‚   β”œβ”€ [372255] β†’ new MockV3Aggregator@0x90193C961A926261B756D1E5bb255e67ff9498A1
    β”‚   β”‚   β”‚   └─ ← [Return] 1082 bytes of code
    β”‚   β”‚   β”œβ”€ [658696] β†’ new ERC20Mock@0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496
    β”‚   β”‚   β”‚   β”œβ”€ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: DeployDSC: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], value: 100000000000 [1e11])
    β”‚   β”‚   β”‚   └─ ← [Return] 2828 bytes of code
    β”‚   β”‚   β”œβ”€ [372255] β†’ new MockV3Aggregator@0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3
    β”‚   β”‚   β”‚   └─ ← [Return] 1082 bytes of code
    β”‚   β”‚   β”œβ”€ [658696] β†’ new ERC20Mock@0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76
    β”‚   β”‚   β”‚   β”œβ”€ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: DeployDSC: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], value: 100000000000 [1e11])
    β”‚   β”‚   β”‚   └─ ← [Return] 2828 bytes of code
    β”‚   β”‚   β”œβ”€ [0] VM::stopBroadcast()
    β”‚   β”‚   β”‚   └─ ← [Return] 
    β”‚   β”‚   └─ ← [Return] 6893 bytes of code
    β”‚   β”œβ”€ [934] HelperConfig::activeNetworkConfig() [staticcall]
    β”‚   β”‚   └─ ← [Return] MockV3Aggregator: [0x90193C961A926261B756D1E5bb255e67ff9498A1], MockV3Aggregator: [0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3], ERC20Mock: [0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496], ERC20Mock: [0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76], 77814517325470205911140941194401928579557062014761831930645393041380819009408 [7.781e76]
    β”‚   β”œβ”€ [0] VM::startBroadcast(<pk>)
    β”‚   β”‚   └─ ← [Return] 
    β”‚   β”œβ”€ [749823] β†’ new DecentralisedStableCoin@0x5FbDB2315678afecb367f032d93F642f64180aa3
    β”‚   β”‚   β”œβ”€ emit OwnershipTransferred(previousOwner: 0x0000000000000000000000000000000000000000, newOwner: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266)
    β”‚   β”‚   └─ ← [Return] 3401 bytes of code
    β”‚   β”œβ”€ [848361] β†’ new DSCEngine@0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
    β”‚   β”‚   └─ ← [Return] 3559 bytes of code
    β”‚   β”œβ”€ [2446] DecentralisedStableCoin::transferOwnership(DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512])
    β”‚   β”‚   β”œβ”€ emit OwnershipTransferred(previousOwner: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, newOwner: DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512])
    β”‚   β”‚   └─ ← [Stop] 
    β”‚   β”œβ”€ [0] VM::stopBroadcast()
    β”‚   β”‚   └─ ← [Return] 
    β”‚   └─ ← [Return] DecentralisedStableCoin: [0x5FbDB2315678afecb367f032d93F642f64180aa3], DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512], HelperConfig: [0x104fBc016F4bb334D775a19E8A6510109AC63E00]
    β”œβ”€ [934] HelperConfig::activeNetworkConfig() [staticcall]
    β”‚   └─ ← [Return] MockV3Aggregator: [0x90193C961A926261B756D1E5bb255e67ff9498A1], MockV3Aggregator: [0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3], ERC20Mock: [0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496], ERC20Mock: [0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76], 77814517325470205911140941194401928579557062014761831930645393041380819009408 [7.781e76]
    β”œβ”€ [24728] ERC20Mock::mint(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], 10000000000000000000 [1e19])
    β”‚   β”œβ”€ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], value: 10000000000000000000 [1e19])
    β”‚   └─ ← [Stop] 
    └─ ← [Stop] 

  [133857] DSCEngineTest::testCanDepositCollateralAndGetAccountInfo()
    β”œβ”€ [0] VM::startPrank(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D])
    β”‚   └─ ← [Return] 
    β”œβ”€ [24651] ERC20Mock::approve(DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512], 10000000000000000000 [1e19])
    β”‚   β”œβ”€ emit Approval(owner: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], spender: DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512], value: 10000000000000000000 [1e19])
    β”‚   └─ ← [Return] true
    β”œβ”€ [65083] DSCEngine::depositCollateral(ERC20Mock: [0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496], 10000000000000000000 [1e19])
    β”‚   β”œβ”€ emit CollateralDeposited(user: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], token: ERC20Mock: [0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496], amount: 10000000000000000000 [1e19])
    β”‚   β”œβ”€ [32489] ERC20Mock::transferFrom(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512], 10000000000000000000 [1e19])
    β”‚   β”‚   β”œβ”€ emit Approval(owner: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], spender: DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512], value: 0)
    β”‚   β”‚   β”œβ”€ emit Transfer(from: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], to: DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512], value: 10000000000000000000 [1e19])
    β”‚   β”‚   └─ ← [Return] true
    β”‚   └─ ← [Stop] 
    β”œβ”€ [0] VM::stopPrank()
    β”‚   └─ ← [Return] 
    β”œβ”€ [39797] DSCEngine::getAccountInformation(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D]) [staticcall]
    β”‚   β”œβ”€ [8993] MockV3Aggregator::latestRoundData() [staticcall]
    β”‚   β”‚   └─ ← [Return] 1, 200000000000 [2e11], 1, 1, 1
    β”‚   β”œβ”€ [8993] MockV3Aggregator::latestRoundData() [staticcall]
    β”‚   β”‚   └─ ← [Return] 1, 100000000000 [1e11], 1, 1, 1
    β”‚   └─ ← [Return] 0, 2000000000000000000000000000000 [2e30]
    β”œβ”€ [2457] DSCEngine::getTokenAmountFromUsd(ERC20Mock: [0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496], 2000000000000000000000000000000 [2e30]) [staticcall]
    β”‚   β”œβ”€ [993] MockV3Aggregator::latestRoundData() [staticcall]
    β”‚   β”‚   └─ ← [Return] 1, 200000000000 [2e11], 1, 1, 1
    β”‚   └─ ← [Return] 0
    β”œβ”€ emit log(val: "Error: a == b not satisfied [uint]")
    β”œβ”€ emit log_named_uint(key: "      Left", val: 2000000000000000000000000000000 [2e30])
    β”œβ”€ emit log_named_uint(key: "     Right", val: 0)
    β”œβ”€ [0] VM::store(VM: [0x7109709ECfa91a80626fF3989D68f67F5b1DD12D], 0x6661696c65640000000000000000000000000000000000000000000000000000, 0x0000000000000000000000000000000000000000000000000000000000000001)
    β”‚   └─ ← [Return] 
    └─ ← [Stop] 

[FAIL. Reason: assertion failed] testGetTokenAmountFromUsd() (gas: 36910)
Logs:
  Error: a == b not satisfied [uint]
        Left: 0
       Right: 50000000000000000

Traces:
  [10556084] DSCEngineTest::setUp()
    β”œβ”€ [4763996] β†’ new DeployDSC@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f
    β”‚   └─ ← [Return] 23571 bytes of code
    β”œβ”€ [5591843] DeployDSC::run()
    β”‚   β”œβ”€ [3752859] β†’ new HelperConfig@0x104fBc016F4bb334D775a19E8A6510109AC63E00
    β”‚   β”‚   β”œβ”€ [0] VM::startBroadcast()
    β”‚   β”‚   β”‚   └─ ← [Return] 
    β”‚   β”‚   β”œβ”€ [372255] β†’ new MockV3Aggregator@0x90193C961A926261B756D1E5bb255e67ff9498A1
    β”‚   β”‚   β”‚   └─ ← [Return] 1082 bytes of code
    β”‚   β”‚   β”œβ”€ [658696] β†’ new ERC20Mock@0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496
    β”‚   β”‚   β”‚   β”œβ”€ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: DeployDSC: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], value: 100000000000 [1e11])
    β”‚   β”‚   β”‚   └─ ← [Return] 2828 bytes of code
    β”‚   β”‚   β”œβ”€ [372255] β†’ new MockV3Aggregator@0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3
    β”‚   β”‚   β”‚   └─ ← [Return] 1082 bytes of code
    β”‚   β”‚   β”œβ”€ [658696] β†’ new ERC20Mock@0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76
    β”‚   β”‚   β”‚   β”œβ”€ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: DeployDSC: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], value: 100000000000 [1e11])
    β”‚   β”‚   β”‚   └─ ← [Return] 2828 bytes of code
    β”‚   β”‚   β”œβ”€ [0] VM::stopBroadcast()
    β”‚   β”‚   β”‚   └─ ← [Return] 
    β”‚   β”‚   └─ ← [Return] 6893 bytes of code
    β”‚   β”œβ”€ [934] HelperConfig::activeNetworkConfig() [staticcall]
    β”‚   β”‚   └─ ← [Return] MockV3Aggregator: [0x90193C961A926261B756D1E5bb255e67ff9498A1], MockV3Aggregator: [0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3], ERC20Mock: [0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496], ERC20Mock: [0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76], 77814517325470205911140941194401928579557062014761831930645393041380819009408 [7.781e76]
    β”‚   β”œβ”€ [0] VM::startBroadcast(<pk>)
    β”‚   β”‚   └─ ← [Return] 
    β”‚   β”œβ”€ [749823] β†’ new DecentralisedStableCoin@0x5FbDB2315678afecb367f032d93F642f64180aa3
    β”‚   β”‚   β”œβ”€ emit OwnershipTransferred(previousOwner: 0x0000000000000000000000000000000000000000, newOwner: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266)
    β”‚   β”‚   └─ ← [Return] 3401 bytes of code
    β”‚   β”œβ”€ [848361] β†’ new DSCEngine@0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
    β”‚   β”‚   └─ ← [Return] 3559 bytes of code
    β”‚   β”œβ”€ [2446] DecentralisedStableCoin::transferOwnership(DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512])
    β”‚   β”‚   β”œβ”€ emit OwnershipTransferred(previousOwner: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, newOwner: DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512])
    β”‚   β”‚   └─ ← [Stop] 
    β”‚   β”œβ”€ [0] VM::stopBroadcast()
    β”‚   β”‚   └─ ← [Return] 
    β”‚   └─ ← [Return] DecentralisedStableCoin: [0x5FbDB2315678afecb367f032d93F642f64180aa3], DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512], HelperConfig: [0x104fBc016F4bb334D775a19E8A6510109AC63E00]
    β”œβ”€ [934] HelperConfig::activeNetworkConfig() [staticcall]
    β”‚   └─ ← [Return] MockV3Aggregator: [0x90193C961A926261B756D1E5bb255e67ff9498A1], MockV3Aggregator: [0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3], ERC20Mock: [0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496], ERC20Mock: [0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76], 77814517325470205911140941194401928579557062014761831930645393041380819009408 [7.781e76]
    β”œβ”€ [24728] ERC20Mock::mint(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], 10000000000000000000 [1e19])
    β”‚   β”œβ”€ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], value: 10000000000000000000 [1e19])
    β”‚   └─ ← [Stop] 
    └─ ← [Stop] 

  [36910] DSCEngineTest::testGetTokenAmountFromUsd()
    β”œβ”€ [14957] DSCEngine::getTokenAmountFromUsd(ERC20Mock: [0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496], 100000000000000000000 [1e20]) [staticcall]
    β”‚   β”œβ”€ [8993] MockV3Aggregator::latestRoundData() [staticcall]
    β”‚   β”‚   └─ ← [Return] 1, 200000000000 [2e11], 1, 1, 1
    β”‚   └─ ← [Return] 0
    β”œβ”€ emit log(val: "Error: a == b not satisfied [uint]")
    β”œβ”€ emit log_named_uint(key: "      Left", val: 0)
    β”œβ”€ emit log_named_uint(key: "     Right", val: 50000000000000000 [5e16])
    β”œβ”€ [0] VM::store(VM: [0x7109709ECfa91a80626fF3989D68f67F5b1DD12D], 0x6661696c65640000000000000000000000000000000000000000000000000000, 0x0000000000000000000000000000000000000000000000000000000000000001)
    β”‚   └─ ← [Return] 
    └─ ← [Stop] 

[FAIL. Reason: assertion failed] testGetUsdValue() (gas: 36998)
Logs:
  Error: a == b not satisfied [uint]
        Left: 30000000000000000000000
       Right: 3000000000000000000000000000000

Traces:
  [10556084] DSCEngineTest::setUp()
    β”œβ”€ [4763996] β†’ new DeployDSC@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f
    β”‚   └─ ← [Return] 23571 bytes of code
    β”œβ”€ [5591843] DeployDSC::run()
    β”‚   β”œβ”€ [3752859] β†’ new HelperConfig@0x104fBc016F4bb334D775a19E8A6510109AC63E00
    β”‚   β”‚   β”œβ”€ [0] VM::startBroadcast()
    β”‚   β”‚   β”‚   └─ ← [Return] 
    β”‚   β”‚   β”œβ”€ [372255] β†’ new MockV3Aggregator@0x90193C961A926261B756D1E5bb255e67ff9498A1
    β”‚   β”‚   β”‚   └─ ← [Return] 1082 bytes of code
    β”‚   β”‚   β”œβ”€ [658696] β†’ new ERC20Mock@0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496
    β”‚   β”‚   β”‚   β”œβ”€ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: DeployDSC: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], value: 100000000000 [1e11])
    β”‚   β”‚   β”‚   └─ ← [Return] 2828 bytes of code
    β”‚   β”‚   β”œβ”€ [372255] β†’ new MockV3Aggregator@0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3
    β”‚   β”‚   β”‚   └─ ← [Return] 1082 bytes of code
    β”‚   β”‚   β”œβ”€ [658696] β†’ new ERC20Mock@0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76
    β”‚   β”‚   β”‚   β”œβ”€ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: DeployDSC: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], value: 100000000000 [1e11])
    β”‚   β”‚   β”‚   └─ ← [Return] 2828 bytes of code
    β”‚   β”‚   β”œβ”€ [0] VM::stopBroadcast()
    β”‚   β”‚   β”‚   └─ ← [Return] 
    β”‚   β”‚   └─ ← [Return] 6893 bytes of code
    β”‚   β”œβ”€ [934] HelperConfig::activeNetworkConfig() [staticcall]
    β”‚   β”‚   └─ ← [Return] MockV3Aggregator: [0x90193C961A926261B756D1E5bb255e67ff9498A1], MockV3Aggregator: [0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3], ERC20Mock: [0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496], ERC20Mock: [0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76], 77814517325470205911140941194401928579557062014761831930645393041380819009408 [7.781e76]
    β”‚   β”œβ”€ [0] VM::startBroadcast(<pk>)
    β”‚   β”‚   └─ ← [Return] 
    β”‚   β”œβ”€ [749823] β†’ new DecentralisedStableCoin@0x5FbDB2315678afecb367f032d93F642f64180aa3
    β”‚   β”‚   β”œβ”€ emit OwnershipTransferred(previousOwner: 0x0000000000000000000000000000000000000000, newOwner: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266)
    β”‚   β”‚   └─ ← [Return] 3401 bytes of code
    β”‚   β”œβ”€ [848361] β†’ new DSCEngine@0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
    β”‚   β”‚   └─ ← [Return] 3559 bytes of code
    β”‚   β”œβ”€ [2446] DecentralisedStableCoin::transferOwnership(DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512])
    β”‚   β”‚   β”œβ”€ emit OwnershipTransferred(previousOwner: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, newOwner: DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512])
    β”‚   β”‚   └─ ← [Stop] 
    β”‚   β”œβ”€ [0] VM::stopBroadcast()
    β”‚   β”‚   └─ ← [Return] 
    β”‚   └─ ← [Return] DecentralisedStableCoin: [0x5FbDB2315678afecb367f032d93F642f64180aa3], DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512], HelperConfig: [0x104fBc016F4bb334D775a19E8A6510109AC63E00]
    β”œβ”€ [934] HelperConfig::activeNetworkConfig() [staticcall]
    β”‚   └─ ← [Return] MockV3Aggregator: [0x90193C961A926261B756D1E5bb255e67ff9498A1], MockV3Aggregator: [0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3], ERC20Mock: [0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496], ERC20Mock: [0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76], 77814517325470205911140941194401928579557062014761831930645393041380819009408 [7.781e76]
    β”œβ”€ [24728] ERC20Mock::mint(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], 10000000000000000000 [1e19])
    β”‚   β”œβ”€ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], value: 10000000000000000000 [1e19])
    β”‚   └─ ← [Stop] 
    └─ ← [Stop] 

  [36998] DSCEngineTest::testGetUsdValue()
    β”œβ”€ [15011] DSCEngine::getUsdValue(ERC20Mock: [0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496], 15000000000000000000 [1.5e19]) [staticcall]
    β”‚   β”œβ”€ [8993] MockV3Aggregator::latestRoundData() [staticcall]
    β”‚   β”‚   └─ ← [Return] 1, 200000000000 [2e11], 1, 1, 1
    β”‚   └─ ← [Return] 3000000000000000000000000000000 [3e30]
    β”œβ”€ emit log(val: "Error: a == b not satisfied [uint]")
    β”œβ”€ emit log_named_uint(key: "      Left", val: 30000000000000000000000 [3e22])
    β”œβ”€ emit log_named_uint(key: "     Right", val: 3000000000000000000000000000000 [3e30])
    β”œβ”€ [0] VM::store(VM: [0x7109709ECfa91a80626fF3989D68f67F5b1DD12D], 0x6661696c65640000000000000000000000000000000000000000000000000000, 0x0000000000000000000000000000000000000000000000000000000000000001)
    β”‚   └─ ← [Return] 
    └─ ← [Stop] 

[PASS] testRevertsIfCollateralZero() (gas: 41386)
Traces:
  [10556084] DSCEngineTest::setUp()
    β”œβ”€ [4763996] β†’ new DeployDSC@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f
    β”‚   └─ ← [Return] 23571 bytes of code
    β”œβ”€ [5591843] DeployDSC::run()
    β”‚   β”œβ”€ [3752859] β†’ new HelperConfig@0x104fBc016F4bb334D775a19E8A6510109AC63E00
    β”‚   β”‚   β”œβ”€ [0] VM::startBroadcast()
    β”‚   β”‚   β”‚   └─ ← [Return] 
    β”‚   β”‚   β”œβ”€ [372255] β†’ new MockV3Aggregator@0x90193C961A926261B756D1E5bb255e67ff9498A1
    β”‚   β”‚   β”‚   └─ ← [Return] 1082 bytes of code
    β”‚   β”‚   β”œβ”€ [658696] β†’ new ERC20Mock@0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496
    β”‚   β”‚   β”‚   β”œβ”€ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: DeployDSC: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], value: 100000000000 [1e11])
    β”‚   β”‚   β”‚   └─ ← [Return] 2828 bytes of code
    β”‚   β”‚   β”œβ”€ [372255] β†’ new MockV3Aggregator@0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3
    β”‚   β”‚   β”‚   └─ ← [Return] 1082 bytes of code
    β”‚   β”‚   β”œβ”€ [658696] β†’ new ERC20Mock@0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76
    β”‚   β”‚   β”‚   β”œβ”€ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: DeployDSC: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], value: 100000000000 [1e11])
    β”‚   β”‚   β”‚   └─ ← [Return] 2828 bytes of code
    β”‚   β”‚   β”œβ”€ [0] VM::stopBroadcast()
    β”‚   β”‚   β”‚   └─ ← [Return] 
    β”‚   β”‚   └─ ← [Return] 6893 bytes of code
    β”‚   β”œβ”€ [934] HelperConfig::activeNetworkConfig() [staticcall]
    β”‚   β”‚   └─ ← [Return] MockV3Aggregator: [0x90193C961A926261B756D1E5bb255e67ff9498A1], MockV3Aggregator: [0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3], ERC20Mock: [0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496], ERC20Mock: [0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76], 77814517325470205911140941194401928579557062014761831930645393041380819009408 [7.781e76]
    β”‚   β”œβ”€ [0] VM::startBroadcast(<pk>)
    β”‚   β”‚   └─ ← [Return] 
    β”‚   β”œβ”€ [749823] β†’ new DecentralisedStableCoin@0x5FbDB2315678afecb367f032d93F642f64180aa3
    β”‚   β”‚   β”œβ”€ emit OwnershipTransferred(previousOwner: 0x0000000000000000000000000000000000000000, newOwner: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266)
    β”‚   β”‚   └─ ← [Return] 3401 bytes of code
    β”‚   β”œβ”€ [848361] β†’ new DSCEngine@0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
    β”‚   β”‚   └─ ← [Return] 3559 bytes of code
    β”‚   β”œβ”€ [2446] DecentralisedStableCoin::transferOwnership(DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512])
    β”‚   β”‚   β”œβ”€ emit OwnershipTransferred(previousOwner: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, newOwner: DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512])
    β”‚   β”‚   └─ ← [Stop] 
    β”‚   β”œβ”€ [0] VM::stopBroadcast()
    β”‚   β”‚   └─ ← [Return] 
    β”‚   └─ ← [Return] DecentralisedStableCoin: [0x5FbDB2315678afecb367f032d93F642f64180aa3], DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512], HelperConfig: [0x104fBc016F4bb334D775a19E8A6510109AC63E00]
    β”œβ”€ [934] HelperConfig::activeNetworkConfig() [staticcall]
    β”‚   └─ ← [Return] MockV3Aggregator: [0x90193C961A926261B756D1E5bb255e67ff9498A1], MockV3Aggregator: [0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3], ERC20Mock: [0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496], ERC20Mock: [0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76], 77814517325470205911140941194401928579557062014761831930645393041380819009408 [7.781e76]
    β”œβ”€ [24728] ERC20Mock::mint(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], 10000000000000000000 [1e19])
    β”‚   β”œβ”€ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], value: 10000000000000000000 [1e19])
    β”‚   └─ ← [Stop] 
    └─ ← [Stop] 

  [41386] DSCEngineTest::testRevertsIfCollateralZero()
    β”œβ”€ [0] VM::startPrank(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D])
    β”‚   └─ ← [Return] 
    β”œβ”€ [24651] ERC20Mock::approve(DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512], 10000000000000000000 [1e19])
    β”‚   β”œβ”€ emit Approval(owner: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], spender: DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512], value: 10000000000000000000 [1e19])
    β”‚   └─ ← [Return] true
    β”œβ”€ [0] VM::expectRevert(DSCEngine__MustBeMoreThanZero())
    β”‚   └─ ← [Return] 
    β”œβ”€ [479] DSCEngine::depositCollateral(ERC20Mock: [0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496], 0)
    β”‚   └─ ← [Revert] DSCEngine__MustBeMoreThanZero()
    β”œβ”€ [0] VM::stopPrank()
    β”‚   └─ ← [Return] 
    └─ ← [Stop] 

[PASS] testRevertsIfTokenLengthDoesntMatchPriceFeeds() (gas: 180444)
Traces:
  [10556084] DSCEngineTest::setUp()
    β”œβ”€ [4763996] β†’ new DeployDSC@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f
    β”‚   └─ ← [Return] 23571 bytes of code
    β”œβ”€ [5591843] DeployDSC::run()
    β”‚   β”œβ”€ [3752859] β†’ new HelperConfig@0x104fBc016F4bb334D775a19E8A6510109AC63E00
    β”‚   β”‚   β”œβ”€ [0] VM::startBroadcast()
    β”‚   β”‚   β”‚   └─ ← [Return] 
    β”‚   β”‚   β”œβ”€ [372255] β†’ new MockV3Aggregator@0x90193C961A926261B756D1E5bb255e67ff9498A1
    β”‚   β”‚   β”‚   └─ ← [Return] 1082 bytes of code
    β”‚   β”‚   β”œβ”€ [658696] β†’ new ERC20Mock@0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496
    β”‚   β”‚   β”‚   β”œβ”€ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: DeployDSC: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], value: 100000000000 [1e11])
    β”‚   β”‚   β”‚   └─ ← [Return] 2828 bytes of code
    β”‚   β”‚   β”œβ”€ [372255] β†’ new MockV3Aggregator@0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3
    β”‚   β”‚   β”‚   └─ ← [Return] 1082 bytes of code
    β”‚   β”‚   β”œβ”€ [658696] β†’ new ERC20Mock@0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76
    β”‚   β”‚   β”‚   β”œβ”€ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: DeployDSC: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], value: 100000000000 [1e11])
    β”‚   β”‚   β”‚   └─ ← [Return] 2828 bytes of code
    β”‚   β”‚   β”œβ”€ [0] VM::stopBroadcast()
    β”‚   β”‚   β”‚   └─ ← [Return] 
    β”‚   β”‚   └─ ← [Return] 6893 bytes of code
    β”‚   β”œβ”€ [934] HelperConfig::activeNetworkConfig() [staticcall]
    β”‚   β”‚   └─ ← [Return] MockV3Aggregator: [0x90193C961A926261B756D1E5bb255e67ff9498A1], MockV3Aggregator: [0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3], ERC20Mock: [0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496], ERC20Mock: [0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76], 77814517325470205911140941194401928579557062014761831930645393041380819009408 [7.781e76]
    β”‚   β”œβ”€ [0] VM::startBroadcast(<pk>)
    β”‚   β”‚   └─ ← [Return] 
    β”‚   β”œβ”€ [749823] β†’ new DecentralisedStableCoin@0x5FbDB2315678afecb367f032d93F642f64180aa3
    β”‚   β”‚   β”œβ”€ emit OwnershipTransferred(previousOwner: 0x0000000000000000000000000000000000000000, newOwner: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266)
    β”‚   β”‚   └─ ← [Return] 3401 bytes of code
    β”‚   β”œβ”€ [848361] β†’ new DSCEngine@0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
    β”‚   β”‚   └─ ← [Return] 3559 bytes of code
    β”‚   β”œβ”€ [2446] DecentralisedStableCoin::transferOwnership(DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512])
    β”‚   β”‚   β”œβ”€ emit OwnershipTransferred(previousOwner: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, newOwner: DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512])
    β”‚   β”‚   └─ ← [Stop] 
    β”‚   β”œβ”€ [0] VM::stopBroadcast()
    β”‚   β”‚   └─ ← [Return] 
    β”‚   └─ ← [Return] DecentralisedStableCoin: [0x5FbDB2315678afecb367f032d93F642f64180aa3], DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512], HelperConfig: [0x104fBc016F4bb334D775a19E8A6510109AC63E00]
    β”œβ”€ [934] HelperConfig::activeNetworkConfig() [staticcall]
    β”‚   └─ ← [Return] MockV3Aggregator: [0x90193C961A926261B756D1E5bb255e67ff9498A1], MockV3Aggregator: [0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3], ERC20Mock: [0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496], ERC20Mock: [0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76], 77814517325470205911140941194401928579557062014761831930645393041380819009408 [7.781e76]
    β”œβ”€ [24728] ERC20Mock::mint(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], 10000000000000000000 [1e19])
    β”‚   β”œβ”€ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], value: 10000000000000000000 [1e19])
    β”‚   └─ ← [Stop] 
    └─ ← [Stop] 

  [180444] DSCEngineTest::testRevertsIfTokenLengthDoesntMatchPriceFeeds()
    β”œβ”€ [0] VM::expectRevert(DSCEngine__TokenAddressesAndPriceFeedAddressesMustBeSameLength())
    β”‚   └─ ← [Return] 
    β”œβ”€ [23720] β†’ new <unknown>@0x2e234DAe75C793f67A35089C9d99245E1C58470b
    β”‚   └─ ← [Revert] 4 bytes of code
    └─ ← [Stop] 

[FAIL. Reason: Error != expected error: 0xa802cfbe != 0xa802cfbe0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b] testRevertsWithUnapprovedCollateral() (gas: 705829)
Traces:
  [10556084] DSCEngineTest::setUp()
    β”œβ”€ [4763996] β†’ new DeployDSC@0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f
    β”‚   └─ ← [Return] 23571 bytes of code
    β”œβ”€ [5591843] DeployDSC::run()
    β”‚   β”œβ”€ [3752859] β†’ new HelperConfig@0x104fBc016F4bb334D775a19E8A6510109AC63E00
    β”‚   β”‚   β”œβ”€ [0] VM::startBroadcast()
    β”‚   β”‚   β”‚   └─ ← [Return] 
    β”‚   β”‚   β”œβ”€ [372255] β†’ new MockV3Aggregator@0x90193C961A926261B756D1E5bb255e67ff9498A1
    β”‚   β”‚   β”‚   └─ ← [Return] 1082 bytes of code
    β”‚   β”‚   β”œβ”€ [658696] β†’ new ERC20Mock@0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496
    β”‚   β”‚   β”‚   β”œβ”€ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: DeployDSC: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], value: 100000000000 [1e11])
    β”‚   β”‚   β”‚   └─ ← [Return] 2828 bytes of code
    β”‚   β”‚   β”œβ”€ [372255] β†’ new MockV3Aggregator@0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3
    β”‚   β”‚   β”‚   └─ ← [Return] 1082 bytes of code
    β”‚   β”‚   β”œβ”€ [658696] β†’ new ERC20Mock@0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76
    β”‚   β”‚   β”‚   β”œβ”€ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: DeployDSC: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], value: 100000000000 [1e11])
    β”‚   β”‚   β”‚   └─ ← [Return] 2828 bytes of code
    β”‚   β”‚   β”œβ”€ [0] VM::stopBroadcast()
    β”‚   β”‚   β”‚   └─ ← [Return] 
    β”‚   β”‚   └─ ← [Return] 6893 bytes of code
    β”‚   β”œβ”€ [934] HelperConfig::activeNetworkConfig() [staticcall]
    β”‚   β”‚   └─ ← [Return] MockV3Aggregator: [0x90193C961A926261B756D1E5bb255e67ff9498A1], MockV3Aggregator: [0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3], ERC20Mock: [0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496], ERC20Mock: [0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76], 77814517325470205911140941194401928579557062014761831930645393041380819009408 [7.781e76]
    β”‚   β”œβ”€ [0] VM::startBroadcast(<pk>)
    β”‚   β”‚   └─ ← [Return] 
    β”‚   β”œβ”€ [749823] β†’ new DecentralisedStableCoin@0x5FbDB2315678afecb367f032d93F642f64180aa3
    β”‚   β”‚   β”œβ”€ emit OwnershipTransferred(previousOwner: 0x0000000000000000000000000000000000000000, newOwner: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266)
    β”‚   β”‚   └─ ← [Return] 3401 bytes of code
    β”‚   β”œβ”€ [848361] β†’ new DSCEngine@0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
    β”‚   β”‚   └─ ← [Return] 3559 bytes of code
    β”‚   β”œβ”€ [2446] DecentralisedStableCoin::transferOwnership(DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512])
    β”‚   β”‚   β”œβ”€ emit OwnershipTransferred(previousOwner: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, newOwner: DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512])
    β”‚   β”‚   └─ ← [Stop] 
    β”‚   β”œβ”€ [0] VM::stopBroadcast()
    β”‚   β”‚   └─ ← [Return] 
    β”‚   └─ ← [Return] DecentralisedStableCoin: [0x5FbDB2315678afecb367f032d93F642f64180aa3], DSCEngine: [0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512], HelperConfig: [0x104fBc016F4bb334D775a19E8A6510109AC63E00]
    β”œβ”€ [934] HelperConfig::activeNetworkConfig() [staticcall]
    β”‚   └─ ← [Return] MockV3Aggregator: [0x90193C961A926261B756D1E5bb255e67ff9498A1], MockV3Aggregator: [0xBb2180ebd78ce97360503434eD37fcf4a1Df61c3], ERC20Mock: [0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496], ERC20Mock: [0xDB8cFf278adCCF9E9b5da745B44E754fC4EE3C76], 77814517325470205911140941194401928579557062014761831930645393041380819009408 [7.781e76]
    β”œβ”€ [24728] ERC20Mock::mint(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], 10000000000000000000 [1e19])
    β”‚   β”œβ”€ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], value: 10000000000000000000 [1e19])
    β”‚   └─ ← [Stop] 
    └─ ← [Stop] 

  [705829] DSCEngineTest::testRevertsWithUnapprovedCollateral()
    β”œβ”€ [658696] β†’ new ERC20Mock@0x2e234DAe75C793f67A35089C9d99245E1C58470b
    β”‚   β”œβ”€ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], value: 10000000000000000000 [1e19])
    β”‚   └─ ← [Return] 2828 bytes of code
    β”œβ”€ [0] VM::startPrank(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D])
    β”‚   └─ ← [Return] 
    β”œβ”€ [0] VM::expectRevert(DSCEngine__NotAllowedToken())
    β”‚   └─ ← [Return] 
    β”œβ”€ [2695] DSCEngine::depositCollateral(ERC20Mock: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], 10000000000000000000 [1e19])
    β”‚   └─ ← [Revert] DSCEngine__NotAllowedToken()
    └─ ← [Revert] Error != expected error: 0xa802cfbe != 0xa802cfbe0000000000000000000000002e234dae75c793f67a35089c9d99245e1c58470b

Suite result: FAILED. 2 passed; 4 failed; 0 skipped; finished in 1.80ms (1.16ms CPU time)

I don’t want to spoil the fun so I am going to be spending my Sunday debugging and informing others of the results. If people want to call out issues they can see, do feel free.

The issues that are immediately obvious to me are:

  1. In testGetTokenAmountFromUsd there is a mismatch between the amountWeth variable and the expectedWeth variable, likely attributable to the logic contained in setup;
  2. In testRevertsWithUnapprovedCollateral it would appear that those with unapproved collateral can actually interact with the contract. I suspect this is an issue inherent from the core logic relating to depositCollateral; and
  3. my fuzz test that tests the invariants of the contract, does not appear to have the required amount of Eth to execute the transaction.
1 Like

Day 128 & 129

A quick post for today and yesterday.

I am still working on the test above, which is proving to take some times given the complexity of the code base (even for me who designed it). I find myself stretched between testing, auditing and also trying to provide meaningful content for this blog. As a result I will be posting less frequently this week to really try to nail various ongoing projects.

Apologies to those waiting for a daily blog posts! I'll resume when I have more meaningful updates re auditing and issues faced via testing.

1 Like