In december 2021 heeft Georgios, CTO van Paradigm Lab en ’s werelds grootste crypto-native investeringsmaatschappij, een blog uitgebracht over de release van een nieuw raamwerk voor (evm-gebaseerde) slimme contractontwikkeling genaamd Foundry. Dit raamwerk heeft de Crypto-gemeenschap stormenderhand veroverd en is al snel de industriestandaard geworden voor het ontwikkelen en testen van slimme contracten, grotendeels dankzij de efficiëntie en prestatie ten opzichte van andere frameworks. Om de betekenis van Foundry te begrijpen, moeten eerst de uitdagingen waartegen het zich probeert te wapenen, worden onderzocht. Hardhat en Truffle worstelen bijvoorbeeld met het feit dat ontwikkelaars een scripttaal zoals JavaScript/TypeScript moeten kennen om met het framework te kunnen werken. Aangezien deze scripttalen vooral in de webontwikkeling worden gebruikt, is het niet altijd noodzakelijk dat soliditeitsontwikkelaars zich deze talen eigen maken omdat zij zich voornamelijk op de backend richten. Naast dit probleem is Hardhat geïmplementeerd met behulp van TypeScript, wat het langzaam maakt in vergelijking met Foundry, dat is geïmplementeerd in Rust. Foundry heeft tal van coole functies, zoals Roep stacktraces op, Interactieve debugger, Ingebouwd-fuzzing en Soliditeit scripting. Het is dan ook essentieel om Foundry en de noodzaak om slimme contracten te testen met Solidity te begrijpen. Foundry wordt geleverd met twee geweldige CLI-tools out-of-the-box, Forge die wordt gebruikt voor het testen en implementeren van slimme contracten en Cast die wordt gebruikt om te communiceren met geïmplementeerde slimme contracten.
Opzetten van een Foundry project is eenvoudig en ongecompliceerd. Installeer eerst Foundry door het volgende uit te voeren in de terminal: `curl -L https://foundry.paradigm.xyz | bash && foundryup`. Nadat Foundry is geïnstalleerd, kunt u Forge en Cast meteen gaan gebruiken. Om niets over het hoofd te zien, hebben we een sjabloonrepository gemaakt die alle vereiste bibliotheken, scripts, en directory-instellingen bevat. Om deze repository te gebruiken, voert u de volgende opdracht uit in uw terminal: `forge init
Als voorbeeld gaan we een kraancontract implementeren voor ons ERC20-token dat tokens kan druppelen op verzoek. Zo kunnen we het aantal tokens per aanvraag beperken met een standaard limit van 100 in ons contract. Dit is eenvoudig te realiseren door het bestand src/Faucet.sol te openen en de onderstaande code toe te voegen:
“`
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.13;
import {Ownable} from “openzeppelin-contracts/access/Ownable.sol”;
import {IERC20} from “openzeppelin-contracts/token/ERC20/IERC20.sol”;
contract Faucet is Ownable {
/// Address of the token that this faucet drips
IERC20 public token;
/// For rate limiting
mapping(address => uint256) public nextRequestAt;
/// Max token limit per request
uint256 public limit = 100;
/// @param _token The address of the faucet’s token
constructor(IERC20 _token) {
token = _token;
}
/// Used to send the tokens
/// @param _recipient The address of the tokens recipient
/// @param _amount The amount of tokens required from the faucet
function drip(address _recipient, uint256 _amount) external {
require(_recipient != address(0), “INVALID_RECIPIENT”);
require(_amount <= limit, "EXCEEDS_LIMIT");
require(nextRequestAt[_recipient] <= block.timestamp, "TRY_LATER");
nextRequestAt[_recipient] = block.timestamp + (5 minutes);
token.transfer(_recipient, _amount);
}
/// Used to set the max limit per request
/// @dev This method is restricted and should be called only by the owner
/// @param _limit The new limit for the tokens per request
function setLimit(uint256 _limit) external onlyOwner {
limit = _limit;
}
}
```
Wanneer we dit contract toevoegen, kunnen we vervolgens de contracten samenstellen door `forge build` uit te voeren. Als alles goed gaat, zou u een vergelijkbare uitvoer moeten zien:
```
(⠒) Compiling...
(⠒) Compiling 14 files with 0.8.13
Compiler run successful
```
We hebben ons Foundry-project succesvol opgezet en ons contract foutloos samengesteld! Nu kunnen we doorgaan en beginnen met het testen van ons kraancontract. Forge helpt ons bij het schrijven van unit-tests met behulp van Solidity, in tegenstelling tot Hardhat. In de src/test/Faucet.t.sol is al een begin gemaakt voor het schrijven van unit-tests. We voegen de volgende code toe om de drip() methode te testen:
```
function test_drip_transferToDev() public {
console.log("Should transfer tokens to recipient when `drip()` is called");
uint256 _inititalDevBal = token.balanceOf(dev);
assertEq(_inititalDevBal, 0);
faucet.drip(dev, amountToDrip);
uint256 _devBalAfterDrip = token.balanceOf(dev);
assertEq(_devBalAfterDrip - _inititalDevBal, amountToDrip);
}
```
Als we nu Forge uitvoeren met de opdracht `forge test`, zullen de testcases worden uitgevoerd en worden gevalideerd. Wanneer alles goed werkt, ziet u een uitvoer die lijkt op:
```
(⠒) Compiling...
(⠒) Compiling 14 files with 0.8.13
Compiler run successful
Test FaucetTest
✔ test_drip_transfer