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.
- package/README.md +87 -0
- package/dist/deploy.js +63 -0
- package/dist/forge.js +27 -0
- package/dist/index.js +176 -0
- package/dist/prompts.js +23 -0
- package/dist/scaffold.js +33 -0
- package/dist/templates.js +108 -0
- package/package.json +29 -0
- package/templates/erc20-gas/.env.example +19 -0
- package/templates/erc20-gas/.gitmodules +6 -0
- package/templates/erc20-gas/README.md +48 -0
- package/templates/erc20-gas/foundry.toml +35 -0
- package/templates/erc20-gas/gitignore +5 -0
- package/templates/erc20-gas/remappings.txt +2 -0
- package/templates/erc20-gas/script/DeployERC20Gas.s.sol +131 -0
- package/templates/erc20-gas/src/KozaGasToken.sol +105 -0
- package/templates/erc20-gas/test/DeployERC20Gas.t.sol +60 -0
- package/templates/erc20-gas/test/ERC20Gas.invariants.t.sol +144 -0
- package/templates/erc20-gas/test/ERC20Gas.t.sol +354 -0
- package/templates/erc721-collection/.env.example +37 -0
- package/templates/erc721-collection/.gitmodules +6 -0
- package/templates/erc721-collection/README.md +48 -0
- package/templates/erc721-collection/foundry.toml +35 -0
- package/templates/erc721-collection/gitignore +5 -0
- package/templates/erc721-collection/remappings.txt +2 -0
- package/templates/erc721-collection/script/DeployERC721Collection.s.sol +151 -0
- package/templates/erc721-collection/src/KozaCollection.sol +281 -0
- package/templates/erc721-collection/test/DeployERC721Collection.t.sol +76 -0
- package/templates/erc721-collection/test/ERC721Collection.invariants.t.sol +175 -0
- package/templates/erc721-collection/test/ERC721Collection.t.sol +501 -0
- package/templates/ictt-bridge/.env.example +19 -0
- package/templates/ictt-bridge/.gitmodules +9 -0
- package/templates/ictt-bridge/README.md +49 -0
- package/templates/ictt-bridge/foundry.toml +41 -0
- package/templates/ictt-bridge/gitignore +5 -0
- package/templates/ictt-bridge/remappings.txt +8 -0
- package/templates/ictt-bridge/script/DeployTokenHome.s.sol +139 -0
- package/templates/ictt-bridge/src/KozaTokenHome.sol +57 -0
- package/templates/ictt-bridge/src/KozaTokenRemote.sol +65 -0
- package/templates/ictt-bridge/test/ICTTBridge.t.sol +157 -0
- package/templates/soulbound-credential/.env.example +19 -0
- package/templates/soulbound-credential/.gitmodules +6 -0
- package/templates/soulbound-credential/README.md +48 -0
- package/templates/soulbound-credential/foundry.toml +35 -0
- package/templates/soulbound-credential/gitignore +5 -0
- package/templates/soulbound-credential/remappings.txt +2 -0
- package/templates/soulbound-credential/script/DeployCredential.s.sol +126 -0
- package/templates/soulbound-credential/src/KozaCredential.sol +201 -0
- package/templates/soulbound-credential/test/DeployCredential.t.sol +46 -0
- package/templates/soulbound-credential/test/Soulbound.invariants.t.sol +133 -0
- package/templates/soulbound-credential/test/Soulbound.t.sol +319 -0
- package/templates/treasury-multisig/.env.example +19 -0
- package/templates/treasury-multisig/.gitmodules +6 -0
- package/templates/treasury-multisig/README.md +48 -0
- package/templates/treasury-multisig/foundry.toml +35 -0
- package/templates/treasury-multisig/gitignore +5 -0
- package/templates/treasury-multisig/remappings.txt +2 -0
- package/templates/treasury-multisig/script/DeployTreasury.s.sol +128 -0
- package/templates/treasury-multisig/src/KozaTreasury.sol +55 -0
- package/templates/treasury-multisig/test/DeployTreasury.t.sol +50 -0
- 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,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,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
|
+
}
|