38 Minuten Lesezeit
Übersicht
Hyperliquid vereint zwei Schichten in einem einheitlichen System: HyperCore, eine Order-Book-Engine mit extrem geringer Latenz, auf die über signierte Aktionen zugegriffen wird, und HyperEVM, ein vollständig EVM-kompatibles Netzwerk für die Entwicklung mit Standard-Solidity.
Chainlink CCIP ermöglicht die Überbrückung von Assets zwischen verschiedenen Blockchains mithilfe eines „Burn-and-Mint“-Mechanismus. Innerhalb von Hyperliquid werden Umwandlungen zwischen HyperCore (HIP-1)-Assets und deren HyperEVM-Darstellungen durch native Protokollabläufe abgewickelt.
In dieser Anleitung werden Sie mit Foundry einen HyperEVM-Token erstellen, der einem HIP-1-Asset entspricht, und diesen Token mithilfe von CCIP zwischen HyperEVM und der BNB Smart Chain (BSC) überbrücken.
Ihre Aufgaben
- Erstellen Sie einen Wrapper-Vertrag für ein HyperEVM-Token, das mit einem HIP-1-Asset verknüpft ist
- CCIP-Token-Pools auf HyperEVM und BSC bereitstellen und konfigurieren
- Überprüfen Sie unsere bereitgestellten Token- und Pool-Verträge in der Blockchain
- CCIP-Übertragungen zwischen HyperEVM und BSC mit Foundry-Skripten durchführen
Was Sie benötigen
- Node.js v22+ und ein Paketmanager (npm, yarn oder pnpm) müssen installiert sein
- MetaMask: Die Netzwerke „HyperEVM Mainnet“ und „Binance Smart Chain Mainnet“ wurden hinzugefügt
- Quicknode-Endpunkte für HyperEVM und Binance Smart Chain
- Erfahrung mit Solidity und Foundry
In dieser Anleitung verwenden wir die MAINNETS der jeweiligen Blockketten. Der Grund dafür ist, dass Chainlink CCIP zum Zeitpunkt der Erstellung dieses Leitfadens im HyperEVM-Testnetz nicht verfügbar ist. Bitte seien Sie vorsichtig und setzen Sie nur Geld ein, dessen Verlust Sie verkraften können.
Einrichten der Entwicklungsumgebung
Wir werden Foundry verwenden, um unsere Smart Contracts zu kompilieren, bereitzustellen und mit ihnen zu interagieren. Falls Sie Foundry noch nicht installiert haben, können Sie dies tun, indem Sie den folgenden Befehl in Ihrem Terminal ausführen:
curl -L https://foundry.paradigm.xyz | bash
Befolgen Sie die Anweisungen auf dem Bildschirm, und anschließend können Sie die foundryup Befehl zur Installation von Foundry. Stellen Sie sicher, dass Sie diesen Befehl in einer neuen Terminalsitzung ausführen, damit die Änderungen an Ihrer PATH Variable.
foundryup
Wir benötigen lokal einen neuen Ordner, in dem unser Projekt für diese Anleitung gespeichert wird. Wir nennen unseren Ordner „hyperevm_ccip“, aber Sie können ihn beliebig benennen. Führen Sie diese Befehle in Ihrem Terminal aus, um den Ordner zu erstellen, und wechseln Sie mit Ihrem Code-Editor in diesen Ordner. In dieser Anleitung verwenden wir VS Code.
forge init hyperevm_ccip
cd hyperevm_ccip
code .
Zu diesem Zeitpunkt sollte Ihre Konfiguration in etwa so aussehen:

Super! Unsere Foundry-Projektstruktur ist nun eingerichtet. Als Nächstes erstellen Sie eine .env Datei im Stammverzeichnis Ihres Projektordners. Dort werden wir unsere Umgebungsvariablen speichern, wie beispielsweise unseren privaten Schlüssel und die RPC-URLs. Das Format der .env Die Datei sollte wie folgt aussehen:
HYPEREVM_RPC="Ihre_HypereVM-RPC-URL"
BSC_RPC="Ihre_BSC-RPC-URL"
PRIVATE_KEY="Ihr_privater_Schlüssel"
ETHERSCAN_API_KEY="Ihr_Etherscan-API-Schlüssel"
Wir werden gleich erläutern, was diese Variablen jeweils bedeuten und wie man sie ermittelt. Der nächste Schritt besteht darin, die Standardwerte zu löschen src/Counter.sol Vertrag und script/Counter.s.sol Skript, das Foundry für uns generiert. Diese werden wir in dieser Anleitung nicht verwenden. Alternativ können Sie die folgenden Befehle in Ihrem Terminal ausführen, um diese Dateien zu löschen:
rm src/Counter.sol
rm script/Counter.s.sol
Außerdem müssen Sie die foundry.toml Datei im Stammverzeichnis Ihres Projektordners, um wichtige Einstellungen für den Solidity-Compiler sowie Neuzuordnungen für die von uns verwendeten Import-Anweisungen festzulegen. So sieht Ihre foundry.toml Die Datei sollte wie folgt aussehen:
[Profil.Standard]
src = "src"
out = „out“
libs = [„lib“]
Optimierer = true
Optimierungsläufe = 200
Neuzuordnungen = [
'@chainlink/contracts-ccip/=node_modules/@chainlink/contracts-ccip/',
'@chainlink/contracts/=node_modules/@chainlink/contracts/',
]
fs_permissions = [{ Zugriff = "Lese-Schreib-Zugriff", Pfad = "./" }]
In dieser Datei haben wir Folgendes hinzugefügt: Optimierer Einstellungen zur Optimierung unserer Smart Contracts für die Bereitstellung. Die fs_permissions Dieser Eintrag ermöglicht es Foundry, Dateien im Projektverzeichnis zu lesen und zu schreiben. Der Neuzuordnungen Die Einträge sind die Pfade zu den Chainlink-Vertragspaketen, die wir in dieser Anleitung verwenden werden. Diese Pakete werden wir als Nächstes installieren.
Installation der Abhängigkeiten
In dieser Anleitung werden wir zwei Chainlink-Vertragspakete verwenden: @chainlink/contracts-ccip und @chainlink/Verträge. Das erste Paket enthält die zentralen CCIP-Verträge, mit denen wir interagieren werden, sowie die CCIP-Token-Pool-Verträge, die wir bereitstellen werden. Das zweite Paket enthält die maßgeschneiderten ERC20 Verträge, die den Anforderungen von Chainlink für kettenübergreifende Übertragungen entsprechen.
Außerdem werden wir die @layerzerolabs/hyperliquid-composer Paket, mit dem das Gaslimit für unsere Transaktionen auf HyperEVM erhöht wird. HyperEVM verfügt über ein Mehrblockarchitektur das aus kleineren Blöcken mit einem Gaslimit von 2 Millionen Gaseinheiten und größeren Blöcken mit einem Gaslimit von 30 Millionen Gaseinheiten besteht. Kleinere Blöcke haben eine Blockzeit von 1 Sekunde, während größere Blöcke eine Blockzeit von 1 Minute haben. Standardmäßig ist ein Konto auf HyperEVM darauf beschränkt, Transaktionen zu senden, die dem Gaslimit der kleineren Blöcke entsprechen. Mit diesem Paket können wir unser Konto so einrichten, dass es Transaktionen mit höheren Gaslimits senden kann, die in die größeren Blöcke passen.
Um diese Pakete zu installieren, geben Sie die folgenden Befehle mit Ihrem bevorzugten Paketmanager ein:
- npm
- Garn
npm install @chainlink/contracts-ccip @chainlink/contracts @layerzerolabs/hyperliquid-composer
yarn add @chainlink/contracts-ccip @chainlink/contracts @layerzerolabs/hyperliquid-composer
Super! Sie haben die Abhängigkeiten, die wir in dieser Anleitung verwenden werden, erfolgreich installiert. Als Nächstes werden wir die Umgebungsvariablen besprechen, die wir in unserer .env Datei.
Umgebungsvariablen
Quicknode-Endpunkte
Zunächst müssen wir die entsprechenden RPC-Endpunkte für HyperEVM und BSC abrufen. Diese finden Sie unter Quicknode. Melden Sie sich einfach für eine kostenlose Testversion an, erstellen Sie einen neuen Multi-Chain-Endpunkt und kopieren Sie die HTTPS-URLs für jede Chain. Fügen Sie die entsprechenden URLs in die HYPEREVM_RPC und BSC_RPC Variablen in Ihrer .env Datei.
Etherscan-API
Gehe anschließend zu deinem Profil auf Etherscan und wechseln Sie zur Registerkarte „API-Schlüssel“. Falls Sie noch kein Konto haben, erstellen Sie eines. hier. Hier erstellen Sie einen API-Schlüssel, mit dem Sie Ihre Smart Contracts in der Blockchain verifizieren können. Kopieren Sie den API-Schlüssel und fügen Sie ihn in das ETHERSCAN_API_KEY Variable in Ihrem .env Datei.
Privater Schlüssel
Zuletzt öffnest du MetaMask und kopierst den privaten Schlüssel eines deiner Konten. Wie du auf deinen privaten Schlüssel zugreifen kannst, erfährst du in dieser kurzen Anleitung Leitfaden. Fügen Sie diesen privaten Schlüssel in die PRIVATE_KEY Variable in Ihrem .env Datei.
Damit sind alle Umgebungsvariablen in Ihrer .env Die Datei sollte nun ausgefüllt sein. Der letzte Schritt bei dieser Einrichtung besteht darin, die entsprechenden Netzwerke zu unserer MetaMask-Wallet hinzuzufügen.
Netzwerke zu MetaMask hinzufügen
Wir werden die Netzwerke „HyperEVM Mainnet“ und „Binance Smart Chain Mainnet“ zu unserer MetaMask-Wallet hinzufügen. Am einfachsten fügen Sie diese Netzwerke hinzu, indem Sie auf hyperevmscan.io und bscscan.com und klicken Sie auf die Hinzufügen Schaltfläche unten links auf der Seite. Dadurch werden die Netzwerke zu Ihrer MetaMask-Wallet hinzugefügt:

