
Join the KibokoDAO Revolution: Limited NFTs to Shape the Future of Web3 in the African Savannah.
Welcome to Web3, a world where digital assets thrive, ownership is decentralized, and the power of community drives progress. In this brave new ecosystem, NFTs are more than just collectibles—they're your gateway to influence and innovation. At the heart of this evolution lies KibokoDAO NFTs, a Decentralized Autonomous Organization powered by membership NFTs on the Lisk blockchain and hosted on Rarible.Why Lisk?Lisk is redefining blockchain development with its modular approach, empowering de...

Payout Models for Content Creators: A Sustainable Future
Farcaster 2026 writing contest

Africa, We’re About to Get BaD: 7 Countries, One Mission, Infinite Vibes
In a world where DAOs are the new black and Web3 is more than just a buzzword you pretend to understand in front of your tech friends, BuildaDAO (BaD) is taking things to a whole new level of decentralized chaos and creativity. And guess what? We’re going BaD across SEVEN African countries. That’s right—seven places where jollof, nyama choma, bunny chow, and chapati are as essential as block explorers. Kenyans, you can store chapatis on decentralized nodes, your chapatis won't get messed with...

Join the KibokoDAO Revolution: Limited NFTs to Shape the Future of Web3 in the African Savannah.
Welcome to Web3, a world where digital assets thrive, ownership is decentralized, and the power of community drives progress. In this brave new ecosystem, NFTs are more than just collectibles—they're your gateway to influence and innovation. At the heart of this evolution lies KibokoDAO NFTs, a Decentralized Autonomous Organization powered by membership NFTs on the Lisk blockchain and hosted on Rarible.Why Lisk?Lisk is redefining blockchain development with its modular approach, empowering de...

Payout Models for Content Creators: A Sustainable Future
Farcaster 2026 writing contest

Africa, We’re About to Get BaD: 7 Countries, One Mission, Infinite Vibes
In a world where DAOs are the new black and Web3 is more than just a buzzword you pretend to understand in front of your tech friends, BuildaDAO (BaD) is taking things to a whole new level of decentralized chaos and creativity. And guess what? We’re going BaD across SEVEN African countries. That’s right—seven places where jollof, nyama choma, bunny chow, and chapati are as essential as block explorers. Kenyans, you can store chapatis on decentralized nodes, your chapatis won't get messed with...
Share Dialog
Share Dialog


