๐ Unit 3 โ Deploy ke Injective EVM
Di akhir unit ini kamu akan:
- Punya project Hardhat atau Foundry yang terkonfigurasi untuk Injective testnet
- Berhasil deploy contract ke Injective EVM Testnet (chain ID 1439)
- Bisa berinteraksi dengan contract yang sudah di-deploy
- Bisa melihat dan memverifikasi contract-mu di Blockscout
- โ
Unit 1 dan Unit 2 selesai โ kamu sudah punya contract
Celenganyang teruji di Remix - โ Phase 0 Unit 4 โ MetaMask sudah punya jaringan Injective EVM Testnet dan ada testnet INJ di dalamnya
- ๐ป Node.js v18+ terpasang โ cek dengan
node --version
Formatnya tetap sama seperti dua unit sebelumnya: satu langkah โ jalankan โ lihat hasil yang seharusnya muncul. Setiap perintah penting diikuti blok Yang seharusnya kamu lihat, supaya kamu langsung tahu kalau ada yang salah.
Bedanya cuma satu, tapi besar: sampai sekarang kamu bermain di Remix VM, simulasi di dalam browser. Mulai unit ini kamu berpindah ke jaringan Injective sungguhan. Artinya transaksi butuh beberapa detik, membayar gas dengan testnet INJ, dan permanen serta terlihat publik di explorer.
Di akhir Unit 1, kamu sempat men-deploy Celengan ke Injective testnet lewat Remix โ Injected Provider. Itu cara tercepat untuk sekali coba.
Unit ini memakai Hardhat atau Foundry โ cara yang dipakai tim sungguhan, karena project-nya bisa masuk version control, punya test otomatis, dan bisa diulang dengan satu perintah. Ini keterampilan yang terbawa langsung ke Phase 3 dan ke guided project.
1. RPC k8s.testnet.json-rpc.injective.network rusak untuk deploy.
Endpoint ini masih beredar luas, tapi ia menerima transaksi (transaksi benar-benar masuk chain, nonce naik, saldo berkurang) sambil selalu menjawab null untuk eth_getTransactionByHash dan eth_getTransactionReceipt.
Akibatnya waitForDeployment() / tx.wait() menunggu selamanya, dan kamu akan menyimpulkan deploy gagal โ padahal contract-mu sudah ter-deploy.
Pakai endpoint sentry di seluruh unit ini:
https://testnet.sentry.chain.json-rpc.injective.network/
2. @nomicfoundation/hardhat-toolbox versi terbaru adalah paket kosong.
npm install --save-dev @nomicfoundation/hardhat-toolbox sekarang memasang v7, yang isinya cuma pesan:
Warning: You installed the `latest` version of @nomicfoundation/hardhat-toolbox,
which does not work with Hardhat 2 nor 3.
Versinya wajib kamu tentukan sendiri โ lihat Step 2.
Unit ini butuh private key wallet-mu untuk menandatangani transaksi deploy.
Pakai wallet khusus latihan. Buat akun baru di MetaMask yang hanya berisi testnet INJ, dan pakai itu. Jangan pernah memakai wallet yang berisi aset sungguhan untuk latihan.
Kita akan menyimpan private key di file .env dan memastikan file itu tidak pernah masuk git. Private key yang ter-commit ke GitHub akan ditemukan bot dalam hitungan detik.
๐งฐ Hardhat atau Foundry?โ
Keduanya adalah kerangka kerja untuk mengembangkan smart contract. Pilih satu.
| Hardhat | Foundry | |
|---|---|---|
| Bahasa | JavaScript / TypeScript | Rust (tapi kamu menulis test dalam Solidity) |
| Belajar | Lebih mudah kalau kamu tahu JS | Lebih cepat, tapi asing di awal |
| Kecepatan test | Sedang | Sangat cepat |
| Cocok untuk | Pemula, integrasi frontend | Testing intensif |
Pakai Hardhat kalau kamu belum pernah memakai keduanya. Ekosistem JavaScript-nya menyambung langsung ke Phase 3 (TypeScript SDK), jadi ilmunya berlanjut.
Pilih Foundry kalau kamu sudah nyaman dengan terminal dan ingin test yang cepat.
- Hardhat
- Foundry
๐ฆ Setup Hardhatโ
Step 1 โ Buat projectโ
mkdir celengan-injective
cd celengan-injective
npm init -y
Step 2 โ Pasang dependensi (perhatikan versinya)โ
Unit ini memakai Hardhat 2, jadi versinya harus dipin โ kalau tidak, npm memasang Hardhat 3 yang format konfigurasinya sama sekali berbeda dan semua contoh di bawah tidak akan jalan.
npm install --save-dev hardhat@^2.26 @nomicfoundation/hardhat-toolbox@^5 dotenv
npm install @openzeppelin/contracts
npx hardhat init
Pilih "Create a JavaScript project" dan setujui opsi bawaannya.
Yang seharusnya kamu lihat: sebuah folder project dengan contracts/, scripts/, test/, dan file hardhat.config.js. Cek dengan ls:
contracts hardhat.config.js node_modules package.json scripts test
Boleh โ Hardhat 3 adalah versi yang didukung ke depan, dan Guided Project Unit 2 memakainya dari awal lengkap dengan konfigurasi yang sudah teruji.
Bedanya cukup besar: ESM ("type": "module"), defineConfig + plugins[], type: "http" di setiap network, dan tidak ada lagi hre.ethers global. Kalau ini deploy pertamamu, selesaikan unit ini dengan Hardhat 2 dulu supaya konsepnya dulu yang tertanam, baru pindah versi di Phase 3.
Step 3 โ Simpan private key dengan amanโ
Buat file .env:
PRIVATE_KEY=masukkan_private_key_wallet_latihanmu_disini
Lalu segera pastikan file itu diabaikan git:
echo ".env" >> .gitignore
Jalankan cat .gitignore dan pastikan .env ada di dalamnya sebelum kamu melakukan git commit apa pun.
node_modules
.env โ pastikan baris ini ada
Private key yang ter-push ke repo publik akan dipindai bot otomatis dan dikuras dalam hitungan detik. Ini terjadi setiap hari kepada developer sungguhan.
Cara mengambil private key dari MetaMask: klik tiga titik di sebelah akun โ Account details โ Show private key โ masukkan password.
Step 4 โ Konfigurasi jaringan Injectiveโ
Ganti isi hardhat.config.js:
require("@nomicfoundation/hardhat-toolbox");
require("dotenv").config();
module.exports = {
solidity: {
version: "0.8.20",
settings: {
optimizer: { enabled: true, runs: 200 },
},
},
networks: {
injectiveTestnet: {
url: "https://testnet.sentry.chain.json-rpc.injective.network/",
chainId: 1439,
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [],
timeout: 120000,
},
},
etherscan: {
apiKey: {
injectiveTestnet: "kosong-tidak-dipakai-blockscout",
},
customChains: [
{
network: "injectiveTestnet",
chainId: 1439,
urls: {
// API-nya ada di HOST TERPISAH, bukan <explorer>/api
apiURL: "https://testnet.blockscout-api.injective.network/api",
browserURL: "https://testnet.blockscout.injective.network/",
},
},
],
},
};
Ini menjebak hampir semua orang yang menebak bahwa API-nya ada di <url-explorer>/api:
| URL | |
|---|---|
| UI explorer (dibuka di browser) | https://testnet.blockscout.injective.network |
API (dipakai hardhat verify) | https://testnet.blockscout-api.injective.network/api |
$ curl -s "https://testnet.blockscout.injective.network/api?module=block&action=eth_block_number"
HTTP 404
$ curl -s "https://testnet.blockscout-api.injective.network/api?module=block&action=eth_block_number"
{"jsonrpc":"2.0","result": "0x819cce0","id": 1}
Perhatikan sisipan -api pada nama host โ itu host yang berbeda, bukan path.
Step 5 โ Simpan contractโ
Buat contracts/Celengan.sol dan isi dengan contract dari Unit 1.
Compile:
npx hardhat compile
Yang seharusnya kamu lihat:
Compiled 1 Solidity file successfully (evm target: paris).
Peringatan (warning) berwarna kuning tidak menghentikan compile. Yang menghentikan adalah error merah โ biasanya salah ketik atau versi pragma tidak cocok dengan 0.8.20 di config. Baca barisnya sampai habis.
Step 6 โ Script deployโ
Buat scripts/deploy.js:
const hre = require("hardhat");
async function main() {
const [deployer] = await hre.ethers.getSigners();
console.log("Deploy dari akun:", deployer.address);
const saldo = await hre.ethers.provider.getBalance(deployer.address);
console.log("Saldo:", hre.ethers.formatEther(saldo), "INJ");
const Celengan = await hre.ethers.getContractFactory("Celengan");
const celengan = await Celengan.deploy();
await celengan.waitForDeployment();
const alamat = await celengan.getAddress();
console.log("Celengan ter-deploy di:", alamat);
console.log(
"Lihat di explorer: https://testnet.blockscout.injective.network/address/" + alamat
);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
Step 7 โ Deploy!โ
npx hardhat run scripts/deploy.js --network injectiveTestnet
Yang seharusnya kamu lihat (alamat dan angka akan berbeda):
Deploy dari akun: 0x3aF1...9c2b
Saldo: 0.5 INJ
Celengan ter-deploy di: 0x8bC4...71aA
Lihat di explorer: https://testnet.blockscout.injective.network/address/0x8bC4...71aA
Simpan alamat contract itu, lalu buka link explorer yang dicetak. Kamu akan melihat contract-mu ada di jaringan publik dengan transaksi pembuatannya. โ
Kalau Saldo tercetak 0.0 INJ, deploy akan gagal di sini โ ambil testnet INJ dari faucet dulu.
Step 8 โ Berinteraksi dengan contractโ
Buat scripts/interact.js:
const hre = require("hardhat");
const ALAMAT_CONTRACT = "0x_ganti_dengan_alamat_hasil_deploy";
async function main() {
const celengan = await hre.ethers.getContractAt("Celengan", ALAMAT_CONTRACT);
// Menabung 0.01 INJ
console.log("Menabung...");
const tx = await celengan.menabung({
value: hre.ethers.parseEther("0.01"),
});
await tx.wait();
console.log("Selesai. Hash:", tx.hash);
// Cek tabungan
const tabungan = await celengan.tabunganSaya();
console.log("Tabungan saya:", hre.ethers.formatEther(tabungan), "INJ");
const total = await celengan.totalTersimpan();
console.log("Total tersimpan:", hre.ethers.formatEther(total), "INJ");
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
Jalankan:
npx hardhat run scripts/interact.js --network injectiveTestnet
Yang seharusnya kamu lihat:
Menabung...
Selesai. Hash: 0x5d2c...e0f7
Tabungan saya: 0.01 INJ
Total tersimpan: 0.01 INJ
Salin Hash transaksinya, tempel di Blockscout. Kamu akan melihat transaksi menabung, gas yang terpakai, dan event Menabung yang kamu pancarkan di Unit 1 โ persis seperti yang kamu lihat di panel logs Remix, tapi sekarang di explorer publik. โ
โ๏ธ Setup Foundryโ
Step 1 โ Pasang Foundryโ
curl -L https://foundry.paradigm.xyz | bash
foundryup
Verifikasi:
forge --version
Yang seharusnya kamu lihat (versi bisa berbeda):
forge 0.2.0 (a1b2c3d 2026-07-15T00:00:00.000000000Z)
Foundry paling baik dijalankan di WSL2, bukan PowerShell atau CMD. Kalau kamu belum punya WSL2, jalankan wsl --install di PowerShell sebagai administrator, lalu ulangi langkah di atas dari dalam terminal Ubuntu.
Step 2 โ Buat projectโ
forge init celengan-injective
cd celengan-injective
Yang seharusnya kamu lihat: folder dengan src/, test/, lib/, dan foundry.toml. Foundry juga membuat contoh Counter.sol โ boleh kamu hapus nanti.
Step 3 โ Pasang OpenZeppelinโ
forge install OpenZeppelin/openzeppelin-contracts
Yang seharusnya kamu lihat: OpenZeppelin terunduh ke lib/openzeppelin-contracts. Kalau forge mengeluh soal perubahan git yang belum di-commit, tambahkan --no-commit di akhir perintah.
Step 4 โ Simpan private keyโ
Buat .env:
PRIVATE_KEY=masukkan_private_key_wallet_latihanmu_disini
INJECTIVE_TESTNET_RPC=https://testnet.sentry.chain.json-rpc.injective.network/
Pastikan diabaikan git:
echo ".env" >> .gitignore
cat .gitignore
.env ada di .gitignore sebelum commit apa punOutput cat .gitignore harus memuat baris .env. Bot memindai GitHub untuk private key secara terus-menerus. Ini bukan kemungkinan teoretis.
Step 5 โ Konfigurasi foundry.tomlโ
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
solc = "0.8.20"
optimizer = true
optimizer_runs = 200
[rpc_endpoints]
injective_testnet = "https://testnet.sentry.chain.json-rpc.injective.network/"
[etherscan]
injective_testnet = { key = "kosong", url = "https://testnet.blockscout-api.injective.network/api", chain = 1439 }
Step 6 โ Simpan contractโ
Buat src/Celengan.sol dengan contract dari Unit 1.
Compile:
forge build
Yang seharusnya kamu lihat:
[โ ข] Compiling...
[โ ฐ] Compiling 2 files with 0.8.20
[โ ] Solc 0.8.20 finished in 1.23s
Compiler run successful!
Step 7 โ Tulis test (keunggulan utama Foundry)โ
Buat test/Celengan.t.sol:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
import "../src/Celengan.sol";
contract CelenganTest is Test {
Celengan celengan;
address alice = address(0x1);
function setUp() public {
celengan = new Celengan();
vm.deal(alice, 10 ether);
}
function testMenabung() public {
vm.prank(alice);
celengan.menabung{value: 1 ether}();
vm.prank(alice);
assertEq(celengan.tabunganSaya(), 1 ether);
}
function testTidakBisaMenarikLebihDariTabungan() public {
vm.prank(alice);
celengan.menabung{value: 1 ether}();
vm.prank(alice);
vm.expectRevert("Tabungan tidak cukup");
celengan.menarik(2 ether);
}
}
Jalankan:
forge test -vv
Yang seharusnya kamu lihat:
Ran 2 tests for test/Celengan.t.sol:CelenganTest
[PASS] testMenabung() (gas: 68421)
[PASS] testTidakBisaMenarikLebihDariTabungan() (gas: 71034)
Suite result: ok. 2 passed; 0 failed; 0 skipped
Di Unit 1 dan 2 kamu menguji dengan mengklik tombol dan berganti akun. vm.prank(alice) melakukan hal yang sama โ membuat panggilan berikutnya seolah datang dari alice โ tapi dalam kode yang bisa dijalankan ulang kapan saja. vm.deal memberi saldo palsu, dan vm.expectRevert menegaskan bahwa sebuah panggilan memang harus gagal.
Coba sengaja rusak: ubah assertEq(..., 1 ether) menjadi 2 ether, jalankan lagi, dan lihat test-nya [FAIL]. Itulah gunanya test โ menangkap kesalahan sebelum sampai ke jaringan.
Step 8 โ Deployโ
source .env
forge create src/Celengan.sol:Celengan \
--rpc-url $INJECTIVE_TESTNET_RPC \
--private-key $PRIVATE_KEY \
--broadcast
Yang seharusnya kamu lihat:
Deployer: 0x3aF1...9c2b
Deployed to: 0x8bC4...71aA
Transaction hash: 0x5d2c...e0f7
Catat alamat di baris Deployed to:, lalu buka https://testnet.blockscout.injective.network/address/<ALAMAT>. Contract-mu ada di sana. โ
Step 9 โ Berinteraksiโ
# Menabung 0.01 INJ
cast send <ALAMAT_CONTRACT> "menabung()" \
--value 0.01ether \
--rpc-url $INJECTIVE_TESTNET_RPC \
--private-key $PRIVATE_KEY
# Baca total tersimpan
cast call <ALAMAT_CONTRACT> "totalTersimpan()(uint256)" \
--rpc-url $INJECTIVE_TESTNET_RPC
Yang seharusnya kamu lihat dari cast call:
10000000000000000 [1e16]
10000000000000000 adalah 0.01 INJ dalam satuan terkecil (18 desimal) โ persis yang kamu setor. Ini pola "tidak ada desimal" dari Unit 1 yang muncul lagi. cast send juga mencetak transactionHash yang bisa kamu cari di Blockscout. โ
๐ Bonus โ Deploy Juga Token ERC-20 dari Unit 2โ
Ini opsional tapi sangat memuaskan. Di Unit 2 kamu membuat TokenCLC, sebuah token ERC-20 penuh. Deploy dengan langkah yang persis sama (taruh di contracts/TokenCLC.sol atau src/TokenCLC.sol, ganti nama contract di script/perintah deploy dari Celengan ke TokenCLC).
Yang membuatnya menyenangkan: setelah ter-deploy dan terverifikasi, buka contract-nya di Blockscout โ Blockscout akan mengenalinya sebagai token dan menampilkan tab khusus token. Kamu bahkan bisa menambahkan token itu ke MetaMask (Import tokens โ tempel alamat contract) dan melihat saldo 1 juta CLC11-mu muncul di wallet seperti token sungguhan.
Salah satu syarat kelulusan adalah post di X. "Saya men-deploy token pertama saya di Injective dan melihatnya muncul di wallet" jauh lebih berkesan dengan screenshot MetaMask yang menampilkan token buatanmu sendiri.
๐ Verifikasi di Blockscoutโ
Setelah deploy, buka:
https://testnet.blockscout.injective.network/address/ALAMAT_CONTRACT_KAMU
Yang bisa kamu lihat:
- Transactions โ riwayat interaksi contract
- Contract โ bytecode, dan source code kalau sudah diverifikasi
- Balance โ saldo INJ yang tersimpan di contract
Kenapa memverifikasi source code?โ
Verifikasi mengunggah kode Solidity-mu ke explorer, sehingga siapa pun bisa membacanya โ dan explorer akan menampilkan antarmuka Read/Write Contract yang bisa dipakai langsung tanpa menulis kode.
Contract yang terverifikasi jauh lebih meyakinkan sebagai bukti pekerjaan. Reviewer bisa langsung membaca kodemu di explorer, bukan hanya melihat alamat.
- Hardhat
- Foundry
npx hardhat verify --network injectiveTestnet ALAMAT_CONTRACT_KAMU
Yang seharusnya kamu lihat:
Successfully verified contract Celengan on the block explorer.
https://testnet.blockscout.injective.network/address/0x8bC4...71aA#code
forge verify-contract \
--chain-id 1439 \
--verifier blockscout \
--verifier-url https://testnet.blockscout-api.injective.network/api \
ALAMAT_CONTRACT_KAMU \
src/Celengan.sol:Celengan
Yang seharusnya kamu lihat:
Submitting verification for [src/Celengan.sol:Celengan] 0x8bC4...71aA.
Contract successfully verified
Setelah verifikasi berhasil, muat ulang halaman contract di Blockscout dan buka tab Contract. Sekarang ada tanda centang hijau, source code Solidity-mu terlihat, dan muncul sub-tab Read Contract / Write Contract yang bisa kamu klik langsung tanpa menulis kode apa pun. โ
Blockscout juga menyediakan verifikasi manual lewat antarmuka web-nya: buka halaman alamat contract โ tab Contract โ Verify & Publish, lalu tempel source code dan pilih versi compiler yang sama persis dengan yang kamu pakai.
Verifikasi bukan syarat kelulusan โ kalau macet, lanjutkan saja dan tanyakan di Telegram.
๐ ๏ธ Troubleshootingโ
"insufficient funds for gas"
Saldo testnet INJ-mu habis atau kosong. Ambil lagi dari faucet.
Periksa juga bahwa kamu memakai akun yang benar โ private key di .env harus milik akun yang berisi testnet INJ, bukan akun lain di MetaMask. Ingat, script deploy Hardhat mencetak Saldo: di awal โ kalau angkanya 0.0, di situlah masalahnya.
"invalid chain id" atau "network mismatch"
Pastikan chainId: 1439 di konfigurasimu dan RPC URL-nya persis https://testnet.sentry.chain.json-rpc.injective.network/ (termasuk garis miring di akhir).
"nonce too low" atau "replacement transaction underpriced"
Ada transaksi sebelumnya yang tersangkut. Di MetaMask: Settings โ Advanced โ Clear activity tab data, lalu coba lagi.
Deploy diam saja, tidak selesai-selesai (paling sering terjadi)
Kamu hampir pasti memakai RPC https://k8s.testnet.json-rpc.injective.network/. Endpoint itu menerima transaksimu tapi tidak pernah mengembalikan receipt, jadi waitForDeployment() menunggu tanpa batas.
Jangan langsung Ctrl+C lalu deploy ulang โ transaksinya kemungkinan besar sudah berhasil, dan mengulang hanya membuang gas serta menghasilkan contract kembar.
Cek dulu:
- Buka alamat wallet-mu di Blockscout
- Lihat apakah ada transaksi
Contract Creationyang sukses - Kalau ada โ itu contract-mu. Catat alamatnya.
Lalu ganti RPC di hardhat.config.js ke https://testnet.sentry.chain.json-rpc.injective.network/ dan deploy berikutnya akan selesai dalam hitungan detik.
Deploy berjalan lama lalu timeout
"cannot estimate gas; transaction may fail"
Biasanya artinya transaksinya memang akan gagal. Penyebab tersering: constructor melempar error, atau argumen yang kamu kirim salah. Coba deploy contract yang sama di Remix VM dulu untuk mengisolasi masalahnya โ persis lingkungan yang kamu pakai di Unit 1 dan 2.
Foundry: "command not found: forge"
Jalankan foundryup lagi, lalu buka terminal baru. Kalau masih gagal, tambahkan ~/.foundry/bin ke PATH-mu.
โ Checklist Sebelum Lanjutโ
- Project Hardhat atau Foundry berjalan,
compile/buildsukses -
.envberisi private key wallet latihan, dan ada di.gitignore - Contract berhasil di-deploy ke Injective EVM Testnet
- Alamat contract tercatat
- Sudah berhasil memanggil minimal satu function yang mengubah state, dan outputnya sesuai yang diharapkan
- Transaksinya terlihat di Blockscout
- (Bonus) Source code terverifikasi, atau token ERC-20 dari Unit 2 ter-deploy
Screenshot halaman contract-mu di Blockscout, dan simpan alamat contract di catatan.
Kamu akan membutuhkannya untuk submission kelulusan, dan jauh lebih mudah mengumpulkannya sekarang daripada mencarinya lagi tanggal 9 Agustus.
๐ฏ Rangkumanโ
- Injective EVM Testnet: chain ID
1439, RPChttps://testnet.sentry.chain.json-rpc.injective.network/โ bukan endpointk8s.โฆyang tidak pernah mengembalikan receipt - Hardhat untuk yang nyaman dengan JavaScript; Foundry untuk test cepat
- Private key selalu di
.env, dan.envselalu di.gitignoreโ verifikasi sebelum commit - Pakai wallet khusus latihan, jangan wallet berisi aset sungguhan
- Setiap perintah punya output yang diharapkan โ kalau berbeda, kamu langsung tahu ada yang salah, bukan tiga jam kemudian
- Blockscout adalah alat debugging dan bukti pekerjaanmu; verifikasi source membuatnya bisa dibaca dan dipakai langsung
- Beda dari Remix VM: transaksi di sini lambat, berbayar gas, permanen, dan publik
โ Quick Checkโ
- Berapa chain ID Injective EVM Testnet?
- Apa dua hal yang harus kamu pastikan sebelum
git commitpertama? - Kamu dapat error "insufficient funds for gas". Dua hal apa yang kamu periksa? (Petunjuk: script deploy Hardhat mencetak sesuatu di awal.)
cast callmengembalikan10000000000000000setelah kamu menabung 0.01 INJ. Kenapa angkanya sebesar itu?- Apa keuntungan memverifikasi source code di explorer?
0.01 INJ dalam satuan terkecil. INJ punya 18 desimal, jadi 0.01 ร 10ยนโธ = 10000000000000000. Blockchain tidak memakai bilangan desimal โ pola yang sama seperti di Unit 1.
๐ Jalur A (Solidity) selesai! Ini mencakup Learning Track Phase 3 dan 4.
Lanjut: Jalur B โ Rust untuk Web3 ๐