-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5e417a7
commit 41e41ad
Showing
36 changed files
with
2,879 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.26; | ||
|
||
/// @title ABI Decode Examples | ||
/// @author Ishan Lakhwani | ||
/// @notice Shows how to encode and decode complex data structures | ||
|
||
/* | ||
* UNDERSTANDING ABI DECODE 📦 | ||
* | ||
* ABI decoding converts encoded bytes back into Solidity types: | ||
* - Reverses the encoding process | ||
* - Must know the exact types to decode | ||
* - Works with complex data structures | ||
* | ||
* Visual Process: | ||
* | ||
* Encode: Data Types → [📦 Encoded Bytes] | ||
* Decode: [📦 Encoded Bytes] → Original Data | ||
* | ||
* Example Flow: | ||
* uint(123), address(0x...) → 0x000...7b... → uint(123), address(0x...) | ||
*/ | ||
contract AbiDecode { | ||
/* | ||
* Complex data structure example | ||
* Shows nested data that needs encoding/decoding | ||
* | ||
* Layout: | ||
* MyStruct { | ||
* string name; // Dynamic type | ||
* uint256[2] nums; // Fixed array | ||
* } | ||
*/ | ||
struct MyStruct { | ||
string name; | ||
uint256[2] nums; | ||
} | ||
|
||
/* | ||
* Encode multiple parameters including complex types | ||
* | ||
* Parameters: | ||
* - x: Simple uint256 | ||
* - addr: Ethereum address | ||
* - arr: Dynamic uint256 array | ||
* - myStruct: Custom struct | ||
* | ||
* Visual Encoding: | ||
* [x][addr][arr_length][arr_data][struct_data] → bytes | ||
*/ | ||
function encode(uint256 x, address addr, uint256[] calldata arr, MyStruct calldata myStruct) | ||
external | ||
pure | ||
returns (bytes memory) | ||
{ | ||
// Pack all parameters into a single bytes array | ||
return abi.encode(x, addr, arr, myStruct); | ||
} | ||
|
||
/* | ||
* Decode bytes back into original types | ||
* | ||
* Flow: | ||
* 1. Take encoded bytes | ||
* 2. Specify expected types | ||
* 3. Get original values | ||
* | ||
* Visual Decoding: | ||
* bytes → [Decoder] → Original Types | ||
* Must match ↑ encoding order | ||
*/ | ||
function decode(bytes calldata data) | ||
external | ||
pure | ||
returns (uint256 x, address addr, uint256[] memory arr, MyStruct memory myStruct) | ||
{ | ||
// Decode bytes into original types | ||
// Order and types must match encoding exactly | ||
(x, addr, arr, myStruct) = abi.decode(data, (uint256, address, uint256[], MyStruct)); | ||
} | ||
} | ||
|
||
/* | ||
* ABI DECODE BEST PRACTICES: | ||
* | ||
* 1. Type Safety: | ||
* - Match types exactly | ||
* - Order matters | ||
* - Handle dynamic types carefully | ||
* | ||
* 2. Common Use Cases: | ||
* - Cross-contract communication | ||
* - Batch processing | ||
* - Data verification | ||
* | ||
* 3. Error Handling: | ||
* - Validate decoded data | ||
* - Handle malformed input | ||
* - Check array lengths | ||
* | ||
* Visual Type Matching: | ||
* | ||
* Encode: (uint256, address, uint[]) → bytes | ||
* Decode: bytes → (uint256, address, uint[]) ✅ | ||
* Wrong: bytes → (address, uint256, uint[]) ❌ | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.26; | ||
|
||
/// @title ABI Encoding Examples | ||
/// @author Ishan Lakhwani | ||
/// @notice Shows different ways to encode function calls | ||
|
||
/* | ||
* UNDERSTANDING ABI ENCODING 📝 | ||
* | ||
* ABI (Application Binary Interface) encoding converts function calls and parameters | ||
* into bytes that can be sent to contracts. | ||
* | ||
* Three main encoding methods: | ||
* 1. encodeWithSignature: Uses string signature | ||
* 2. encodeWithSelector: Uses function selector | ||
* 3. encodeCall: Type-safe encoding (recommended) | ||
* | ||
* Visual Example: | ||
* | ||
* Function Call → Encoded Bytes | ||
* transfer(0x123.., 100) → 0xa9059cbb... | ||
* [selector][params] | ||
*/ | ||
|
||
// Interface defines the function we want to call | ||
interface IERC20 { | ||
function transfer(address, uint256) external; | ||
} | ||
|
||
// Mock token contract for example | ||
contract Token { | ||
function transfer(address, uint256) external {} | ||
} | ||
|
||
contract AbiEncode { | ||
/* | ||
* Generic function to execute encoded calls | ||
* Like a universal remote that can send any command | ||
* | ||
* Flow: | ||
* 1. Receive encoded data | ||
* 2. Send to target contract | ||
* 3. Check if call succeeded | ||
*/ | ||
function test(address _contract, bytes calldata data) external { | ||
(bool ok,) = _contract.call(data); | ||
require(ok, "call failed"); | ||
} | ||
|
||
/* | ||
* Method 1: encodeWithSignature | ||
* Uses string function signature | ||
* | ||
* Risks: | ||
* - Typos won't be caught at compile time | ||
* - "transfer(address,uint256)" must be exact | ||
* | ||
* Visual: | ||
* "transfer(address,uint256)" → 0xa9059cbb (selector) | ||
*/ | ||
function encodeWithSignature(address to, uint256 amount) external pure returns (bytes memory) { | ||
// Manually specify function signature | ||
return abi.encodeWithSignature("transfer(address,uint256)", to, amount); | ||
} | ||
|
||
/* | ||
* Method 2: encodeWithSelector | ||
* Uses function selector directly | ||
* | ||
* Better than signature because: | ||
* - No string manipulation | ||
* - Selector is computed at compile time | ||
* | ||
* Visual: | ||
* IERC20.transfer.selector → 0xa9059cbb | ||
*/ | ||
function encodeWithSelector(address to, uint256 amount) external pure returns (bytes memory) { | ||
// Use interface to get selector | ||
return abi.encodeWithSelector(IERC20.transfer.selector, to, amount); | ||
} | ||
|
||
/* | ||
* Method 3: encodeCall (Recommended) | ||
* Type-safe encoding using interface | ||
* | ||
* Advantages: | ||
* - Compile-time type checking | ||
* - No manual signature/selector needed | ||
* - Safest option | ||
* | ||
* Visual: | ||
* IERC20.transfer → Type-checked → Encoded bytes | ||
*/ | ||
function encodeCall(address to, uint256 amount) external pure returns (bytes memory) { | ||
// Most safe: compiler checks types | ||
return abi.encodeCall(IERC20.transfer, (to, amount)); | ||
} | ||
} | ||
|
||
/* | ||
* ABI ENCODING BEST PRACTICES: | ||
* | ||
* 1. Safety: | ||
* - Use encodeCall when possible (type-safe) | ||
* - Verify encoded data carefully | ||
* - Test with actual contracts | ||
* | ||
* 2. Common Use Cases: | ||
* - Contract interaction | ||
* - Proxy contracts | ||
* - Batch transactions | ||
* | ||
* 3. Method Selection: | ||
* encodeCall → Known interface, type safety needed | ||
* encodeWithSelector → Known selector, no interface | ||
* encodeWithSignature → Dynamic/unknown functions | ||
* | ||
* Visual Encoding Process: | ||
* | ||
* Function + Args → ABI Encode → Selector + Params → Contract | ||
* transfer(addr, 100) → 0xa9059cbb + params → Target | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.26; | ||
|
||
/// @title Array Examples | ||
/// @author Ishan Lakhwani | ||
/// @notice Shows different types of arrays and how to use them | ||
|
||
/* | ||
* ARRAYS IN SOLIDITY | ||
* | ||
* Think of arrays like a list of items: | ||
* | ||
* Dynamic Array (can grow/shrink): | ||
* [1, 2, 3, 4, 5, ...] | ||
* | ||
* Fixed Array (size can't change): | ||
* [_, _, _, _] (4 slots, fixed) | ||
* | ||
* Visual Example: | ||
* +---+---+---+---+---+ | ||
* | 1 | 2 | 3 | 4 | 5 | Dynamic: can add more → | ||
* +---+---+---+---+---+ | ||
* | ||
* +---+---+---+---+ | ||
* | 1 | 2 | 3 | 4 | Fixed: size stays at 4 | ||
* +---+---+---+---+ | ||
*/ | ||
contract Array { | ||
// Can grow or shrink | ||
uint256[] public arr; | ||
|
||
// Starts with values | ||
uint256[] public arr2 = [1, 2, 3]; | ||
|
||
// Fixed size of 10 | ||
uint256[10] public myFixedSizeArr; | ||
|
||
// Get one item | ||
function get(uint256 i) public view returns (uint256) { | ||
return arr[i]; | ||
} | ||
|
||
// Get whole array | ||
function getArr() public view returns (uint256[] memory) { | ||
return arr; // Warning: expensive for big arrays! | ||
} | ||
|
||
// Add item to end | ||
function push(uint256 i) public { | ||
arr.push(i); | ||
} | ||
|
||
// Remove last item | ||
function pop() public { | ||
arr.pop(); | ||
} | ||
|
||
// Get array size | ||
function getLength() public view returns (uint256) { | ||
return arr.length; | ||
} | ||
|
||
// Clear item at position | ||
function remove(uint256 index) public { | ||
// Just sets to 0, doesn't shrink array | ||
delete arr[index]; | ||
} | ||
|
||
// Create array in memory | ||
function examples() external pure { | ||
// Fixed size of 5 in memory | ||
uint256[] memory a = new uint256[](5); | ||
} | ||
} |
Oops, something went wrong.