Herzlichen Glückwunsch! Sie haben Ihre Entwicklungsumgebung für diese Anleitung erfolgreich eingerichtet. Als Nächstes werden wir ein HIP-1-Asset von HyperCore nach HyperEVM übertragen.
Brücke von HyperCore zu HyperEVM
Sie werden nun ein HIP-1-Asset von HyperCore auf HyperEVM übertragen. Bei diesem Vorgang wird das HIP-1-Asset in die entsprechende HyperEVM-Token-Darstellung umgewandelt. Für diese Anleitung verwenden wir die native Ökosystem-Coin von Hyperliquid: HYPE. Rufen Sie die Hyperliquid-Handelsoberfläche auf und melden Sie sich mit MetaMask an, um loszulegen.
Falls Sie noch keine HYPE-Coins besitzen, können Sie diese erwerben, indem Sie USDC vom Arbitrum-Mainnet bei Hyperliquid einzahlen und diese dann über den Spot-Handel auf der Handelsplattform gegen HYPE eintauschen:

Sobald Sie über HYPE verfügen, können Sie damit fortfahren, diese an HyperEVM zu überweisen. Klicken Sie dazu unten auf der Seite unterhalb des Diagramms auf die Schaltfläche „An/von EVM übertragen “. Geben Sie einfach den Betrag an HYPE ein, den Sie überweisen möchten, und klicken Sie auf „Bestätigen“.