<100 subscribers
<100 subscribers
So, you want to write a smart contract. Great! You’ve got dreams of decentralization, passive income, and maybe even a token named after your cat. But before you deploy and accidentally mint 2 billion extra tokens or lose everything in a reentrancy blackhole… sit down. Breathe.
Ah yes, the good old days (pre-Solidity 0.8.0) when subtracting 1 from 0 gave you 2⁵⁶-1 and nobody blinked.
Rookie mistake:
// Solidity <0.8.0
uint8 balance = 0;
balance -= 1; // Surprise! balance = 255
Use SafeMath, unless you're into heart attacks:
// Solidity >=0.8.0 has built-in checks. But let's pretend it's 2019 again:
using SafeMath for uint256;
uint256 balance = 0;
balance = balance.sub(1); // Revert with "SafeMath: subtraction overflow"
What it feels like debugging overflow bugs:
"Why does this token supply say 1.1 quattuordecillion?"
Say you’re building a bank contract. (Bold move. Auditors are already sweating.)
Here’s how NOT to do it:
Editfunction withdraw() public {
require(balances[msg.sender] > 0);
(bool sent, ) = msg.sender.call{value: balances[msg.sender]}(""); // 😬 External call first?
require(sent, "Failed to send Ether");
balances[msg.sender] = 0; // Too late, bro.
}
Attacker’s dream:
Editfallback() external payable {
victim.withdraw(); // Yo-yo time!
}
How to fix it (and keep your ETH):
// Check-Effects-Interactions pattern
function withdraw() public nonReentrant {
uint256 amount = balances[msg.sender];
require(amount > 0);
balances[msg.sender] = 0; // Update balance first
(bool sent, ) = msg.sender.call{value: amount}("");
require(sent, "Transfer failed");
}
Bonus tip:
"@openzeppelin/contracts/security/ReentrancyGuard.sol";
Be smart. Be guarded. Like a smart contract Kevin Costner.
You think you’re clever. You write:
function storeData() public {
MyStruct storage s; // Uh-oh.
s.value = 42;
}
This doesn’t "create" a new struct. This says: "Hey, modify random storage slot zero!"
Result: You may overwrite important contract data like the owner address, or your dignity.
Do this instead:
MyStruct storage s = myStructs[msg.sender]; // Actual location
Imagine this:
function sendRewards() public {
for (uint i = 0; i < users.length; i++) {
users[i].transfer(1 ether); // expensive AF
}
}
User list gets long. Function dies of gas exhaustion. R.I.P.
Fix:
Use pull over push method.
Limit batch size.
Add checkpointing logic.
Or just don’t build Ethereum into a to-do list app.
ExternalService external = ExternalService(externalAddress);
external.doSomethingCritical(); // Checks? Nah. YOLO.
This is how rug pulls happen.
Better:
(bool success, bytes memory data) = externalAddress.call(abi.encodeWithSignature("doSomethingCritical()"));
require(success, "External call failed");
if (abi.decode(data, (bool)) != true) {
revert("That external contract is sus");
}
Or use interfaces and only call verified contracts. You wouldn't give your wallet to a guy in an alley with "TotallyNotAScam.eth" on his jacket, right?
Smart contracts are like vending machines: automatic, immutable, and occasionally prone to spitting out flaming toads when you mess up.
So, use require, modifier, and humility liberally. Always test like your ETH depends on it — because it does.
Problem | Fix |
|---|---|
Overflow/Underflow | Use SafeMath or Solidity ≥ 0.8.0 |
Reentrancy | Checks-Effects-Interactions / |
Uninitialized Pointers | Always assign storage vars explicitly |
DoS via gas | Avoid unbounded loops / Use batching |
Unchecked Calls | Validate return values / Use trusted interfaces |
May your gas be cheap and your audits thorough.
Deploy responsibly, you must.
So, you want to write a smart contract. Great! You’ve got dreams of decentralization, passive income, and maybe even a token named after your cat. But before you deploy and accidentally mint 2 billion extra tokens or lose everything in a reentrancy blackhole… sit down. Breathe.
Ah yes, the good old days (pre-Solidity 0.8.0) when subtracting 1 from 0 gave you 2⁵⁶-1 and nobody blinked.
Rookie mistake:
// Solidity <0.8.0
uint8 balance = 0;
balance -= 1; // Surprise! balance = 255
Use SafeMath, unless you're into heart attacks:
// Solidity >=0.8.0 has built-in checks. But let's pretend it's 2019 again:
using SafeMath for uint256;
uint256 balance = 0;
balance = balance.sub(1); // Revert with "SafeMath: subtraction overflow"
What it feels like debugging overflow bugs:
"Why does this token supply say 1.1 quattuordecillion?"
Say you’re building a bank contract. (Bold move. Auditors are already sweating.)
Here’s how NOT to do it:
Editfunction withdraw() public {
require(balances[msg.sender] > 0);
(bool sent, ) = msg.sender.call{value: balances[msg.sender]}(""); // 😬 External call first?
require(sent, "Failed to send Ether");
balances[msg.sender] = 0; // Too late, bro.
}
Attacker’s dream:
Editfallback() external payable {
victim.withdraw(); // Yo-yo time!
}
How to fix it (and keep your ETH):
// Check-Effects-Interactions pattern
function withdraw() public nonReentrant {
uint256 amount = balances[msg.sender];
require(amount > 0);
balances[msg.sender] = 0; // Update balance first
(bool sent, ) = msg.sender.call{value: amount}("");
require(sent, "Transfer failed");
}
Bonus tip:
"@openzeppelin/contracts/security/ReentrancyGuard.sol";
Be smart. Be guarded. Like a smart contract Kevin Costner.
You think you’re clever. You write:
function storeData() public {
MyStruct storage s; // Uh-oh.
s.value = 42;
}
This doesn’t "create" a new struct. This says: "Hey, modify random storage slot zero!"
Result: You may overwrite important contract data like the owner address, or your dignity.
Do this instead:
MyStruct storage s = myStructs[msg.sender]; // Actual location
Imagine this:
function sendRewards() public {
for (uint i = 0; i < users.length; i++) {
users[i].transfer(1 ether); // expensive AF
}
}
User list gets long. Function dies of gas exhaustion. R.I.P.
Fix:
Use pull over push method.
Limit batch size.
Add checkpointing logic.
Or just don’t build Ethereum into a to-do list app.
ExternalService external = ExternalService(externalAddress);
external.doSomethingCritical(); // Checks? Nah. YOLO.
This is how rug pulls happen.
Better:
(bool success, bytes memory data) = externalAddress.call(abi.encodeWithSignature("doSomethingCritical()"));
require(success, "External call failed");
if (abi.decode(data, (bool)) != true) {
revert("That external contract is sus");
}
Or use interfaces and only call verified contracts. You wouldn't give your wallet to a guy in an alley with "TotallyNotAScam.eth" on his jacket, right?
Smart contracts are like vending machines: automatic, immutable, and occasionally prone to spitting out flaming toads when you mess up.
So, use require, modifier, and humility liberally. Always test like your ETH depends on it — because it does.
Problem | Fix |
|---|---|
Overflow/Underflow | Use SafeMath or Solidity ≥ 0.8.0 |
Reentrancy | Checks-Effects-Interactions / |
Uninitialized Pointers | Always assign storage vars explicitly |
DoS via gas | Avoid unbounded loops / Use batching |
Unchecked Calls | Validate return values / Use trusted interfaces |
May your gas be cheap and your audits thorough.
Deploy responsibly, you must.
Fabian Owuor
Fabian Owuor
No comments yet