-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy path04_smart_contracts.zig
More file actions
204 lines (175 loc) Β· 8.7 KB
/
Copy path04_smart_contracts.zig
File metadata and controls
204 lines (175 loc) Β· 8.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
/// Example: Smart Contract Interaction
/// This example demonstrates how to:
/// - Interact with ERC-20 tokens
/// - Call view functions
/// - Send transactions to contracts
/// - Parse event logs
/// - Use contract abstractions
const std = @import("std");
const zigeth = @import("zigeth");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
std.debug.print("\nπ Zigeth Smart Contract Examples\n", .{});
std.debug.print("ββββββββββββββββββββββββββββββββββ\n\n", .{});
// Connect to Ethereum mainnet
var provider = try zigeth.providers.Networks.mainnet(allocator);
defer provider.deinit();
// Example 1: ERC-20 Token Interaction
std.debug.print("Example 1: ERC-20 Token (USDC)\n", .{});
std.debug.print("βββββββββββββββββββββββββββββββ\n", .{});
{
// USDC contract on Ethereum mainnet - simple string literal!
const usdc_address = try zigeth.primitives.Address.fromHex("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48");
const addr_hex = try usdc_address.toHex(allocator);
defer allocator.free(addr_hex);
std.debug.print("β
USDC Contract: {s}\n", .{addr_hex});
// Create ERC-20 contract binding
const erc20 = try zigeth.sol.Erc20Contract(allocator, usdc_address);
defer erc20.deinit();
std.debug.print(" Contract type: ERC-20\n", .{});
std.debug.print(" Standard functions: balanceOf, transfer, approve, etc.\n\n", .{});
}
// Example 2: Encode function call (balanceOf)
std.debug.print("Example 2: Encode Function Call\n", .{});
std.debug.print("ββββββββββββββββββββββββββββββββ\n", .{});
{
// Create function definition
const balance_of = zigeth.abi.Function{
.name = "balanceOf",
.inputs = &[_]zigeth.abi.Parameter{
.{
.name = "account",
.type = .address,
.indexed = false,
},
},
.outputs = &[_]zigeth.abi.Parameter{
.{
.name = "balance",
.type = .uint256,
.indexed = false,
},
},
.state_mutability = .view,
};
// Encode call
const check_address = try zigeth.primitives.Address.fromHex("0x0000000000000000000000000000000000000001");
const params = [_]zigeth.abi.AbiValue{
.{ .address = check_address },
};
const encoded = try zigeth.abi.encodeFunctionCall(
allocator,
balance_of,
¶ms,
);
defer allocator.free(encoded);
const encoded_hex = try zigeth.utils.hex.bytesToHex(allocator, encoded);
defer allocator.free(encoded_hex);
std.debug.print("β
Encoded balanceOf call\n", .{});
std.debug.print(" Function: balanceOf(address)\n", .{});
std.debug.print(" Encoded data: {s}\n", .{encoded_hex[0..@min(66, encoded_hex.len)]});
std.debug.print(" Data length: {} bytes\n\n", .{encoded.len});
}
// Example 3: Parse event logs
std.debug.print("Example 3: Parse Event Logs\n", .{});
std.debug.print("βββββββββββββββββββββββββββ\n", .{});
{
// ERC-20 Transfer event signature
const transfer_sig = "Transfer(address,address,uint256)";
const event_hash = zigeth.crypto.keccak.eventSignature(transfer_sig);
const hash_hex = try event_hash.toHex(allocator);
defer allocator.free(hash_hex);
std.debug.print("β
Transfer event signature\n", .{});
std.debug.print(" Event: {s}\n", .{transfer_sig});
std.debug.print(" Keccak-256 hash: {s}\n\n", .{hash_hex});
}
// Example 4: Contract deployment data
std.debug.print("Example 4: Contract Deployment\n", .{});
std.debug.print("ββββββββββββββββββββββββββββββ\n", .{});
{
// Example: Simple storage contract
const bytecode = [_]u8{
0x60, 0x80, 0x60, 0x40, // Contract bytecode (simplified)
0x52, 0x34, 0x80, 0x15,
};
std.debug.print("β
Contract deployment\n", .{});
std.debug.print(" Bytecode length: {} bytes\n", .{bytecode.len});
std.debug.print(" Deployment uses 'to' = null\n", .{});
std.debug.print(" Contract address calculated from sender + nonce\n\n", .{});
}
// Example 5: Using pre-defined selectors
std.debug.print("Example 5: Function Selectors\n", .{});
std.debug.print("βββββββββββββββββββββββββββββ\n", .{});
{
const selectors = zigeth.sol.Selectors;
std.debug.print("β
Common ERC-20 selectors:\n", .{});
std.debug.print(" balanceOf: {s}\n", .{selectors.ERC20_BALANCE_OF});
std.debug.print(" transfer: {s}\n", .{selectors.ERC20_TRANSFER});
std.debug.print(" approve: {s}\n", .{selectors.ERC20_APPROVE});
std.debug.print(" transferFrom: {s}\n", .{selectors.ERC20_TRANSFER_FROM});
std.debug.print(" allowance: {s}\n\n", .{selectors.ERC20_ALLOWANCE});
}
// Example 6: ABI encoding patterns
std.debug.print("Example 6: ABI Encoding Patterns\n", .{});
std.debug.print("βββββββββββββββββββββββββββββββββ\n", .{});
{
// Encode different types
const types_to_encode = [_]struct {
type_name: []const u8,
description: []const u8,
}{
.{ .type_name = "uint256", .description = "Unsigned 256-bit integer" },
.{ .type_name = "address", .description = "Ethereum address (20 bytes)" },
.{ .type_name = "bool", .description = "Boolean value" },
.{ .type_name = "bytes", .description = "Dynamic byte array" },
.{ .type_name = "string", .description = "UTF-8 string" },
.{ .type_name = "uint256[]", .description = "Dynamic array of uint256" },
.{ .type_name = "bytes32", .description = "Fixed 32-byte array" },
};
std.debug.print("β
Supported ABI types:\n", .{});
for (types_to_encode) |t| {
std.debug.print(" β’ {s:<12} - {s}\n", .{ t.type_name, t.description });
}
std.debug.print("\n", .{});
}
// Example 7: Event filtering
std.debug.print("Example 7: Event Filtering\n", .{});
std.debug.print("ββββββββββββββββββββββββββ\n", .{});
{
// USDC contract
const usdc_address = try zigeth.primitives.Address.fromHex("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48");
// Create filter for Transfer events
const filter = zigeth.rpc.FilterOptions{
.address = usdc_address,
.topics = null, // Could filter by specific addresses
.from_block = null,
.to_block = null,
};
_ = filter; // Would be used with provider.eth.getLogs(filter)
std.debug.print("β
Event filter created\n", .{});
std.debug.print(" Contract: USDC\n", .{});
std.debug.print(" Event: All Transfer events\n", .{});
std.debug.print(" Usage: provider.eth.getLogs(filter)\n\n", .{});
}
// Example 8: Multi-call pattern (reading multiple values)
std.debug.print("Example 8: Multi-Call Pattern\n", .{});
std.debug.print("ββββββββββββββββββββββββββββββ\n", .{});
{
std.debug.print("β
Best practices for multi-call:\n", .{});
std.debug.print(" 1. Create provider connection\n", .{});
std.debug.print(" 2. Prepare multiple CallParams\n", .{});
std.debug.print(" 3. Execute calls in sequence or parallel\n", .{});
std.debug.print(" 4. Decode results\n", .{});
std.debug.print(" 5. Close connections\n\n", .{});
std.debug.print(" Example pattern:\n", .{});
std.debug.print(" - Get token balance\n", .{});
std.debug.print(" - Get token name\n", .{});
std.debug.print(" - Get token symbol\n", .{});
std.debug.print(" - Get token decimals\n", .{});
std.debug.print(" All in efficient sequence!\n\n", .{});
}
std.debug.print("π All smart contract examples completed!\n", .{});
std.debug.print("π‘ Tip: Use ERC-20, ERC-721, ERC-1155 helpers from zigeth.sol\n\n", .{});
}