Brücke von HYPE zu HyperEVM
Super! Sie haben HYPE erfolgreich von HyperCore auf HyperEVM übertragen. Sie sollten nun Ihren HYPE-Kontostand in MetaMask im HyperEVM-Netzwerk sehen können. Wir fahren nun mit der Erstellung eines Wrapper-Vertrags für HYPE fort, der den Anforderungen von Chainlink für kettenübergreifende Transfers entspricht.
Erstellen eines Wrapper-Vertrags für HYPE
Um HYPE mithilfe von Chainlink CCIP zwischen HyperEVM und BSC zu überbrücken, müssen wir einen Wrapper-Vertrag erstellen, der den Anforderungen von Chainlink für kettenübergreifende Transfers entspricht. Dazu müssen wir einen neuen ERC20-Token-Vertrag erstellen, der den bestehenden HYPE-Asset auf HyperEVM einbindet, sowie einen entsprechenden ERC20-Token-Vertrag auf BSC.
Wir werden ein Quicknode – Der Hype um das Produkt Token mit dem Symbol qWHYPE. Geben Sie den folgenden Befehl ein, um eine neue Solidity-Datei im Verzeichnis src Ordner in Ihrem Projektverzeichnis und fügen Sie den folgenden Code dort ein.
- Datei erstellen
- Code
touch src/qWHYPE.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import {BurnMintERC20} from "@chainlink/contracts/src/v0.8/shared/token/ERC20/BurnMintERC20.sol";
contract qWHYPE is BurnMintERC20 {
event Deposit(address indexed account, uint256 amount);
event Withdraw(address indexed account, uint256 amount);
constructor() BurnMintERC20("Quicknode Wrapped HYPE", "qWHYPE", 18, 0, 0) {}
function deposit() public payable {
_mint(msg.sender, msg.value);
emit Deposit(msg.sender, msg.value);
}
function withdraw(uint256 amount) external {
_burn(msg.sender, amount);
payable(msg.sender).transfer(amount);
emit Withdraw(msg.sender, amount);
}
}
Den Wrapper-Vertrag verstehen
Schauen wir uns den Code in der qWHYPE.sol Vertrag. Der Vertrag importiert die BurnMintERC20 Vertrag von der @chainlink/Verträge Paket, das die erforderlichen Funktionen zum Schaffen und Vernichten von Token bereitstellt. Wenn Nutzer HYPE in den Vertrag einzahlen, werden an ihre Adresse qWHYPE-Token in gleicher Höhe geschaffen. Umgekehrt werden, wenn Nutzer qWHYPE-Token abheben, die Token vom Vertrag vernichtet und die entsprechende Menge an HYPE zurück an die Adresse des Nutzers übertragen.
Dieser spezielle Vertrag wird im HyperEVM-Netzwerk bereitgestellt. Auf der BSC werden wir die Basisversion bereitstellen BurnMintERC20 direkt als Vertrag, da er keine zusätzlichen Funktionen erfordert. Im nächsten Abschnitt werden wir beide Verträge mithilfe von Skripten bereitstellen.
Schriften für die Schriftgießerei erstellen
Wir werden mehrere Foundry-Skripte erstellen, um unsere Smart Contracts bereitzustellen und mit ihnen zu interagieren. Dieser Abschnitt ist in mehrere Teile gegliedert, um jedes Skript im Detail zu behandeln. Wir werden die folgenden Skripte erstellen und sie in dieser Reihenfolge ausführen:
| Skriptname | Beschreibung |
|---|---|
DeployTokens.s.sol | Stellt den qWHYPE-Vertrag auf HyperEVM und der Basis bereit BurnMintERC20 Vertrag über BSC |
DeployPools.s.sol | Stellt die CCIP-Token-Pool-Verträge sowohl auf HyperEVM als auch auf BSC bereit |
SetupAdmin.s.sol | Registrieren und konfigurieren Sie die Administratorrollen in den CCIP-Verträgen für jede Kette |
ConfigurePools.s.sol | Konfiguriert unsere CCIP-Token-Pools für kettenübergreifende Transfers untereinander |
DepositAndTransferTokens.s.sol | Eine kleine Menge HYPE auf den qWHYPE-Kontrakt einzahlen, um qWHYPE-Token zu prägen, und anschließend eine kettenübergreifende Übertragung an BSC durchführen |
TransferTokens.s.sol | Führen Sie eine kettenübergreifende Übertragung von qWHYPE-Token in beide Richtungen durch |
Voraussetzungen
Bevor wir die Skripte schreiben, benötigen wir eine Möglichkeit, die Adressen unserer bereitgestellten Verträge zu verfolgen, sowie eine Datei zur Speicherung allgemeiner Konstanten, die wir in unseren Skripten verwenden werden.
Führen Sie die folgenden Befehle aus, um die entsprechenden Dateien zu erstellen:
touch script/Constants.s.sol
mkdir -p script/output
touch script/output/deployments.json
Wir werden das deployments.json Datei zur Nachverfolgung der Adressen der auf den einzelnen Blockchains bereitgestellten Verträge.
Hier ist, was die Konstanten.s.sol Die Datei sollte wie folgt aussehen:
Zum Anzeigen des Codes hier klicken
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import {Script} from "forge-std/Script.sol";
contract Constants is Script {
struct CCIPConstants {
uint64 chainSelector;
address router;
address rmnProxy;
address tokenAdminRegistry;
address registryModuleOwnerCustom;
string nativeCurrencySymbol;
}
function getCCIPConstants(uint256 chainId) public pure returns (CCIPConstants memory) {
if(chainId == 999) {
return CCIPConstants({
chainSelector: 2442541497099098535,
router: 0x13b3332b66389B1467CA6eBd6fa79775CCeF65ec,
rmnProxy: 0x07f15e9813FBd007d38CF534133C0838f449ecFA,
tokenAdminRegistry: 0xcE44363496ABc3a9e53B3F404a740F992D977bDF,
registryModuleOwnerCustom: 0xbAb3aBB5F29275065F2814F1f4B10Ffc1284fFEf,
nativeCurrencySymbol: "HYPE"
});
} else if (chainId == 56) {
return CCIPConstants({
chainSelector: 11344663589394136015,
router: 0x34B03Cb9086d7D758AC55af71584F81A598759FE,
rmnProxy: 0x9e09697842194f77d315E0907F1Bda77922e8f84,
tokenAdminRegistry: 0x736Fd8660c443547a85e4Eaf70A49C1b7Bb008fc,
registryModuleOwnerCustom: 0x47Db76c9c97F4bcFd54D8872FDb848Cab696092d,
nativeCurrencySymbol: "BNB"
});
}
revert("Chain not supported");
}
}
Skript-Menü
- DeployTokens.s.sol
- DeployPools.s.sol
- SetupAdmin.s.sol
- ConfigurePools.s.sol
- DepositAndTransferTokens.s.sol
- TransferTokens.s.sol
Dieses Skript stellt die qWHYPE Vertrag über HyperEVM und die Basis BurnMintERC20 Vertrag auf BSC. Erstellen Sie eine neue Datei in der Skript Ordner in Ihrem Projektverzeichnis mit dem Namen DeployTokens.s.sol und fügen Sie den folgenden Code dort ein.
Zum Anzeigen des Codes hier klicken
Erstellen Sie die Datei:
touch script/DeployTokens.s.sol
Füge den folgenden Code in die Datei ein:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import {Script, console} from "forge-std/Script.sol";
import {qWHYPE} from "../src/qWHYPE.sol";
import {BurnMintERC20} from "@chainlink/contracts/src/v0.8/shared/token/ERC20/BurnMintERC20.sol";
contract DeployTokens is Script {
string internal constant OUTPUT_PATH = "script/output/deployments.json";
/// forge script script/DeployTokens.s.sol:DeployTokens
function run() external {
// Load env vars
bytes memory hyperevm = bytes(vm.envString("HYPEREVM_RPC"));
bytes memory bsc = bytes(vm.envString("BSC_RPC"));
uint256 pk = vm.envUint("PRIVATE_KEY");
// Check if env vars are set
require(hyperevm.length != 0, "HYPEREVM_RPC not set");
require(bsc.length != 0, "BSC_RPC not set");
// print deployer address
address deployer = vm.addr(pk);
console.log("Deployer address:", deployer);
// Deploy on both chains
address hyperAddr = deployOn(hyperevm, deployer, pk);
address bscAddr = deployOn(bsc, deployer, pk);
// Write deployed addresses to JSON file
string memory obj = vm.serializeString("deployments", "qWHYPE_hyperevm", vm.toString(hyperAddr));
obj = vm.serializeString("deployments", "qWHYPE_bsc", vm.toString(bscAddr));
vm.writeJson(obj, OUTPUT_PATH);
}
function deployOn(bytes memory rpc, address deployer, uint256 pk) internal returns (address) {
vm.selectFork(vm.createFork(string(rpc)));
vm.startBroadcast(pk);
string memory chainName = getChainName(block.chainid);
address tokenAddr = address(block.chainid == 999 ? new qWHYPE() : new BurnMintERC20("Quicknode Wrapped HYPE", "qWHYPE", 18, 0, 0));
console.log("\nDeployed qWHYPE to:", tokenAddr, "on", chainName);
BurnMintERC20(tokenAddr).grantMintAndBurnRoles(deployer);
console.log("Granted minter and burner roles on", chainName, "qWHYPE to:", deployer);
vm.stopBroadcast();
return tokenAddr;
}
function getChainName(uint256 chainId) internal pure returns (string memory) {
if (chainId == 56) return "\x1b[36mBSC Mainnet\x1b[0m";
else if (chainId == 999) return "\x1b[32mHyperEVM Mainnet\x1b[0m";
else revert("Unsupported chain ID");
}
}
Das DeployTokens-Skript verstehen
In diesem Skript laden wir zunächst die Umgebungsvariablen für die RPC-URLs und den privaten Schlüssel. Anschließend definieren wir eine deployOn Funktion, die eine RPC-URL, die Adresse des Deployers und einen privaten Schlüssel als Parameter entgegennimmt. Diese Funktion erstellt einen Fork der angegebenen Chain, beginnt mit der Übertragung von Transaktionen unter Verwendung des bereitgestellten privaten Schlüssels und stellt entweder das qWHYPE Vertrag (auf HyperEVM) oder die Basis BurnMintERC20 Vertrag (auf BSC). Nach der Bereitstellung gewährt er der Adresse des Bereitstellers die Rechte zum Prägen und Verbrennen des bereitgestellten Token-Vertrags.
Dieses Skript stellt die CCIP-Token-Pool-Verträge sowohl auf HyperEVM als auch auf BSC bereit. Erstellen Sie eine neue Datei im Skript Ordner in Ihrem Projektverzeichnis mit dem Namen DeployPools.s.sol und fügen Sie den folgenden Code dort ein.
Zum Anzeigen des Codes hier klicken
Erstellen Sie die Datei:
touch script/DeployPools.s.sol
Füge den folgenden Code in die Datei ein:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import {Script} from "forge-std/Script.sol";
import {BurnMintERC20} from "@chainlink/contracts/src/v0.8/shared/token/ERC20/BurnMintERC20.sol";
import {IBurnMintERC20} from "@chainlink/contracts/src/v0.8/shared/token/ERC20/IBurnMintERC20.sol";
import {BurnMintTokenPool} from "@chainlink/contracts-ccip/contracts/pools/BurnMintTokenPool.sol";
import {Constants} from "./Constants.s.sol";
contract DeployPools is Script {
string internal constant OUTPUT_PATH = "script/output/deployments.json";
/// forge script script/DeployPools.s.sol:DeployPools
function run() external {
// Load env vars
bytes memory hyperevm = bytes(vm.envString("HYPEREVM_RPC"));
bytes memory bsc = bytes(vm.envString("BSC_RPC"));
uint256 pk = vm.envUint("PRIVATE_KEY");
// Check if env vars are set
require(hyperevm.length != 0, "HYPEREVM_RPC not set");
require(bsc.length != 0, "BSC_RPC not set");
// Read deployed token addresses from JSON
string memory json = vm.readFile(OUTPUT_PATH);
address tokenHyp = vm.parseJsonAddress(json, ".qWHYPE_hyperevm");
address tokenBsc = vm.parseJsonAddress(json, ".qWHYPE_bsc");
// Fetch CCIP constants
Constants constants = new Constants();
Constants.CCIPConstants memory cfgHyp = constants.getCCIPConstants(999);
Constants.CCIPConstants memory cfgBsc = constants.getCCIPConstants(56);
// Create forks up front
uint256 hyperFork = vm.createFork(string(hyperevm));
uint256 bscFork = vm.createFork(string(bsc));
// Deploy pool on HyperEVM
vm.selectFork(hyperFork);
vm.startBroadcast(pk);
address poolHyp = address(new BurnMintTokenPool(IBurnMintERC20(tokenHyp), 18, new address[](0), cfgHyp.rmnProxy, cfgHyp.router));
BurnMintERC20(tokenHyp).grantMintAndBurnRoles(poolHyp);
vm.stopBroadcast();
// Deploy pool on BSC
vm.selectFork(bscFork);
vm.startBroadcast(pk);
address poolBsc = address(new BurnMintTokenPool(IBurnMintERC20(tokenBsc), 18, new address[](0), cfgBsc.rmnProxy, cfgBsc.router));
BurnMintERC20(tokenBsc).grantMintAndBurnRoles(poolBsc);
vm.stopBroadcast();
// Write deployed addresses to JSON file
string memory out = vm.serializeString("deployments", "qWHYPE_hyperevm", vm.toString(tokenHyp));
out = vm.serializeString("deployments", "qWHYPE_bsc", vm.toString(tokenBsc));
out = vm.serializeString("deployments", "qWHYPE_pool_hyperevm", vm.toString(poolHyp));
out = vm.serializeString("deployments", "qWHYPE_pool_bsc", vm.toString(poolBsc));
vm.writeJson(out, OUTPUT_PATH);
}
}
Das DeployPools-Skript verstehen
In diesem Skript laden wir zunächst die Umgebungsvariablen für die RPC-URLs und den privaten Schlüssel. Anschließend lesen wir die Adressen der bereitgestellten Token aus der deployments.json Datei, die im vorherigen Skript erstellt wurde. Wir rufen die erforderlichen CCIP-Konstanten sowohl für HyperEVM als auch für BSC mithilfe der Konstanten Vertrag.
Zu diesen Konstanten gehören die von Chainlink auf jeder Blockchain bereitgestellten zentralen CCIP-Verträge, darunter der Router, die TokenAdminRegistry, das RegistryModuleOwnerCustom sowie die für die Bereitstellung des Pools erforderlichen Proxy-Adressen des RiskManagementNetwork (RMN). Der Router ist für das Weiterleiten kettenübergreifender Nachrichten zuständig, die TokenAdminRegistry verwaltet eine Zuordnung von Token-Adressen zu ihren jeweiligen Pools, das RegistryModuleOwnerCustom dient der Registrierung von Token-Administratoren für verschiedene Eigentumsmodelle und der RMN-Proxy wird zur Überprüfung von RMN-Signaturen für kettenübergreifende Nachrichten verwendet.
Unter Verwendung dieser Konstanten setzen wir die BurnMintTokenPool Verträge auf beiden Blockchains, wodurch ihnen die Befugnisse zum Prägen und Verbrennen ihrer jeweiligen Token-Verträge gewährt werden. Schließlich aktualisieren wir die deployments.json Datei mit den Adressen der bereitgestellten Token-Pools.
Dieses Skript registriert den Administrator der Token, die wir in den CCIP-Registry-Verträgen für jede Chain bereitgestellt haben. Erstellen Sie eine neue Datei im Skript Ordner in Ihrem Projektverzeichnis mit dem Namen SetupAdmin.s.sol und fügen Sie den folgenden Code dort ein.
Zum Anzeigen des Codes hier klicken
Erstellen Sie die Datei:
touch script/SetupAdmin.s.sol
Füge den folgenden Code in die Datei ein:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import {Script, console} from "forge-std/Script.sol";
import {TokenAdminRegistry} from "@chainlink/contracts-ccip/contracts/tokenAdminRegistry/TokenAdminRegistry.sol";
import {RegistryModuleOwnerCustom} from "@chainlink/contracts-ccip/contracts/tokenAdminRegistry/RegistryModuleOwnerCustom.sol";
import {Constants} from "./Constants.s.sol";
contract SetupAdmin is Script {
string internal constant OUTPUT_PATH = "script/output/deployments.json";
/// forge script script/SetupAdmin.s.sol:SetupAdmin
function run() external {
// Load env vars
bytes memory hyperevm = bytes(vm.envString("HYPEREVM_RPC"));
bytes memory bsc = bytes(vm.envString("BSC_RPC"));
uint256 pk = vm.envUint("PRIVATE_KEY");
// Check if env vars are set
require(hyperevm.length != 0, "HYPEREVM_RPC not set");
require(bsc.length != 0, "BSC_RPC not set");
// Read deployed token addresses
string memory json = vm.readFile(OUTPUT_PATH);
address tokenHyp = vm.parseJsonAddress(json, ".qWHYPE_hyperevm");
address tokenBsc = vm.parseJsonAddress(json, ".qWHYPE_bsc");
// Fork both chains up front
uint256 hyperFork = vm.createFork(string(hyperevm));
uint256 bscFork = vm.createFork(string(bsc));
// Do HyperEVM
vm.selectFork(hyperFork);
_registerAndAccept(tokenHyp, pk);
// Do BSC
vm.selectFork(bscFork);
_registerAndAccept(tokenBsc, pk);
}
function _registerAndAccept(address token, uint256 pk) internal {
Constants constants = new Constants();
Constants.CCIPConstants memory cfg = constants.getCCIPConstants(block.chainid);
address ownerCustomModule = cfg.registryModuleOwnerCustom;
address tokenAdminRegistry = cfg.tokenAdminRegistry;
string memory chainName = _getChainName(block.chainid);
vm.startBroadcast(pk);
// Register admin on RegistryModuleOwnerCustom (msg.sender becomes pending admin)
RegistryModuleOwnerCustom(ownerCustomModule).registerAdminViaGetCCIPAdmin(token);
console.log("Proposed admin via OwnerCustom on", chainName);
// Accept the admin role from the pending admin
TokenAdminRegistry tokenAdminRegistryContract = TokenAdminRegistry(tokenAdminRegistry);
TokenAdminRegistry.TokenConfig memory config = tokenAdminRegistryContract.getTokenConfig(token);
address pendingAdmin = config.pendingAdministrator;
require(pendingAdmin == vm.addr(pk), "Pending admin mismatch");
tokenAdminRegistryContract.acceptAdminRole(token);
console.log("Successfully registered and accepted admin role for token on", chainName, ": ", token);
vm.stopBroadcast();
}
function _getChainName(uint256 chainId) internal pure returns (string memory) {
if (chainId == 56) return "BSC";
if (chainId == 999) return "HyperEVM";
return "Unknown";
}
}
Das SetupAdmin-Skript verstehen
In diesem Skript laden wir zunächst die Umgebungsvariablen für die RPC-URLs und den privaten Schlüssel. Anschließend lesen wir die Adressen der bereitgestellten Token aus der deployments.json Datei. Diese Token-Adressen werden von den CCIP-Registrierungsverträgen benötigt, um die Administratoren der einzelnen Token abzurufen und anschließend in ihren jeweiligen Blockchains zu registrieren.
Die Registrierung des Administrators eines CCIP-Tokens erfolgt in zwei Schritten. Zunächst wird der RegistryModuleOwnerCustom Der Vertrag wird aufgerufen. Dieser Vertrag dient dazu, einen neuen Administrator für das Token vorzuschlagen. Der aktuelle Administrator, der über getCCIPAdmin auf unserer qWHYPE Vertrag, wird zum zuständigen Sachbearbeiter. Der RegistryModuleOwnerCustom nennt die TokenAdminRegistry Vertrag zur Einführung der neuen Verwaltung. Dieser Zustand wird dann einem TokenConfig struct in der TokenAdminRegistry Vertrag. Dann der letzte Schritt, der TokenAdminRegistry Die Funktion wird aufgerufen, um die Administratorrolle des ausstehenden Administrators zu übernehmen, der aus der TokenConfig für das angegebene Token.
Vielleicht fragen Sie sich, warum die Registrierung des Administrators eines Tokens in diesem aufwendigen zweistufigen Verfahren erfolgt. Warum wird der Administrator nicht einfach direkt auf der TokenAdminRegistry Vertrag? Für diese Gestaltungsentscheidung gibt es mehrere Gründe:
- Erhöhte Sicherheit: Durch den zweistufigen Prozess kann der derzeitige Administrator den neuen Administrator vor der endgültigen Bestätigung prüfen und genehmigen.
- Multisig-Kompatibilität: Kompatibel mit Multisig-Wallets (z. B. Safe), indem Admin-Änderungen vorgeschlagen und später akzeptiert werden.
- Eigentumsverhältnisse: kompatibel mit dem Eigentumsmodell von CCIP über
getCCIPOwnerund dank des „Ownable“-basierten Eigentumsmodells von OpenZeppelin, das unter anderem die Einbindung einer Vielzahl bestehender Token ermöglicht.
Dieses Skript konfiguriert unsere CCIP-Token-Pools für kettenübergreifende Übertragungen untereinander. Erstellen Sie eine neue Datei im Verzeichnis Skript Ordner in Ihrem Projektverzeichnis mit dem Namen ConfigurePools.s.sol und fügen Sie den folgenden Code dort ein.
Zum Anzeigen des Codes hier klicken
Erstellen Sie die Datei:
touch script/ConfigurePools.s.sol
Füge den folgenden Code in die Datei ein:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import {Script, console} from "forge-std/Script.sol";
import {TokenAdminRegistry} from "@chainlink/contracts-ccip/contracts/tokenAdminRegistry/TokenAdminRegistry.sol";
import {TokenPool} from "@chainlink/contracts-ccip/contracts/pools/TokenPool.sol";
import {RateLimiter} from "@chainlink/contracts-ccip/contracts/libraries/RateLimiter.sol";
import {Constants} from "./Constants.s.sol";
contract ConfigurePools is Script {
struct Params {
address localToken;
address localPool;
address tokenAdminRegistry;
uint64 remoteSelector;
address remotePool;
address remoteToken;
uint256 pk;
string chainName;
}
string internal constant OUTPUT_PATH = "script/output/deployments.json";
/// forge script script/ConfigurePools.s.sol:ConfigurePools
function run() external {
// Load env vars
bytes memory hyperevm = bytes(vm.envString("HYPEREVM_RPC"));
bytes memory bsc = bytes(vm.envString("BSC_RPC"));
uint256 pk = vm.envUint("PRIVATE_KEY");
require(hyperevm.length != 0, "HYPEREVM_RPC not set");
require(bsc.length != 0, "BSC_RPC not set");
// Load deployed addresses
string memory json = vm.readFile(OUTPUT_PATH);
address tokenHyp = vm.parseJsonAddress(json, ".qWHYPE_hyperevm");
address tokenBsc = vm.parseJsonAddress(json, ".qWHYPE_bsc");
address poolHyp = vm.parseJsonAddress(json, ".qWHYPE_pool_hyperevm");
address poolBsc = vm.parseJsonAddress(json, ".qWHYPE_pool_bsc");
// Preload constants for both chains
Constants constants = new Constants();
Constants.CCIPConstants memory cfgHyp = constants.getCCIPConstants(999);
Constants.CCIPConstants memory cfgBsc = constants.getCCIPConstants(56);
// Forks
uint256 hyperFork = vm.createFork(string(hyperevm));
uint256 bscFork = vm.createFork(string(bsc));
// Configure HyperEVM pool and registry
vm.selectFork(hyperFork);
Params memory pHyp = Params({
localToken: tokenHyp,
localPool: poolHyp,
tokenAdminRegistry: cfgHyp.tokenAdminRegistry,
remoteSelector: cfgBsc.chainSelector,
remotePool: poolBsc,
remoteToken: tokenBsc,
pk: pk,
chainName: "HyperEVM"
});
_setPoolAndApplyChainUpdates(pHyp);
// Configure BSC pool and registry
vm.selectFork(bscFork);
Params memory pBsc = Params({
localToken: tokenBsc,
localPool: poolBsc,
tokenAdminRegistry: cfgBsc.tokenAdminRegistry,
remoteSelector: cfgHyp.chainSelector,
remotePool: poolHyp,
remoteToken: tokenHyp,
pk: pk,
chainName: "BSC"
});
_setPoolAndApplyChainUpdates(pBsc);
}
function _setPoolAndApplyChainUpdates(Params memory p) internal {
// Set pool in TokenAdminRegistry (maps token -> pool)
vm.startBroadcast(p.pk);
TokenAdminRegistry(p.tokenAdminRegistry).setPool(p.localToken, p.localPool);
console.log("setPool set on ", p.localPool);
// Configure pool with remote chain, pool, rate limits
TokenPool pool = TokenPool(p.localPool);
TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](1);
// Encode remote pool addresses (single entry)
bytes[] memory remotePoolAddressesEncoded = new bytes[](1);
remotePoolAddressesEncoded[0] = abi.encode(p.remotePool);
chainUpdates[0] = TokenPool.ChainUpdate({
remoteChainSelector: p.remoteSelector,
remotePoolAddresses: remotePoolAddressesEncoded,
remoteTokenAddress: abi.encode(p.remoteToken),
outboundRateLimiterConfig: RateLimiter.Config({isEnabled: false, capacity: 0, rate: 0}),
inboundRateLimiterConfig: RateLimiter.Config({isEnabled: false, capacity: 0, rate: 0})
});
// No removals, apply chain updates
uint64[] memory chainSelectorRemovals = new uint64[](0);
pool.applyChainUpdates(chainSelectorRemovals, chainUpdates);
console.log("Chain update applied to pool at address:");
console.log(p.localPool);
vm.stopBroadcast();
}
}
Das Skript „ConfigurePools“ verstehen
In diesem Skript laden wir zunächst die Umgebungsvariablen für die RPC-URLs und den privaten Schlüssel. Anschließend lesen wir das bereitgestellte Token und die Pool-Adressen aus der deployments.json Datei. Wir rufen die erforderlichen CCIP-Konstanten sowohl für HyperEVM als auch für BSC mithilfe der Konstanten Vertrag. Zu diesen Konstanten gehören die TokenAdminRegistry Adresse und Kettenauswahl, die benötigt werden, um den Pool für jedes Token festzulegen.
Wir haben eine Parameter Eine Struktur, die alle notwendigen Parameter zur Konfiguration der einzelnen Pools enthält. Das ist nicht nur übersichtlicher, sondern hilft auch dabei, „Stack too deep“-Fehler in Solidity zu vermeiden. Wir nennen die setPool Funktion auf der TokenAdminRegistry Vertrag, um jedes Token seinem jeweiligen Pool zuzuordnen. Als Nächstes konfigurieren wir jeden Pool mit dem Remote-Chain-Selektor, der Remote-Pool-Adresse und der Remote-Token-Adresse mithilfe des applyChainUpdates Funktion auf der TokenPool Vertrag. In diesem Beispiel deaktivieren wir der Einfachheit halber die Ratenbegrenzung, doch in einer Produktionsumgebung können Sie geeignete Ratenbegrenzungen entsprechend Ihren Anforderungen konfigurieren.
Dieses Skript wird eine kleine Menge HYPE auf den qWHYPE-Kontrakt einzahlen, um qWHYPE-Token zu prägen, und anschließend eine kettenübergreifende Übertragung an BSC durchführen. Erstellen Sie eine neue Datei im Skript Ordner in Ihrem Projektverzeichnis mit dem Namen DepositAndTransferTokens.s.sol und fügen Sie den folgenden Code dort ein.
Zum Anzeigen des Codes hier klicken
Erstellen Sie die Datei:
touch script/DepositAndTransferTokens.s.sol
Füge den folgenden Code in die Datei ein:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import {Script, console} from "forge-std/Script.sol";
import {IERC20} from "@chainlink/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
import {IRouterClient} from "@chainlink/contracts-ccip/contracts/interfaces/IRouterClient.sol";
import {Client} from "@chainlink/contracts-ccip/contracts/libraries/Client.sol";
import {Constants} from "./Constants.s.sol";
import {qWHYPE} from "../src/qWHYPE.sol";
contract DepositAndTransferTokens is Script {
string internal constant OUTPUT_PATH = "script/output/deployments.json";
/// forge script script/DepositAndTransferTokens.s.sol:DepositAndTransferTokens
function run() external {
// Load env vars
bytes memory hyperevm = bytes(vm.envString("HYPEREVM_RPC"));
bytes memory bsc = bytes(vm.envString("BSC_RPC"));
uint256 pk = vm.envUint("PRIVATE_KEY");
require(hyperevm.length != 0, "HYPEREVM_RPC not set");
require(bsc.length != 0, "BSC_RPC not set");
// Read deployed token addresses
string memory json = vm.readFile(OUTPUT_PATH);
address tokenHyp = vm.parseJsonAddress(json, ".qWHYPE_hyperevm");
// Create forks and select HyperEVM (source)
uint256 hyperFork = vm.createFork(string(hyperevm));
vm.selectFork(hyperFork);
// Resolve CCIP constants for source and destination
Constants constants = new Constants();
Constants.CCIPConstants memory cfgHyp = constants.getCCIPConstants(999);
Constants.CCIPConstants memory cfgBsc = constants.getCCIPConstants(56);
address router = cfgHyp.router;
uint64 destinationChainSelector = cfgBsc.chainSelector;
address sender = vm.addr(pk);
// Amount to wrap and transfer: 0.01 HYPE -> 0.01 qWHYPE (18 decimals)
uint256 amount = 0.01 ether;
vm.startBroadcast(pk);
// Deposit HYPE to mint qWHYPE on HyperEVM
qWHYPE(tokenHyp).deposit{value: amount}();
console.log("Deposited and minted qWHYPE amount");
console.log(amount);
// Approve router to spend qWHYPE
IERC20(tokenHyp).approve(router, amount);
console.log("Approved router to spend qWHYPE");
// Build CCIP EVM2AnyMessage for token transfer
Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
tokenAmounts[0] = Client.EVMTokenAmount({token: tokenHyp, amount: amount});
Client.EVMExtraArgsV1 memory extraArgs = Client.EVMExtraArgsV1({gasLimit: 0});
bytes memory extraArgsBytes = Client._argsToBytes(extraArgs);
Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
receiver: abi.encode(sender),
data: abi.encode(),
tokenAmounts: tokenAmounts,
feeToken: address(0), // pay fees in native
extraArgs: extraArgsBytes
});
// Route via CCIP using native token for gas
IRouterClient routerClient = IRouterClient(router);
require(routerClient.isChainSupported(destinationChainSelector), "Dest chain not supported");
uint256 fee = routerClient.getFee(destinationChainSelector, message);
console.log("Estimated fee (native)", fee);
bytes32 messageId = routerClient.ccipSend{value: fee}(destinationChainSelector, message);
console.log("CCIP messageId");
console.logBytes32(messageId);
vm.stopBroadcast();
}
}
Das „DepositAndTransferTokens“-Skript verstehen
In diesem Skript laden wir zunächst die Umgebungsvariablen für die RPC-URLs und den privaten Schlüssel. Anschließend lesen wir die Adresse des bereitgestellten Tokens aus der deployments.json Datei. Wir erstellen einen Fork der HyperEVM-Chain, der als Quell-Chain für den kettenübergreifenden Transfer dienen wird.
Wir rufen die erforderlichen CCIP-Konstanten sowohl für HyperEVM als auch für BSC mithilfe der Konstanten Vertrag. Zu diesen Konstanten gehören die Router Adresse und Kettenauswahl, die zum Senden der kettenübergreifenden Nachricht erforderlich sind. Wir legen den Betrag an HYPE fest, den wir einzahlen und übertragen möchten; in diesem Beispiel sind das 0,01 HYPE.
Wir nennen das Einzahlung Funktion auf der qWHYPE Vertrag zur Prägung von qWHYPE-Token durch Einzahlung von HYPE. Als Nächstes erteilen wir dem Router die Berechtigung, unsere qWHYPE-Token auszugeben. Anschließend erstellen wir einen Client.EVM2AnyMessage Eine Struktur, die die Details unserer kettenübergreifenden Übertragung enthält, darunter die Empfängeradresse, die Token-Beträge und etwaige zusätzliche Argumente.
Abschließend rufen wir die ccipSend Funktion im Router-Vertrag, um die kettenübergreifende Nachricht zu senden, wobei die erforderliche Gebühr im nativen Token der Quellkette (HYPE) entrichtet wird. Das Skript protokolliert die geschätzte Gebühr und die Nachrichten-ID der CCIP-Übertragung. Anhand dieser Nachrichten-ID lässt sich der Status der Übertragung auf der Chainlink CCIP Explorer.
Dieses Skript führt eine kettenübergreifende Übertragung von qWHYPE-Token in beide Richtungen durch. Erstellen Sie eine neue Datei im Skript Ordner in Ihrem Projektverzeichnis mit dem Namen TransferTokens.s.sol und fügen Sie den folgenden Code dort ein.
Zum Anzeigen des Codes hier klicken
Erstellen Sie die Datei:
touch script/TransferTokens.s.sol
Füge den folgenden Code in die Datei ein:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import {Script, console} from "forge-std/Script.sol";
import {IERC20} from "@chainlink/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
import {IRouterClient} from "@chainlink/contracts-ccip/contracts/interfaces/IRouterClient.sol";
import {Client} from "@chainlink/contracts-ccip/contracts/libraries/Client.sol";
import {Constants} from "./Constants.s.sol";
// Transfer-only script: does NOT deposit. Assumes caller holds qWHYPE on source chain.
contract TransferTokens is Script {
string internal constant OUTPUT_PATH = "script/output/deployments.json";
uint256 internal constant AMOUNT = 0.01 ether;
/// forge script script/TransferTokens.s.sol:TransferTokens --sig 'run(string)' <to-bsc | to-hyperevm>
function run(string memory to) external {
bool toBsc = _eq(to, "to-bsc");
require(toBsc || _eq(to, "to-hyperevm"), "to must be 'to-bsc' or 'to-hyperevm'");
_run(toBsc);
}
function run() external {
string memory to = vm.envOr("TO", string(""));
require(bytes(to).length != 0, "Set TO or use run(string)");
bool toBsc = _eq(to, "to-bsc");
require(toBsc || _eq(to, "to-hyperevm"), "to must be 'to-bsc' or 'to-hyperevm'");
_run(toBsc);
}
function _run(bool toBsc) internal {
// Validate RPCs and select source fork
require(bytes(vm.envString("HYPEREVM_RPC")).length != 0, "HYPEREVM_RPC not set");
require(bytes(vm.envString("BSC_RPC")).length != 0, "BSC_RPC not set");
vm.selectFork(vm.createFork(toBsc ? vm.envString("HYPEREVM_RPC") : vm.envString("BSC_RPC")));
// Resolve router and destination selector
address router = (new Constants()).getCCIPConstants(block.chainid).router;
uint64 destSelector = (new Constants()).getCCIPConstants(toBsc ? 56 : 999).chainSelector;
// Source token address
address srcToken = toBsc
? vm.parseJsonAddress(vm.readFile(OUTPUT_PATH), ".qWHYPE_hyperevm")
: vm.parseJsonAddress(vm.readFile(OUTPUT_PATH), ".qWHYPE_bsc");
// Start broadcasting
vm.startBroadcast(vm.envUint("PRIVATE_KEY"));
// Approve router to spend qWHYPE
IERC20(srcToken).approve(router, AMOUNT);
console.log("Approved router to spend qWHYPE");
// Build token amounts
Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
tokenAmounts[0] = Client.EVMTokenAmount({token: srcToken, amount: AMOUNT});
// Send via CCIP using native gas as fee
require(IRouterClient(router).isChainSupported(destSelector), "Dest chain not supported");
uint256 fee = IRouterClient(router).getFee(
destSelector,
Client.EVM2AnyMessage({
receiver: abi.encode(vm.addr(vm.envUint("PRIVATE_KEY"))),
data: abi.encode(),
tokenAmounts: tokenAmounts,
feeToken: address(0),
extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 0}))
})
);
console.log("Estimated fee (native)");
console.log(fee);
console.log("CCIP messageId");
console.logBytes32(
IRouterClient(router).ccipSend{value: fee}(
destSelector,
Client.EVM2AnyMessage({
receiver: abi.encode(vm.addr(vm.envUint("PRIVATE_KEY"))),
data: abi.encode(),
tokenAmounts: tokenAmounts,
feeToken: address(0),
extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 0}))
})
)
);
vm.stopBroadcast();
}
function _eq(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}
Das „TransferTokens“-Skript verstehen
In diesem Skript prüfen wir zunächst, ob das im Terminal übergebene Argument entweder to-bsc oder to-hyperevm, wobei die Richtung der Übertragung angegeben wird. Auf dieser Grundlage erstellen wir einen Fork der entsprechenden Quellkette (HyperEVM oder BSC). Wir rufen die erforderlichen CCIP-Konstanten für beide Ketten mithilfe der Konstanten Vertrag. Zu diesen Konstanten gehören die Router Adresse und Kettenauswahl, die zum Senden der kettenübergreifenden Nachricht erforderlich sind.
Wir legen einen festen Betrag an qWHYPE fest, der übertragen werden soll; in diesem Beispiel sind das 0,01 qWHYPE. Wir erteilen dem Router die Erlaubnis, unsere qWHYPE-Token auszugeben, und erstellen einen Client.EVM2AnyMessage Eine Struktur, die die Details unserer kettenübergreifenden Übertragung enthält, darunter die Empfängeradresse, die Token-Beträge und etwaige zusätzliche Argumente.
Abschließend rufen wir die ccipSend Funktion im Router-Vertrag, um die kettenübergreifende Nachricht zu senden, wobei die erforderliche Gebühr im nativen Token der Quellkette (HYPE oder BNB) entrichtet wird. Das Skript protokolliert die geschätzte Gebühr und die Nachrichten-ID der CCIP-Übertragung. Anhand dieser Nachrichten-ID lässt sich der Status der Übertragung auf der Chainlink CCIP Explorer.
Großartig! Wir haben nun alle erforderlichen Skripte geschrieben, um unsere CCIP-Token-Pools bereitzustellen und zu konfigurieren sowie kettenübergreifende Übertragungen von qWHYPE-Token zwischen HyperEVM und BSC durchzuführen. Im nächsten Abschnitt werden wir nun mit der Ausführung dieser Skripte fortfahren.
Ausführen der Skripte
Nachdem wir nun alle erforderlichen Skripte geschrieben haben, können wir sie nacheinander ausführen, um unsere CCIP-Token-Pools bereitzustellen und zu konfigurieren sowie eine kettenübergreifende Übertragung von qWHYPE-Token durchzuführen.
Wir haben bereits die Multi-Block-Architektur von Hyperliquid besprochen: Kleinere Blöcke verbrauchen maximal 2M Gas, während größere Blöcke bis zu 30M Gas verbrauchen können. Unsere Transaktionen zur Vertragsbereitstellung werden das Gaslimit von 2M mit Sicherheit überschreiten, daher müssen wir zunächst unser Konto für die Nutzung größerer Blöcke freischalten. Führen Sie dazu den folgenden Befehl in Ihrem Terminal aus:
source .env
npx @layerzerolabs/hyperliquid-composer set-block --size big --network mainnet --private-key $PRIVATE_KEY
Wir empfehlen, Ihren privaten Schlüssel nicht direkt in der Befehlszeile anzugeben, da er möglicherweise im Verlauf Ihrer Shell gespeichert wird. Verwenden Sie für den Umgang mit sensiblen Informationen stets Umgebungsvariablen oder sichere Methoden!
Wenn Ihre Wallet nicht bei HyperCore registriert ist, schlägt dieser Befehl möglicherweise mit folgender Fehlermeldung fehl: Der Benutzer oder die API-Wallet existiert nicht. Stellen Sie sicher, dass Sie eine Einzahlung getätigt oder einen Handel auf Hyperliquid durchgeführt haben, um Ihre Wallet zu registrieren. Wenn Sie die Schritte in Brücke von HyperCore zu HyperEVM Richtig, Ihre Wallet ist bereits registriert!
Super! Unser Konto kann nun größere Blöcke verwenden. Wir werden unsere Token nun mithilfe des DeployTokens.s.sol Skript:
forge script script/DeployTokens.s.sol:DeployTokens --broadcast --verify --verifier etherscan
Dieser Befehl stellt unsere Token sowohl im HyperEVM- als auch im BSC-Netzwerk bereit. Der Fortschritt der Bereitstellung wird in Ihrem Terminal angezeigt, und sobald die Transaktionen bestätigt sind, werden die Transaktions-Hashes angezeigt. Die --Sendung Das Flag zeigt an, dass wir die Transaktionen an das Netzwerk senden möchten, während das --verify und --Verifizierer Etherscan flags überprüft unsere Smart Contracts nach der Bereitstellung automatisch auf hyperevmscan.io und bscscan.com. Sie werden außerdem feststellen, dass Ihre deployments.json Die Datei wurde mit den Adressen der bereitgestellten Verträge gefüllt. Die Ausgabe auf Ihrem Terminal sollte in etwa so aussehen:

