create-kozalak-l1 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +87 -0
  2. package/dist/deploy.js +63 -0
  3. package/dist/forge.js +27 -0
  4. package/dist/index.js +176 -0
  5. package/dist/prompts.js +23 -0
  6. package/dist/scaffold.js +33 -0
  7. package/dist/templates.js +108 -0
  8. package/package.json +29 -0
  9. package/templates/erc20-gas/.env.example +19 -0
  10. package/templates/erc20-gas/.gitmodules +6 -0
  11. package/templates/erc20-gas/README.md +48 -0
  12. package/templates/erc20-gas/foundry.toml +35 -0
  13. package/templates/erc20-gas/gitignore +5 -0
  14. package/templates/erc20-gas/remappings.txt +2 -0
  15. package/templates/erc20-gas/script/DeployERC20Gas.s.sol +131 -0
  16. package/templates/erc20-gas/src/KozaGasToken.sol +105 -0
  17. package/templates/erc20-gas/test/DeployERC20Gas.t.sol +60 -0
  18. package/templates/erc20-gas/test/ERC20Gas.invariants.t.sol +144 -0
  19. package/templates/erc20-gas/test/ERC20Gas.t.sol +354 -0
  20. package/templates/erc721-collection/.env.example +37 -0
  21. package/templates/erc721-collection/.gitmodules +6 -0
  22. package/templates/erc721-collection/README.md +48 -0
  23. package/templates/erc721-collection/foundry.toml +35 -0
  24. package/templates/erc721-collection/gitignore +5 -0
  25. package/templates/erc721-collection/remappings.txt +2 -0
  26. package/templates/erc721-collection/script/DeployERC721Collection.s.sol +151 -0
  27. package/templates/erc721-collection/src/KozaCollection.sol +281 -0
  28. package/templates/erc721-collection/test/DeployERC721Collection.t.sol +76 -0
  29. package/templates/erc721-collection/test/ERC721Collection.invariants.t.sol +175 -0
  30. package/templates/erc721-collection/test/ERC721Collection.t.sol +501 -0
  31. package/templates/ictt-bridge/.env.example +19 -0
  32. package/templates/ictt-bridge/.gitmodules +9 -0
  33. package/templates/ictt-bridge/README.md +49 -0
  34. package/templates/ictt-bridge/foundry.toml +41 -0
  35. package/templates/ictt-bridge/gitignore +5 -0
  36. package/templates/ictt-bridge/remappings.txt +8 -0
  37. package/templates/ictt-bridge/script/DeployTokenHome.s.sol +139 -0
  38. package/templates/ictt-bridge/src/KozaTokenHome.sol +57 -0
  39. package/templates/ictt-bridge/src/KozaTokenRemote.sol +65 -0
  40. package/templates/ictt-bridge/test/ICTTBridge.t.sol +157 -0
  41. package/templates/soulbound-credential/.env.example +19 -0
  42. package/templates/soulbound-credential/.gitmodules +6 -0
  43. package/templates/soulbound-credential/README.md +48 -0
  44. package/templates/soulbound-credential/foundry.toml +35 -0
  45. package/templates/soulbound-credential/gitignore +5 -0
  46. package/templates/soulbound-credential/remappings.txt +2 -0
  47. package/templates/soulbound-credential/script/DeployCredential.s.sol +126 -0
  48. package/templates/soulbound-credential/src/KozaCredential.sol +201 -0
  49. package/templates/soulbound-credential/test/DeployCredential.t.sol +46 -0
  50. package/templates/soulbound-credential/test/Soulbound.invariants.t.sol +133 -0
  51. package/templates/soulbound-credential/test/Soulbound.t.sol +319 -0
  52. package/templates/treasury-multisig/.env.example +19 -0
  53. package/templates/treasury-multisig/.gitmodules +6 -0
  54. package/templates/treasury-multisig/README.md +48 -0
  55. package/templates/treasury-multisig/foundry.toml +35 -0
  56. package/templates/treasury-multisig/gitignore +5 -0
  57. package/templates/treasury-multisig/remappings.txt +2 -0
  58. package/templates/treasury-multisig/script/DeployTreasury.s.sol +128 -0
  59. package/templates/treasury-multisig/src/KozaTreasury.sol +55 -0
  60. package/templates/treasury-multisig/test/DeployTreasury.t.sol +50 -0
  61. package/templates/treasury-multisig/test/Treasury.t.sol +154 -0