Als Nächstes werden wir unsere CCIP-Token-Pools mithilfe des DeployPools.s.sol Skript:
forge script script/DeployPools.s.sol:DeployPools --broadcast --verify --verifier etherscan
Dieser Befehl stellt unsere Token-Pools sowohl im HyperEVM- als auch im BSC-Netzwerk bereit. Ähnlich wie im vorherigen Schritt werden Ihnen der Fortschritt der Bereitstellung in Ihrem Terminal sowie die Transaktions-Hashes angezeigt, sobald die Transaktionen bestätigt sind. Der deployments.json Die Datei wird mit den Adressen der bereitgestellten Pools aktualisiert. Die Ausgabe auf Ihrem Terminal sollte in etwa so aussehen:

Als Nächstes richten wir den Admin-Bereich für unsere Tokens mithilfe der SetupAdmin.s.sol Skript und konfigurieren unsere Pools mithilfe des ConfigurePools.s.sol Skript. Mit den folgenden Befehlen können wir beide Skripte nacheinander ausführen:
forge script script/SetupAdmin.s.sol:SetupAdmin --broadcast
forge script script/ConfigurePools.s.sol:ConfigurePools --broadcast
Wie im vorherigen Schritt wird eine ähnliche Terminalausgabe mit den Transaktions-Hashes angezeigt, sobald die Transaktionen bestätigt sind.
Unsere erste kettenübergreifende Übertragung
Abschließend werden wir eine kettenübergreifende Übertragung von qWHYPE-Token von HyperEVM zu BSC mithilfe der DepositAndTransferTokens.s.sol Skript:
forge script script/DepositAndTransferTokens.s.sol:DepositAndTransferTokens --broadcast
Dieser Befehl hinterlegt HYPE, um qWHYPE auf HyperEVM zu prägen, und überträgt anschließend die qWHYPE-Token an BSC. Sobald die Transaktion bestätigt ist, werden Ihnen der Fortschritt der Übertragung in Ihrem Terminal sowie der Transaktions-Hash angezeigt. Außerdem wird die CCIP-Nachrichten-ID der Übertragung angezeigt, mit der Sie den Status der Übertragung im Chainlink CCIP Explorer verfolgen können. Ihr Terminal gibt die Nachrichten-ID wie unten gezeigt aus:
- Terminalausgabe
- CCIP Explorer
- HyperEVM Explorer
- BSC Explorer
Terminalausgabe mit der CCIP-Meldungs-ID
CCIP Explorer mit Anzeige des Status der kettenübergreifenden Übertragung
HyperEVM Explorer mit den Details der Übertragungstransaktion
BSC Explorer mit den Details der empfangenen Überweisung
Prüfen wir, ob die qWHYPE Die Token sind auf dem BSC-Netzwerk eingegangen. Öffnen Sie Ihre MetaMask-Wallet, wechseln Sie zum BSC-Netzwerk und importieren Sie die qWHYPE Token unter Verwendung der Adresse, die Sie in Ihrer deployments.json Datei mit dem Schlüssel qWHYPE_bsc. Wenn Sie Hilfe beim Importieren eines Tokens benötigen, befolgen Sie die Anleitung von MetaMask hier. In Ihrer Wallet sollte nun ein Guthaben von 0,01 qWHYPE-Token angezeigt werden, was bestätigt, dass die kettenübergreifende Übertragung erfolgreich war!
Übertragung in jede Richtung
Die TransferTokens.s.sol Mit diesem Skript lassen sich qWHYPE-Token in beide Richtungen zwischen HyperEVM und BSC übertragen. Sie können die Richtung der Übertragung festlegen, indem Sie entweder to-bsc oder to-hyperevm als Argument beim Ausführen des Skripts. Um beispielsweise qWHYPE-Token von BSC auf HyperEVM zu übertragen, würden Sie den folgenden Befehl ausführen:
forge script script/TransferTokens.s.sol:TransferTokens --broadcast --sig 'run(string)' 'to-hyperevm'
Die Ausgabe wird ähnlich wie bei unserer ersten kettenübergreifenden Übertragung aussehen und den Transaktions-Hash sowie die CCIP-Nachrichten-ID anzeigen. Wenn Sie die Nachrichten-ID in den Chainlink CCIP Explorer einfügen, wird nun die Übertragung in die entgegengesetzte Richtung angezeigt:

Fazit
Herzlichen Glückwunsch! Sie haben erfolgreich gelernt, wie man mit Chainlink CCIP Token auf Hyperliquid überbrückt. Sie haben Ihre eigenen ERC-20-Token bereitgestellt, CCIP-Token-Pools eingerichtet und kettenübergreifende Übertragungen von qWHYPE-Token zwischen HyperEVM und BSC durchgeführt.
Nächste Schritte
Nachdem Sie nun über eine funktionierende kettenübergreifende Brücke verfügen, können Sie Ihre Konfiguration weiter optimieren und anpassen. Hier sind einige Ideen:
- Hyperliquid Bridge UI: Erstellen Sie eine benutzerfreundliche Oberfläche für Ihre Bridge mithilfe von Frameworks wie React oder Vue.js. So können Nutzer problemlos mit Ihrer Bridge interagieren, ohne Befehlszeilentools verwenden zu müssen.
- Ratenbegrenzung: Richten Sie eine Ratenbegrenzung für Ihre Token-Pools ein, um Missbrauch zu verhindern und eine faire Nutzung zu gewährleisten. Sie können die Ratenbegrenzungen in der
ConfigurePools.s.solSkript. - Weitere Blockchains implementieren: Erweitern Sie Ihre Bridge, um weitere von Chainlink CCIP unterstützte Blockchains zu integrieren. Sie können die in dieser Anleitung beschriebenen Schritte befolgen, um Token-Pools auf anderen Blockchains bereitzustellen und zu konfigurieren. Informieren Sie sich im CCIP-Verzeichnis über die Lanes und die unterstützten Blockchains.
- Weitere HIP-1-Assets „verpacken“: Sie können auf Hyperliquid zusätzliche „verpackte“ Token für andere HIP-1-Assets erstellen und bereitstellen, wobei Sie ähnlich vorgehen wie bei HYPE. Der einzige Unterschied besteht darin, dass für jedes Asset ein eigener ERC-20-Wrapper-Vertrag erstellt werden muss. Dadurch können Nutzer eine größere Bandbreite an Assets zwischen HyperEVM und anderen Blockchains übertragen.
Weitere Ressourcen
- Hyperliquid-Dokumentation
- Quicknode-Anleitungen zu Hyperliquid
- Quicknode Hyperliquid-Dokumentation
- Gießereibuch
- Video: Was ist Hyperliquid HyperEVM und wie fängt man damit an?
Wenn du nicht weiterkommst oder Fragen hast, teile sie uns einfach in unserem Discord mit. Bleibe auf dem Laufenden, indem du uns auf X (@Quicknode) oder in unserem Telegram-Ankündigungskanal folgst.
Wir ❤️ Feedback!
Wenn Sie Anregungen oder Fragen zu dieser Dokumentation haben, teilen Sie uns diese bitte mit. Wir freuen uns auf Ihre Rückmeldung!