@@ -0,0 +1,139 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.25;
3
+
4
+ import {Script} from "forge-std/Script.sol";
5
+ import {console2} from "forge-std/console2.sol";
6
+ import {KozaTokenHome} from "../src/KozaTokenHome.sol";
7
+
8
+ /**
9
+ * @title DeployTokenHome
10
+ * @notice Foundry deployment script for KozaTokenHome (Phase 1, Sprint 3, v0.3.0).
11
+ * Kaynak zincirde (default: Fuji) ERC-20 lock contract'ını yayar.
12
+ *
13
+ * Kullanım (Fuji testnet, .env doluyken):
14
+ *
15
+ * forge script script/deploy/DeployTokenHome.s.sol \
16
+ * --rpc-url fuji \
17
+ * --broadcast \
18
+ * --verify
19
+ *
20
+ * Zorunlu env (.env):
21
+ * - PRIVATE_KEY — deployer (testnet only!)
22
+ *
23
+ * Opsiyonel env (default'lar Phase 1 senaryosu — Fuji'de KGAS bridge):
24
+ * - HOME_TELEPORTER_REGISTRY (0xF86Cb19Ad8405AEFa7d09C778215D2Cb6eBfB228 — Fuji resmi)
25
+ * - HOME_TELEPORTER_MANAGER (broadcaster) — production: multisig
26
+ * - HOME_MIN_TELEPORTER_VERSION (1)
27
+ * - HOME_TOKEN_ADDRESS (KozaGasToken v0.1.0 — 0x06451...2eB0)
28
+ * - HOME_TOKEN_DECIMALS (18)
29
+ *
30
+ * Production checklist:
31
+ * - HOME_TELEPORTER_MANAGER MUTLAKA multisig olmalı (mainnet öncesi)
32
+ * - HOME_TOKEN_ADDRESS denetlenmiş, immutable bir ERC-20'ye işaret etmeli
33
+ * - Snowtrace/Routescan API key SNOWTRACE_API_KEY env'inde set'li olmalı
34
+ */
35
+ contract DeployTokenHome is Script {
36
+ /*//////////////////////////////////////////////////////////////
37
+ DEFAULTS
38
+ //////////////////////////////////////////////////////////////*/
39
+
40
+ /// @dev Fuji Teleporter Registry — Avalanche resmi sürüm (chain ID 43113).
41
+ address internal constant DEFAULT_TELEPORTER_REGISTRY = 0xF86Cb19Ad8405AEFa7d09C778215D2Cb6eBfB228;
42
+
43
+ /// @dev KozaGasToken v0.1.0 — Fuji'de canlı, Phase 1'in default bridge token'ı.
44
+ address internal constant DEFAULT_TOKEN_ADDRESS = 0x06451DD4Fb8ebFC19870DacC9568f4364D2A2eB0;
45
+
46
+ uint256 internal constant DEFAULT_MIN_TELEPORTER_VERSION = 1;
47
+ uint8 internal constant DEFAULT_TOKEN_DECIMALS = 18;
48
+
49
+ /*//////////////////////////////////////////////////////////////
50
+ RUN
51
+ //////////////////////////////////////////////////////////////*/
52
+
53
+ function run() external returns (KozaTokenHome home, address deployer) {
54
+ address teleporterRegistry = vm.envOr("HOME_TELEPORTER_REGISTRY", DEFAULT_TELEPORTER_REGISTRY);
55
+ uint256 minTeleporterVersion = vm.envOr("HOME_MIN_TELEPORTER_VERSION", DEFAULT_MIN_TELEPORTER_VERSION);
56
+ address tokenAddress = vm.envOr("HOME_TOKEN_ADDRESS", DEFAULT_TOKEN_ADDRESS);
57
+ uint256 tokenDecimalsRaw = vm.envOr("HOME_TOKEN_DECIMALS", uint256(DEFAULT_TOKEN_DECIMALS));
58
+ uint8 tokenDecimals = uint8(tokenDecimalsRaw);
59
+
60
+ address broadcaster = _resolveBroadcaster();
61
+ address teleporterManager = vm.envOr("HOME_TELEPORTER_MANAGER", broadcaster);
62
+
63
+ return
64
+ deploy(
65
+ teleporterRegistry, teleporterManager, minTeleporterVersion, tokenAddress, tokenDecimals, broadcaster
66
+ );
67
+ }
68
+
69
+ /// @notice Test-friendly entry point. Parametrik, env'e dokunmaz.
70
+ function deploy(
71
+ address teleporterRegistry,
72
+ address teleporterManager,
73
+ uint256 minTeleporterVersion,
74
+ address tokenAddress,
75
+ uint8 tokenDecimals,
76
+ address broadcaster
77
+ )
78
+ public
79
+ returns (KozaTokenHome home, address deployer)
80
+ {
81
+ _logPreDeploy(
82
+ teleporterRegistry, teleporterManager, minTeleporterVersion, tokenAddress, tokenDecimals, broadcaster
83
+ );
84
+
85
+ vm.startBroadcast();
86
+ home =
87
+ new KozaTokenHome(teleporterRegistry, teleporterManager, minTeleporterVersion, tokenAddress, tokenDecimals);
88
+ vm.stopBroadcast();
89
+
90
+ deployer = broadcaster;
91
+
92
+ _logPostDeploy(home);
93
+ }
94
+
95
+ /*//////////////////////////////////////////////////////////////
96
+ INTERNALS
97
+ //////////////////////////////////////////////////////////////*/
98
+
99
+ function _resolveBroadcaster() internal view returns (address) {
100
+ address explicitDeployer = vm.envOr("DEPLOYER_ADDRESS", address(0));
101
+ if (explicitDeployer != address(0)) return explicitDeployer;
102
+
103
+ uint256 pk = vm.envOr("PRIVATE_KEY", uint256(0));
104
+ if (pk != 0) return vm.addr(pk);
105
+
106
+ return tx.origin;
107
+ }
108
+
109
+ function _logPreDeploy(
110
+ address teleporterRegistry,
111
+ address teleporterManager,
112
+ uint256 minTeleporterVersion,
113
+ address tokenAddress,
114
+ uint8 tokenDecimals,
115
+ address broadcaster
116
+ )
117
+ internal
118
+ pure
119
+ {
120
+ console2.log("=== Deploying KozaTokenHome ===");
121
+ console2.log(" Broadcaster: ", broadcaster);
122
+ console2.log(" Teleporter Registry: ", teleporterRegistry);
123
+ console2.log(" Teleporter Manager: ", teleporterManager);
124
+ console2.log(" Min Teleporter Version:", minTeleporterVersion);
125
+ console2.log(" Token Address (KGAS): ", tokenAddress);
126
+ console2.log(" Token Decimals: ", tokenDecimals);
127
+ }
128
+
129
+ function _logPostDeploy(KozaTokenHome home) internal pure {
130
+ console2.log("=== Deployed ===");
131
+ console2.log(" KozaTokenHome at: ", address(home));
132
+ console2.log("");
133
+ console2.log("Next steps:");
134
+ console2.log(" 1) Hedef zincire (kozaTestL1) KozaTokenRemote'u deploy et:");
135
+ console2.log(" - REMOTE_TOKEN_HOME_ADDRESS = <yukaridaki adres>");
136
+ console2.log(" 2) Remote tarafta registerWithHome() cagrisini gonder.");
137
+ console2.log(" 3) End-to-end bridge demosu icin Sprint 3G rehberini takip et.");
138
+ }
139
+ }
@@ -0,0 +1,57 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.25;
3
+
4
+ import {ERC20TokenHome} from "@ictt/TokenHome/ERC20TokenHome.sol";
5
+
6
+ /**
7
+ * @title KozaTokenHome
8
+ * @notice kozalak-l1 Sprint 3 ICTT TokenHome boilerplate (Phase 1, v0.3.0).
9
+ *
10
+ * Source-chain ERC-20 lock contract. ava-labs/icm-contracts'tan
11
+ * denetlenmiş `ERC20TokenHome`'u doğrudan miras alır; üzerine
12
+ * custom logic eklemez. Audit-grade prensibi: minimum custom
13
+ * layer on top of audited primitives.
14
+ *
15
+ * Yayın senaryosu (Phase 1 default):
16
+ * - Kaynak zincir: Avalanche Fuji testnet (chain ID 43113)
17
+ * - Bridge edilen token: KozaGasToken (KGAS) v0.1.0 — Fuji'de
18
+ * zaten canlı: 0x06451DD4Fb8ebFC19870DacC9568f4364D2A2eB0
19
+ * - Hedef zincir: kozaTestL1 (chain ID 9999) — Avalanche CLI
20
+ * tarafından local'de ayağa kaldırılmış Subnet-EVM tabanlı L1
21
+ * - Hedef contract: `KozaTokenRemote` (ayrı deploy)
22
+ *
23
+ * Parent `ERC20TokenHome`'un sağladıkları:
24
+ * - Reentrancy guard (SendReentrancyGuardUpgradeable)
25
+ * - Teleporter registry üzerinden version pinning ve migration
26
+ * (TeleporterRegistryOwnableAppUpgradeable)
27
+ * - Multi-hop transfer desteği (Home -> Remote A -> Remote B)
28
+ * - sendAndCall pattern: token transfer + uzak zincirde
29
+ * fonksiyon çağrısı (atomik)
30
+ * - ERC-20 lock/unlock (deposit/withdraw) muhasebesi
31
+ *
32
+ * Production hazırlık checklist'i:
33
+ * - `teleporterManager` MUTLAKA Safe (Gnosis) multisig olmalı.
34
+ * Bu adres Teleporter version migration'ları yönetir; tek
35
+ * nokta güven (single point of trust). EOA mainnet'e konmaz.
36
+ * - `tokenAddress` immutable bir ERC-20'ye işaret etmeli
37
+ * (KozaGasToken zaten Ownable2Step + cap'li, uygun).
38
+ * - `minTeleporterVersion` her iki zincirin desteklediği en
39
+ * düşük versiyon olmalı; Avalanche resmi Teleporter
40
+ * release notes'a bakılarak güncellenir.
41
+ * - Constructor argümanları deterministic — aynı Bridge
42
+ * birden fazla L1 çiftine deploy edilirse her seferinde
43
+ * aynı bytecode + adres üretmek için CreateX/CREATE2 kullan.
44
+ *
45
+ * @custom:security-contact security@bekirerdem.dev
46
+ */
47
+ contract KozaTokenHome is ERC20TokenHome {
48
+ constructor(
49
+ address teleporterRegistryAddress,
50
+ address teleporterManager,
51
+ uint256 minTeleporterVersion,
52
+ address tokenAddress,
53
+ uint8 tokenDecimals
54
+ )
55
+ ERC20TokenHome(teleporterRegistryAddress, teleporterManager, minTeleporterVersion, tokenAddress, tokenDecimals)
56
+ {}
57
+ }
@@ -0,0 +1,65 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.25;
3
+
4
+ import {ERC20TokenRemote} from "@ictt/TokenRemote/ERC20TokenRemote.sol";
5
+ import {TokenRemoteSettings} from "@ictt/TokenRemote/interfaces/ITokenRemote.sol";
6
+
7
+ /**
8
+ * @title KozaTokenRemote
9
+ * @notice kozalak-l1 Sprint 3 ICTT TokenRemote boilerplate (Phase 1, v0.3.0).
10
+ *
11
+ * Hedef-zincir mint/burn ERC-20 representation. ava-labs/icm-contracts'tan
12
+ * denetlenmiş `ERC20TokenRemote`'u doğrudan miras alır; üzerine custom
13
+ * logic eklemez. Audit-grade prensibi: minimum custom layer.
14
+ *
15
+ * Yayın senaryosu (Phase 1 default):
16
+ * - Hedef zincir: kozaTestL1 (chain ID 9999) — Subnet-EVM,
17
+ * Avalanche CLI ile yerel deploy
18
+ * - Bu kontrat üretir: wKGAS (Wrapped Koza Gas), 18 decimals
19
+ * - Kaynak zincir TokenHome: Fuji'deki `KozaTokenHome`
20
+ * instance'ı (Sprint 3'ün diğer yarısı)
21
+ *
22
+ * Akış (Senaryo B):
23
+ * 1. Kullanıcı Fuji'de KGAS (`KozaGasToken`) approve eder.
24
+ * 2. `KozaTokenHome.send(...)` çağırır → KGAS lock'lanır,
25
+ * Teleporter messenger üzerinden kozaTestL1'e mesaj gider.
26
+ * 3. kozaTestL1'de `KozaTokenRemote` mesajı alır → kullanıcının
27
+ * cüzdanına wKGAS mint eder.
28
+ * 4. Geri yönde: kullanıcı wKGAS'ı burn eder, Fuji'deki KGAS'ı
29
+ * unlock olur.
30
+ *
31
+ * Parent `ERC20TokenRemote`'un sağladıkları:
32
+ * - ERC-20 standardı (mint/burn dahil)
33
+ * - Reentrancy guard (SendReentrancyGuardUpgradeable)
34
+ * - Teleporter registry üzerinden version pinning + migration
35
+ * - TokenHome ile decimals scaling (farklı decimals ise oranlar)
36
+ * - Multi-hop transfer ve sendAndCall desteği
37
+ * - `registerWithHome()` ilk deploy sonrası çağrılarak
38
+ * TokenHome ile eşleşmeyi tamamlar
39
+ *
40
+ * Production hazırlık checklist'i:
41
+ * - `settings.teleporterManager` MUTLAKA Safe (Gnosis) multisig
42
+ * olmalı (Home tarafıyla aynı kural).
43
+ * - `settings.tokenHomeBlockchainID` Fuji blockchain ID'si:
44
+ * `0x` prefix'li 32-byte (Avalanche CLI veya P-Chain query
45
+ * ile öğrenilir).
46
+ * - `settings.tokenHomeAddress` deploy edilmiş `KozaTokenHome`
47
+ * contract adresi.
48
+ * - `tokenName`/`tokenSymbol`: hedef L1'de "wKGAS" / "Wrapped
49
+ * Koza Gas" gibi anlamlı değerler (kullanıcı UX'i için).
50
+ * - Deploy sonrası ilk işlem: `registerWithHome(feeInfo)` ile
51
+ * Home tarafına bildirim gönder; bu olmadan transfer'ler
52
+ * reverte uğrar.
53
+ *
54
+ * @custom:security-contact security@bekirerdem.dev
55
+ */
56
+ contract KozaTokenRemote is ERC20TokenRemote {
57
+ constructor(
58
+ TokenRemoteSettings memory settings,
59
+ string memory tokenName,
60
+ string memory tokenSymbol,
61
+ uint8 tokenDecimals
62
+ )
63
+ ERC20TokenRemote(settings, tokenName, tokenSymbol, tokenDecimals)
64
+ {}
65
+ }
@@ -0,0 +1,157 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.25;
3
+
4
+ import {Test} from "forge-std/Test.sol";
5
+ import {KozaTokenHome} from "../src/KozaTokenHome.sol";
6
+ import {KozaTokenRemote} from "../src/KozaTokenRemote.sol";
7
+ import {TokenRemoteSettings} from "@ictt/TokenRemote/interfaces/ITokenRemote.sol";
8
+ import {ITeleporterMessenger} from "@teleporter/ITeleporterMessenger.sol";
9
+
10
+ /**
11
+ * @title MockTeleporterRegistry
12
+ * @notice Smoke test setup için minimal TeleporterRegistry stub. Sadece
13
+ * `__TeleporterRegistryApp_init`'in zero-check + version-compare
14
+ * adımlarını geçirebilmek için yeterli yüzeye sahip. send/receive
15
+ * flow burada test edilmez (Sprint 3G fork test'leri o iş için).
16
+ */
17
+ contract MockTeleporterRegistry {
18
+ address public messenger;
19
+ uint256 public latestVersion = 1;
20
+
21
+ constructor(address messenger_) {
22
+ messenger = messenger_;
23
+ }
24
+
25
+ function getAddressFromVersion(uint256) external view returns (address) {
26
+ return messenger;
27
+ }
28
+
29
+ function getLatestTeleporter() external view returns (ITeleporterMessenger) {
30
+ return ITeleporterMessenger(messenger);
31
+ }
32
+
33
+ function getVersionFromAddress(address) external pure returns (uint256) {
34
+ return 1;
35
+ }
36
+ }
37
+
38
+ /**
39
+ * @title MockERC20
40
+ * @notice Sadece `decimals()` döndürmek için ihtiyaç var (Home init bunu çekmez,
41
+ * ama deploy sırasında ERC-20 referansı tutulur). Boş bir kontrat yeterli.
42
+ */
43
+ contract MockERC20 {
44
+ function decimals() external pure returns (uint8) {
45
+ return 18;
46
+ }
47
+ }
48
+
49
+ contract ICTTBridgeSmokeTest is Test {
50
+ MockTeleporterRegistry internal registry;
51
+ MockERC20 internal mockToken;
52
+ address internal mockMessenger;
53
+ address internal teleporterManager;
54
+
55
+ bytes32 internal constant SAMPLE_HOME_BLOCKCHAIN_ID =
56
+ bytes32(hex"abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd");
57
+ address internal constant SAMPLE_HOME_ADDRESS = address(0xC0FFEE);
58
+
59
+ /// @dev Warp Messenger precompile address (Avalanche Subnet-EVM yerleşik). Foundry
60
+ /// test EVM'inde mevcut değil; vm.etch + vm.mockCall ile sahte bir kontrat
61
+ /// koyup `getBlockchainID()` çağrısını yakalıyoruz. ICTT init için yeterli.
62
+ address internal constant WARP_MESSENGER = 0x0200000000000000000000000000000000000005;
63
+
64
+ function setUp() public {
65
+ mockMessenger = makeAddr("messenger");
66
+ teleporterManager = makeAddr("teleporterManager");
67
+ registry = new MockTeleporterRegistry(mockMessenger);
68
+ mockToken = new MockERC20();
69
+
70
+ // Warp precompile mock: EVM call'unun "call to non-contract" hatası vermemesi için
71
+ // bytecode etch et, sonra getBlockchainID()'yi mock'la.
72
+ vm.etch(WARP_MESSENGER, hex"01");
73
+ vm.mockCall(
74
+ WARP_MESSENGER,
75
+ abi.encodeWithSignature("getBlockchainID()"),
76
+ abi.encode(bytes32(uint256(43_113))) // sembolik — Fuji chain ID
77
+ );
78
+ }
79
+
80
+ /*//////////////////////////////////////////////////////////////
81
+ KOZA TOKEN HOME — SMOKE
82
+ //////////////////////////////////////////////////////////////*/
83
+
84
+ function test_KozaTokenHome_DeploysWithValidParams() public {
85
+ KozaTokenHome home = new KozaTokenHome({
86
+ teleporterRegistryAddress: address(registry),
87
+ teleporterManager: teleporterManager,
88
+ minTeleporterVersion: 1,
89
+ tokenAddress: address(mockToken),
90
+ tokenDecimals: 18
91
+ });
92
+
93
+ assertTrue(address(home) != address(0));
94
+ }
95
+
96
+ function test_KozaTokenHome_RevertsOnZeroRegistry() public {
97
+ vm.expectRevert();
98
+ new KozaTokenHome({
99
+ teleporterRegistryAddress: address(0),
100
+ teleporterManager: teleporterManager,
101
+ minTeleporterVersion: 1,
102
+ tokenAddress: address(mockToken),
103
+ tokenDecimals: 18
104
+ });
105
+ }
106
+
107
+ function test_KozaTokenHome_RevertsOnZeroMinVersion() public {
108
+ vm.expectRevert();
109
+ new KozaTokenHome({
110
+ teleporterRegistryAddress: address(registry),
111
+ teleporterManager: teleporterManager,
112
+ minTeleporterVersion: 0,
113
+ tokenAddress: address(mockToken),
114
+ tokenDecimals: 18
115
+ });
116
+ }
117
+
118
+ /*//////////////////////////////////////////////////////////////
119
+ KOZA TOKEN REMOTE — SMOKE
120
+ //////////////////////////////////////////////////////////////*/
121
+
122
+ function _defaultRemoteSettings() internal view returns (TokenRemoteSettings memory) {
123
+ return TokenRemoteSettings({
124
+ teleporterRegistryAddress: address(registry),
125
+ teleporterManager: teleporterManager,
126
+ minTeleporterVersion: 1,
127
+ tokenHomeBlockchainID: SAMPLE_HOME_BLOCKCHAIN_ID,
128
+ tokenHomeAddress: SAMPLE_HOME_ADDRESS,
129
+ tokenHomeDecimals: 18
130
+ });
131
+ }
132
+
133
+ function test_KozaTokenRemote_DeploysWithValidParams() public {
134
+ KozaTokenRemote remote = new KozaTokenRemote(_defaultRemoteSettings(), "Wrapped Koza Gas", "wKGAS", 18);
135
+
136
+ assertEq(remote.name(), "Wrapped Koza Gas");
137
+ assertEq(remote.symbol(), "wKGAS");
138
+ assertEq(remote.decimals(), 18);
139
+ assertEq(remote.totalSupply(), 0);
140
+ }
141
+
142
+ function test_KozaTokenRemote_RevertsOnZeroHomeAddress() public {
143
+ TokenRemoteSettings memory settings = _defaultRemoteSettings();
144
+ settings.tokenHomeAddress = address(0);
145
+
146
+ vm.expectRevert();
147
+ new KozaTokenRemote(settings, "Wrapped Koza Gas", "wKGAS", 18);
148
+ }
149
+
150
+ function test_KozaTokenRemote_RevertsOnZeroHomeBlockchainID() public {
151
+ TokenRemoteSettings memory settings = _defaultRemoteSettings();
152
+ settings.tokenHomeBlockchainID = bytes32(0);
153
+
154
+ vm.expectRevert();
155
+ new KozaTokenRemote(settings, "Wrapped Koza Gas", "wKGAS", 18);
156
+ }
157
+ }
@@ -0,0 +1,19 @@
1
+ # ============================================
2
+ # Bu dosyayı kopyalayıp `.env` olarak adlandırın. `.env` ASLA commit edilmez.
3
+ # ============================================
4
+
5
+ # ---- Deploy Wallet (Fuji testnet) ----
6
+ # UYARI: Mainnet private key'i ASLA buraya koyma. Sadece testnet için.
7
+ # Production'da Foundry Cast Wallet (encrypted keystore) veya hardware wallet kullan.
8
+ PRIVATE_KEY=
9
+
10
+ # Deployer adres (sanity check, opsiyonel)
11
+ DEPLOYER_ADDRESS=
12
+
13
+ # ---- Block Explorer (Routescan) ----
14
+ # routescan.io'dan ücretsiz `rs_` prefix'li API key al. `--verify` için gerekir.
15
+ SNOWTRACE_API_KEY=
16
+
17
+ # ---- ICM / Teleporter ----
18
+ # Avalanche Teleporter messenger — tüm L1'lerde deterministic adres.
19
+ TELEPORTER_MESSENGER_ADDRESS=0x253b2784c75e510dD0fF1da844684a1aC0aa5fcf
@@ -0,0 +1,6 @@
1
+ [submodule "lib/forge-std"]
2
+ path = lib/forge-std
3
+ url = https://github.com/foundry-rs/forge-std
4
+ [submodule "lib/openzeppelin-contracts"]
5
+ path = lib/openzeppelin-contracts
6
+ url = https://github.com/OpenZeppelin/openzeppelin-contracts
@@ -0,0 +1,48 @@
1
+ # Soulbound Credential
2
+
3
+ Devredilemez (soulbound), role-bazlı sertifika NFT'si (KozaCredential).
4
+
5
+ Bu, kozalak-l1 deposundan üretilmiş **standalone** bir Foundry projesidir;
6
+ kendi başına derlenir ve test edilir.
7
+
8
+ ## Kurulum
9
+
10
+ ```bash
11
+ forge install foundry-rs/forge-std@8987040ede9553cea20c95ad40d0455930f9c8e0 OpenZeppelin/openzeppelin-contracts@e4f70216d759d8e6a64144a9e1f7bbeed78e7079
12
+ forge build
13
+ forge test
14
+ ```
15
+
16
+ > `forge install ...@<commit>` bağımlılıkları repo ile birebir aynı commit'lere
17
+ > pinler (aşağıdaki tabloya bakın). `.gitmodules` ve `remappings.txt`
18
+ > bu pinlerle uyumludur.
19
+
20
+ ## Deploy (Fuji testnet)
21
+
22
+ ```bash
23
+ cp .env.example .env # PRIVATE_KEY + SNOWTRACE_API_KEY doldur
24
+ forge script script/DeployCredential.s.sol \
25
+ --rpc-url fuji \
26
+ --broadcast \
27
+ --verify
28
+ ```
29
+
30
+ > Production: `PRIVATE_KEY` yalnızca testnet olmalı; sahiplik/yönetici
31
+ > adreslerini bir multisig'e (Safe) yönlendir, EOA bırakma.
32
+
33
+ ## Yeniden adlandırma
34
+
35
+ Contract'ı kendi adınla yeniden adlandırmak istersen `src/`, `test/` ve
36
+ `script/` altındaki dosyalarda contract/dosya adını birlikte güncelle
37
+ (import'lar tek-seviye relative olduğu için tutarlı kalmalı).
38
+
39
+ ## Bağımlılık pinleri
40
+
41
+ | Bağımlılık | Tag | Commit (pin) |
42
+ | --- | --- | --- |
43
+ | `forge-std` | v1.16.0 | `8987040ede9553cea20c95ad40d0455930f9c8e0` |
44
+ | `openzeppelin-contracts` | v5.3.0 | `e4f70216d759d8e6a64144a9e1f7bbeed78e7079` |
45
+
46
+ ---
47
+
48
+ _Bu proje `create-kozalak-l1` tarafından üretildi. Kaynak: kozalak-l1 mono-repo._
@@ -0,0 +1,35 @@
1
+ [profile.default]
2
+ src = "src"
3
+ out = "out"
4
+ libs = ["lib"]
5
+ test = "test"
6
+ script = "script"
7
+ # Bu şablon solc 0.8.34 pragma'sı kullanır. auto_detect_solc dosya
8
+ # pragma'sına göre doğru derleyiciyi otomatik indirir/seçer.
9
+ auto_detect_solc = true
10
+ optimizer = true
11
+ optimizer_runs = 200
12
+ via_ir = true
13
+ bytecode_hash = "none"
14
+ cbor_metadata = false
15
+ remappings = [
16
+ "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
17
+ "forge-std/=lib/forge-std/src/"
18
+ ]
19
+
20
+ [fmt]
21
+ line_length = 120
22
+ tab_width = 4
23
+ bracket_spacing = false
24
+ int_types = "long"
25
+ multiline_func_header = "all"
26
+ quote_style = "double"
27
+ number_underscore = "thousands"
28
+
29
+ [rpc_endpoints]
30
+ fuji = "https://api.avax-test.network/ext/bc/C/rpc"
31
+ avalanche = "https://api.avax.network/ext/bc/C/rpc"
32
+
33
+ [etherscan]
34
+ fuji = { key = "${SNOWTRACE_API_KEY}", url = "https://api.routescan.io/v2/network/testnet/evm/43113/etherscan", chain = 43113 }
35
+ avalanche = { key = "${SNOWTRACE_API_KEY}", url = "https://api.routescan.io/v2/network/mainnet/evm/43114/etherscan", chain = 43114 }
@@ -0,0 +1,5 @@
1
+ .env
2
+ out/
3
+ cache/
4
+ broadcast/
5
+ lib/
@@ -0,0 +1,2 @@
1
+ @openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
2
+ forge-std/=lib/forge-std/src/
@@ -0,0 +1,126 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.34;
3
+
4
+ import {Script} from "forge-std/Script.sol";
5
+ import {console2} from "forge-std/console2.sol";
6
+ import {KozaCredential} from "../src/KozaCredential.sol";
7
+
8
+ /**
9
+ * @title DeployCredential
10
+ * @notice Foundry deployment script for KozaCredential (Phase 1, Template 4).
11
+ *
12
+ * Usage (Fuji testnet, with .env populated):
13
+ *
14
+ * forge script script/deploy/DeployCredential.s.sol \
15
+ * --rpc-url fuji \
16
+ * --broadcast \
17
+ * --verify
18
+ *
19
+ * Required env (loaded by `forge` from .env):
20
+ * - PRIVATE_KEY — deployer private key (testnet only!)
21
+ *
22
+ * Optional env (defaults below if unset):
23
+ * - CREDENTIAL_NAME ("ARIA Hub Credential")
24
+ * - CREDENTIAL_SYMBOL ("ARIA")
25
+ * - CREDENTIAL_ADMIN (broadcaster) — production: multisig
26
+ * - CREDENTIAL_ISSUER (broadcaster) — sertifika veren/iptal eden
27
+ *
28
+ * Production checklist:
29
+ * - PRIVATE_KEY testnet-only veya cast-wallet/keystore ile değiştirilmeli
30
+ * - CREDENTIAL_ADMIN bir Safe (Gnosis) multisig olmalı (rol yönetimi)
31
+ * - CREDENTIAL_ISSUER kurum/eğitmen cüzdanı; çoklu issuer admin tarafından
32
+ * `grantRole(ISSUER_ROLE, ...)` ile eklenir
33
+ * - SNOWTRACE_API_KEY `.env`'de set'li olmalı (Routescan verify)
34
+ */
35
+ contract DeployCredential is Script {
36
+ /*//////////////////////////////////////////////////////////////
37
+ DEFAULTS
38
+ //////////////////////////////////////////////////////////////*/
39
+
40
+ string internal constant DEFAULT_NAME = "ARIA Hub Credential";
41
+ string internal constant DEFAULT_SYMBOL = "ARIA";
42
+
43
+ /*//////////////////////////////////////////////////////////////
44
+ RUN
45
+ //////////////////////////////////////////////////////////////*/
46
+
47
+ /// @notice Entry point invoked by `forge script`. Reads parameters from env.
48
+ function run() external returns (KozaCredential cred, address deployer) {
49
+ string memory name = vm.envOr("CREDENTIAL_NAME", DEFAULT_NAME);
50
+ string memory symbol = vm.envOr("CREDENTIAL_SYMBOL", DEFAULT_SYMBOL);
51
+
52
+ address broadcaster = _resolveBroadcaster();
53
+ address admin = vm.envOr("CREDENTIAL_ADMIN", broadcaster);
54
+ address issuer = vm.envOr("CREDENTIAL_ISSUER", broadcaster);
55
+
56
+ return deploy(name, symbol, admin, issuer, broadcaster);
57
+ }
58
+
59
+ /// @notice Test-friendly entry point. Takes explicit parameters instead of env.
60
+ /// @dev Prefer this from Foundry tests so env state does not leak between cases.
61
+ function deploy(
62
+ string memory name,
63
+ string memory symbol,
64
+ address admin,
65
+ address issuer,
66
+ address broadcaster
67
+ )
68
+ public
69
+ returns (KozaCredential cred, address deployer)
70
+ {
71
+ _logPreDeploy(name, symbol, admin, issuer, broadcaster);
72
+
73
+ vm.startBroadcast();
74
+ cred = new KozaCredential(name, symbol, admin, issuer);
75
+ vm.stopBroadcast();
76
+
77
+ deployer = broadcaster;
78
+
79
+ _logPostDeploy(cred, admin, issuer);
80
+ }
81
+
82
+ /*//////////////////////////////////////////////////////////////
83
+ INTERNALS
84
+ //////////////////////////////////////////////////////////////*/
85
+
86
+ /// @dev Order: explicit DEPLOYER_ADDRESS > derived from PRIVATE_KEY > tx.origin.
87
+ function _resolveBroadcaster() internal view returns (address) {
88
+ address explicitDeployer = vm.envOr("DEPLOYER_ADDRESS", address(0));
89
+ if (explicitDeployer != address(0)) return explicitDeployer;
90
+
91
+ uint256 pk = vm.envOr("PRIVATE_KEY", uint256(0));
92
+ if (pk != 0) return vm.addr(pk);
93
+
94
+ return tx.origin;
95
+ }
96
+
97
+ function _logPreDeploy(
98
+ string memory name,
99
+ string memory symbol,
100
+ address admin,
101
+ address issuer,
102
+ address broadcaster
103
+ )
104
+ internal
105
+ pure
106
+ {
107
+ console2.log("=== Deploying KozaCredential ===");
108
+ console2.log(" Broadcaster: ", broadcaster);
109
+ console2.log(" Name: ", name);
110
+ console2.log(" Symbol: ", symbol);
111
+ console2.log(" Admin: ", admin);
112
+ console2.log(" Issuer: ", issuer);
113
+ }
114
+
115
+ function _logPostDeploy(KozaCredential cred, address admin, address issuer) internal view {
116
+ console2.log("=== Deployed ===");
117
+ console2.log(" Address: ", address(cred));
118
+ console2.log(" Admin set: ", cred.hasRole(cred.DEFAULT_ADMIN_ROLE(), admin));
119
+ console2.log(" Issuer set: ", cred.hasRole(cred.ISSUER_ROLE(), issuer));
120
+ console2.log("");
121
+ console2.log("Next steps:");
122
+ console2.log(" 1) cast send <addr> 'issue(address,string)' <to> 'Course Name' --rpc-url fuji ...");
123
+ console2.log(" 2) cast call <addr> 'isValid(uint256)' 1 --rpc-url fuji");
124
+ console2.log(" 3) admin: cast send <addr> 'grantRole(bytes32,address)' <ISSUER_ROLE> <newIssuer>");
125
+ }
126
+ }