For the complete documentation index, see llms.txt. This page is also available as Markdown.

Auf Bloom aufbauen

Dieser Leitfaden beantwortet eine Frage: Wie macht ein Builder das selbst? Nimm einen Solidity-Real-World-Asset-Vertrag, setze ihn auf einer Rome-Chain als berechtigtes Token auf, öffne ihn für Solana-Wallets ebenso wie für EVM-Wallets ohne Bridge und ohne zweites Token, und binde deine eigene KYC-/Compliance-Entscheidung ein.

Die Zielgruppe ist ein Entwickler, der den Ansatz evaluiert oder übernimmt. Bloom ist durchgehend das durchgearbeitete Beispiel — sein Live-Asset ARCV ("Mineral Vault I") auf Hadrian (200010) ist eine reale Instanz aller Schritte unten, und sein Deploy-Receipt (deployments/200010.tokens/ARCV.json) dokumentiert die genau drei Verträge und acht Transaktionen, die diese Methode erzeugt.

Nichts hier verändert die Asset-Verträge. Bloom betreibt Plumes Arc-Framework unverändert (der vendorte Baum in contracts/, byte-identisch zu plumenetwork/contracts am Pin in NOTICE); der einzige Vertrag auf Rome-Seite ist ArcTokenFactoryV2, der eine Funktion hinzufügt. Die Arbeit steckt in wie du die Verträge bereitstellst und wie du die Verträge steuerst — nicht darin, sie zu ändern.

Die Methode auf einen Blick. Ein berechtigtes Token ist drei bereitgestellte Verträge. Es wird stückweise — ein Vertrag pro Transaktion — bereitgestellt, weil ein Factory-Aufruf in einer Transaktion das Account-Limit von Rome pro Transaktion überschreitet. Seine Proxys müssen aus herkunftsverriegelten Artefakten stammen, sonst schlägt die On-Chain-Registrierung fehl und scheitert sicher. Compliance ist ein Boolean pro Adresse, geschrieben von demjenigen, den dein KYC-Prozess autorisiert. Und dieselbe Bereitstellung ist von einer Solana-Wallet aus über einen synthetischen Sender erreichbar, der on-chain abgeleitet wird — keine Bridge, kein Wrapped Token, keine zweite Allowlist.

Voraussetzungen

Alle Referenz-Tools liegen in scripts/ (führe npm install dort zuerst aus). Jeder Befehl löst Chain-Fakten aus dem Registry statt sie fest einzubrennen, daher ist das Umstellen auf eine andere Rome-Chain eine Umgebungsänderung, keine Codeänderung:

export PRIVATE_KEY=# finanzierter Schlüssel des Deployers/Emittenten auf der Ziel-Chain
export CHAIN_ID=200010     # wählt die Chain aus
export REGISTRY_ROOT=# ein Checkout der Rome-Chain-Registry
# Solana-Lane-Flows benötigen außerdem:
export SOLANA_KEYPAIR=# Pfad zu einer finanzierten Solana-Keypair-JSON (dem Fee Payer)

Gas auf Rome-Chains ist in USDC denominiert; die komplette Deploy-Sequenz kostet in der Größenordnung von 10–15 nativen Einheiten auf dem Devnet. Schlüssel kommen nur aus der Umgebung — niemals aus dem Repo. Baue die Verträge einmal vor dem Deploy, denn Artefakte müssen aus rome-contracts/out (siehe Schritt 3):

cd contracts       && forge build --via-ir     # die vendorte Arc-Suite
cd rome-contracts  && forge build --via-ir     # ArcTokenFactoryV2 + der kanonische Proxy

Schritt 1 — Verstehe, was ein berechtigtes Token ist hier

Ein berechtigtes Bloom-Token ist nicht ein Vertrag. Es sind drei bereitgestellte Verträge, plus vier gemeinsame Verträge, die Ops einmal pro Chain bereitstellt und die jeder Emittent wiederverwendet.

Die drei pro-Token-Verträge — ein Asset besitzt genau diese:

Vertrag
Quelle
Was es ist

ArcTokenProxy

contracts/src/proxy/ArcTokenProxy.sol

Das Token selbst — ein UUPS-Proxy, der auf das gemeinsame ArcToken Implementation verweist. Salden, Inhaber und Rollen leben hier.

WhitelistRestrictions

contracts/src/restrictions/WhitelistRestrictions.sol

Das Allowlist-Modul. Ein Boolean pro Adresse; wird bei jeder Übertragung durchgesetzt, solange das Asset gegated ist.

YieldBlacklistRestrictions

contracts/src/restrictions/YieldBlacklistRestrictions.sol

Das Yield-Modul. Schließt Adressen von Yield-Ausschüttungen aus, ohne ihren Bestand anzutasten.

Die vier gemeinsamen, einmal-pro-Chain-Verträge (bereitgestellt von deploy-infra.ts):

Vertrag
Rolle

RestrictionsRouter

Registry für Modultypen — Chain-Verdrahtung, einmal von Ops gesetzt.

ArcTokenFactoryV2

Registrierung + der kanonische Proxy-Codehash (Schritte 2–3).

ArcToken (Implementation)

Die gemeinsame, wiederverwendbare Asset-Logik, auf die jedes Token per Proxy zugreift.

ArcTokenPurchase

Ein gemeinsamer Marktplatz für jedes Token und jeden Emittenten (Schritt 4).

wUSDC

Die Cash-Seite — die Yield-Währung und die Kaufwährung beim Verkauf.

Transferbeschränkung und Yield-Beschränkung sind bewusst getrennte Module: ein Inhaber kann vom Einkommen ausgeschlossen werden, während er das Asset behält; genau so funktionieren Sanktionen und Gerichtsentscheidungen in der Praxis.

Diese Tatsache „drei Verträge“ ist für die Verifikation entscheidend. verify-deployments.ts und register-asset.ts erwarten beide, dass sich ein Token auf drei bereitgestellte Verträge auflöst — eine manuelle Verifikation eines Tokens übersah einmal sieben davon über eine Chain hinweg (jedes Yield-Modul und drei Whitelist-Module).

Der Lebenszyklus hat drei Phasen und eine Einbahnstraße:

Das Gating ist für den Vorrat eine Einbahnstraße, weil Mint und Burn address(0) als Gegenpartei verwenden und address(0) niemals auf die Allowlist gesetzt werden können — sobald also gegated ist, kann nie wieder neuer Vorrat gemintet werden. Das ist die Garantie, die ein berechtigtes Asset seinen Inhabern gibt.


Schritt 2 — Bereitstellung stückweise, niemals als eine Transaktion

Arc liefert einen Ein-Klick- createToken aus, der den Proxy und beide Module bereitstellt und in einem einzigen Aufruf verdrahtet. Auf Rome kannst du ihn nicht verwenden. Diese Transaktion braucht 77 Solana-Account-Locks, und Rome hat ein Limit von 62 Locks. Sie passt niemals hinein — weder mit Tuning noch mit einem Optimizer-Pass.

Also ist das Deploy stückweise: jeder Vertrag in seiner eigenen Transaktion, und das Token erhält den Status eines Factory-Gegenstücks über ArcTokenFactoryV2.registerToken statt über das monolithische createToken. Das ist der Create-Wizard, und genau das macht die Issuer-Konsole Schritt für Schritt:

der Create-Wizard

Die Referenzimplementierung ist arc/plan/create.ts (createSequence()), das die App als sechs Karten rendert (bloom/lib/createCards.ts) über acht Transaktionen, genau in der Reihenfolge, die die Verträge erzwingen:

#
Transaktion
Vertragsaufruf

1

Das Asset bereitstellen

new ArcTokenProxy(impl, initData) wobei initData = ArcToken.initialize(...)

2

Das Allowlist-Modul bereitstellen

new WhitelistRestrictions()

3

Dich als seinen Administrator festlegen

whitelist.initialize(issuer)

4

Es bei Übertragungen erzwingen

token.setRestrictionModule(TRANSFER, whitelist)

5

Das Yield-Modul bereitstellen

new YieldBlacklistRestrictions()

6

Dich als seinen Administrator festlegen

yieldBlacklist.initialize(issuer)

7

Es beim Yield erzwingen

token.setRestrictionModule(YIELD, yieldBlacklist)

8

Bei der Factory registrieren

factoryV2.registerToken(token, impl)

Die Skriptform ist ein Befehl:

Der Emittent (PRIVATE_KEY) signiert jede Transaktion und hält am Ende die Rollen des Tokens (ArcToken.initialize gewährt an msg.sender — siehe Schritt 7). Die Registrierung (Tx 8) schaltet den enableToken des Marktplatzes und jedes factoryvermittelte Upgrade frei.

„Optimiere“ das nicht wieder zu einem Monolithen. Das Bündeln dieser Aufrufe in einer Transaktion, um Round-Trips zu sparen, bringt genau den 62-Locks-Überlauf zurück, den der stückweise Pfad vermeiden soll. Dasselbe Limit ist der Grund, warum die Yield-Ausschüttung pro Transaktion nur einen Inhaber durchläuft (Schritt 8). Wenn ein Aufruf fehlschlägt mit Zu viele Konten: N > 62, greift eine Transaktion auf zu viele Konten zu — aufteilen, nicht tunen.


Schritt 3 — Proxys nur aus den herkunftsverriegelten Artefakten bereitstellen

registerToken ist die Sicherheitsgrenze, die stückweise Deploys sicher macht. Sie akzeptiert nur ein Token, dessen Runtime-Codehash mit dem kanonischen übereinstimmt ArcTokenProxy zur Deploy-Zeit in die Factory eingebrannt wurde:

Weil dieser Codehash ein immutableist, schlägt ein Proxy, der aus einem anderen Artefakt gebaut wurde, sicher fehl mit ProxyCodehashUnknown. Daraus folgen zwei Regeln, und beide werden durch CI und die harten Regeln in CLAUDE.md:

  1. Token-Proxys MÜSSEN aus rome-contracts/out bereitgestellt werden — niemals aus contracts/out, niemals aus einem anderen Build. Das ist die Kompilierung, auf die der kanonische Codehash der Factory fest verdrahtet ist.

  2. bytecode_hash = "none" und cbor_metadata = false in rome-contracts/foundry.toml sind entscheidend. Mit aktivierten Metadaten trägt der ArcTokenProxy Runtime-Code eingebettet in der Factory (type().runtimeCode) einen anderen CBOR/IPFS-String als das eigenständige out/ Artefakt, aus dem der Wizard bereitstellt — also schlagen On-Chain registerToken Reverts zu, während jeder Test aus Foundry mit Source-Code besteht (Foundry bettet beide Kopien ein, daher kann es die Abweichung nicht sehen). rome-contracts/test/ArtifactProvenance.t.sol verankert diese Eigenschaft; der gefundene Lauf war es, der sie ursprünglich aufdeckte.

Eine grüne in-Source-Test-Suite beweist keine Herkunft. Bevor du ein Image auslieferst und nach JEGLICHER Änderung der Compiler-Einstellungen, beweise die Eigenschaft gegen die bereitgestellte Factory (nur lesend, keine Schlüssel):

Es hasht dein lokales ArcTokenProxy Artefakt und prüft, dass dieser Hash wörtlich im Bytecode der bereitgestellten Factory erscheint.

Wenn sich Compiler-Einstellungen ändern müssen, rotiere die Factory — deploye eine frische Factory, deren Immutable den neuen Codehash fest verdrahtet, und verdrahte neu — statt den Check von Hand zu patchen:

Die Rotation behält die alte Adresse im Receipt; Tokens, die gegen die alte Factory registriert wurden, müssen sich gegen die neue neu registrieren.


Schritt 4 — Einen Verkauf über den gemeinsamen Marktplatz öffnen

Verkaufen ist ein eigener Akt, getrennt vom Erstellen, und läuft über den einen gemeinsamen ArcTokenPurchase Marktplatz. Bevor ein Verkauf geöffnet wird, müssen drei Dinge wahr sein, und ArcTokenPurchase.enableToken prüft jedes davon on-chain:

Es gibt eine vierte, implizite Anforderung, die ein gegated Asset erzwingt: weil jede Übertragung das Allowlist-Gate durchläuft, kann das Verschieben von Bestand zum Marktplatz nur funktionieren, wenn die Marktplatz-Adresse selbst auf deinem Token whitelisted ist. Der vollständige Ablauf zum Öffnen eines Verkaufs ist also:

  1. Den Marktplatz whitelisten auf dem Whitelist-Modul deines Tokens (batchAddToWhitelist([storefront]) — siehe Schritt 5). Ohne dies schlägt der Inventartransfer in (2) fehl mit TransferRestricted() sobald gegated.

  2. Inventar übertragen an die Marktplatzadresse (aus dem arcTokenPurchase).

  3. enableToken(token, amount, price) — Käufer zahlen nun in wUSDC und erhalten das RWA.

Die Aufteilung der Auszahlungen ist auf einem gemeinsamen Marktplatz wissenswert, und sie ist nicht symmetrisch (arc/roles.ts ist die Autorität):

Aktion
Berechtigung
Gehalten von

enableToken / disableToken / withdrawUnsoldArcTokens

die ADMIN_ROLE (onlyTokenAdmin)

dir, dem Emittenten

withdrawPurchaseTokens (die wUSDC-Erlöse)

des Marktplatzes DEFAULT_ADMIN_ROLE

wer auch immer den Marktplatz bereitgestellt hat

Auf einer selbst gehosteten Chain bist du beides. Auf einem gemeinsamen Marktplatz ist der Erlöspool die Gesamteinnahme aller Emittenten, daher ist seine Auszahlung eine Plattform-Entscheidung — entwerfe deine Abwicklung darum herum, statt von alleiniger Kontrolle auszugehen.


Schritt 5 — Binde dein eigenes KYC / deine eigene Compliance ein

Das ist der Abschnitt, den ein Kunde vor seiner Zustimmung liest, also ist er Code, nicht Prosa. Compliance wird vom Token-Vertrag selbst durchgesetzt — nicht durch einen Off-Chain-Check, einen Sequencer-Filter oder eine Venue-Policy. Die Regeln reisen mit dem Token auf jedem Ausführungsweg, auf beiden Wallet-Lanes. Was die Chain aufzeichnet, ist das Ergebnis deiner KYC-Entscheidung, als ein einzelner Boolean:

Die Schnittstelle, in die dein Prozess schreibt

Die Approve/Deny-Entscheidung deines KYC-Anbieters wird exakt zu einem dieser Aufrufe:

Wer schreiben darf

Die Berechtigung, die ein Approval braucht, ist MANAGER_ROLE auf dem Modul — nicht ADMIN_ROLE auf dem Token. addToWhitelist / batchAddToWhitelist / removeFromWhitelist sind alle nurRole(MANAGER_ROLE), und diese Rolle lebt auf der WhitelistRestrictions Instanz. Die Authentifizierung ADMIN_ROLE am Token und dann in das Modul zu schreiben, ist ein echter Fehler, den diese Codebasis bereits teuer bezahlt hat. Biete nicht WHITELIST_ADMIN_ROLE als Lösung für eine Verweigerung an — es wird bei initialize gewährt und nirgendwo in der Suite geprüft (arc/roles.ts behauptet, dass es die einzige Rolle ist, die nichts absichert).

WhitelistRestrictions.initialize(issuer) (Transaktion 3 des Wizards) gewährt dem Issuer DEFAULT_ADMIN_ROLE, ADMIN_ROLE, MANAGER_ROLE, WHITELIST_ADMIN_ROLE, und UPGRADER_ROLE auf diesem Modul. Also hält der Issuer MANAGER_ROLE von Haus aus und kann sie auch delegieren: weil der Issuer DEFAULT_ADMIN_ROLE, eine grantRole(MANAGER_ROLE, serviceAccount) übergibt den Schreibvorgang an einen Backend-Signer.

Eine Entscheidung wird zu einem On-Chain-Schreibvorgang

Richte den Webhook deines Anbieters auf einen Signer aus, der MANAGER_ROLE, und fasse bei einer Genehmigung die Adressen in einem Batch zusammen:

Auflösen whitelistModule aus dem Token selbst (ArcToken.getRestrictionModule(TRANSFER_RESTRICTION_TYPE)), niemals aus einer gecachten Projektion — ein Schreibvorgang auf das falsche Modul zu richten ist genau so, wie „approve on any asset“ einst in die Allowlist eines einzelnen Tokens schrieb.

Die wallet-signierte Variante (Self-Service-Demo)

Für ein erlaubnisloses Test-Deployment, bei dem Besucher sich selbst zulassen, gewähre MANAGER_ROLE an einen TestApprover (rome-contracts/src/TestApprover.sol) dessen Modul ist immutable. Dann approve(address) von jedem aus der eigenen Wallet aufrufbar ist, wobei er sein eigenes Gas zahlt — er ruft addToWhitelist nur dann auf, wenn die Adresse noch nicht gelistet ist:

Das ist das „Sign-in-Gate“ — es zeigt einem Besucher den eigentlichen Mechanismus (eine Genehmigung wird zu einem On-Chain-Allowlist-Eintrag, den der Token dann durchsetzt), ohne irgendetwas zu verwahren. Gewähre niemals MANAGER_ROLE an einen TestApprover auf einem Produktions-Token — dadurch wird die Allowlist dieses Tokens erlaubnislos.

Wenn das Gate greift, und Anbieter wechseln

Das Gate beschränkt erst, wenn das Asset gegatet (setTransfersAllowed(false), ADMIN_ROLE auf dem Modul). Solange nicht gegatet, sind Transfers offen — baue zuerst deine Allowlist auf, dann aktiviere das Gate. Sobald gegatet, wird ein Transfer, bei dem eine der beiden Seiten nicht auf der Liste steht, mit dem typisierten Fehler revertiert TransferRestricted() (0xe827105e).

Ein späterer Wechsel des KYC-Anbieters erfordert keine On-Chain-Änderung. Das Allowlist-Modul, seine Schnittstelle und das von ihm gespeicherte Boolean sind anbieteragnostisch. Um Anbieter zu wechseln, richte eine andere Entscheidungsquelle auf denselben MANAGER_ROLE Signer — kein Redeploy, keine Migration, keine Zustandsänderung. Die Chain weiß nie, welcher Anbieter den Aufruf gemacht hat, nur das Ergebnis.


Schritt 6 — Dieselben Assets für Solana-Wallets öffnen

Dieselben drei Verträge sind von einer Solana-Wallet aus erreichbar ohne Bridge und ohne zweiten Token. Ein Solana-nativer Nutzer hat nirgendwo einen EVM-Schlüssel; stattdessen ist seine EVM-Identität synthetisch, on-chain aus dem tatsächlichen Solana-Signer der Transaktion abgeleitet:

Das Rome-EVM-Programm leitet dies direkt aus dem Signer selbst ab (do_tx_unsigned::derive_sender), daher kann es nicht gefälscht werden und es existiert kein secp256k1-Privatschlüssel dafür — die Solana-Signatur ist das Einzige, das diese Adresse jemals steuern kann. Die Referenzableitung ist arc/materialise/solana/identity.ts (syntheticAddress), byte-kompatibel mit der On-Chain-Regel:

Was ein Builder tut, um diese Lane zu unterstützen — beachte, dass nichts davon eine Vertragsänderung ist:

  1. Den Solana-Nutzer über seine synthetische Adresse auf die Allowlist setzen. Für die Compliance-Ebene ist eine synthetische Adresse eine gewöhnliche Adresse: füge den Solana-Pubkey des Nutzers ein, leite die synthetische Adresse ab, und batchAddToWhitelist([synthetic]). Eine Allowlist umfasst beide Wallet-Welten.

  2. Richte das Signing-PDA einmal ein, vor ihrer ersten Transaktion. Das External-Authority-PDA, das die Signatur einer synthetischen Adresse autorisiert, muss zuerst existieren, und es anzulegen ist ein EVM-Lane-Aufruf (create_pda) — ein rein Solana-Nutzer kann das nicht selbst tun, daher richtet der Issuer es ein. Das Provisioning ist external_auth, nicht lazy.

  3. Über die Lane-Bibliothek einreichen, nicht von Hand. submitDoTxUnsigned (arc/materialise/solana/submit.ts) baut ein DoTxUnsigned Instruction — ein unsigniertes EIP-1559-Payload, autorisiert durch die Solana-Signatur — und behandelt die vier Dinge, die eine von Hand gebaute Transaktion falsch macht:

    • Account-Ermittlung über rome_emulateCallAccounts, die die Schreibbarkeit jedes Accounts bestimmt. Der Wert müssen muss an die Ermittlung weitergeleitet werden, sonst markiert ein Value-Transfer das Balance-PDA des Empfängers als nur lesbar und scheitert on-chain.

    • Compute-Budget — eine DoTxUnsigned benötigt ein 250-KB-Heap-Frame und ein 1,35 Mio. CU Limit (Romes EVM sprengt die 32-KB-/200K-Standardwerte); dadurch bleiben etwa 50K Puffer unter Solanas 1,4-Mio.-Obergrenze.

    • Das Treasure-(Gebühren-)Wallet-PDA, als schreibbar angehängt — die Ermittlung lässt es weg.

    • Der v0- + Lookup-Table-Fallback. Wenn die Accounts eines Aufrufs den 1232-Byte-Rahmen einer Legacy-Transaktion sprengen, reicht der Client den Aufruf erneut als v0-Transaktion über eine frische Address-Lookup-Table ein. (Gemessen passt ein heutiger Storefront-Kauf mit etwa 1.061 von 1232 Bytes in den Legacy-Rahmen; ein Erstbesitzer, dessen Associated Token Account noch angelegt werden muss, kann ihn überschreiten.)

Der Nutzer ist der Gebührenzahler und zahlt Lamports (SOL) aus seiner Solana-Wallet; die synthetische Adresse, die er kontrolliert, hält die Assets und niemals SOL. Nach jedem Lane-Send den EVM-Nonce vor dem nächsten abfragen — der Indexer hinkt der Solana-Bestätigung leicht hinterher.

Die Lane ist NUR-ATOMAR. Ein DoTxUnsigned ist eine EVM-Transaktion, die von Romes atomarer VM innerhalb einer Solana-Transaktion ausgeführt wird. Die iterative VM (eine EVM-Ausführung, die über mehrere Solana-Transaktionen gestaffelt ist) ist über diese Lane noch nicht erreichbar. Ein Aufruf, der atomar nicht hineinpasst, kann diese Lane überhaupt nicht nutzen — die Lösung ist ein kleinerer Aufruf, kein Fallback. Beachte: Der v0+ALT-Fallback ist ein größeres Umschlag, keine andere Ausführung; es ist immer noch eine einzige atomare Transaktion.

Warum das RWA nicht aus dem Perimeter entweichen kann. Das Asset ist im EVM-Zustand gespeichert — seine Salden sind Storage innerhalb der Accounts des Rome-EVM-Programms. Es gibt kein SPL-Mint davon und nichts Solana-Natives, das bewegt werden könnte; die Asset-Bewegungs-Primitiven der Lane arbeiten auf SPL-Token-Accounts, die ein EVM-Storage-Saldo nicht hat. Jede Bewegung, die die Solana-Signatur ausdrücken kann, ist ein Aufruf in den Token-Vertrag, der das Allowlist-Gate durchläuft — die finanzierte Suite stellt fest, dass ein Transfer an eine nicht auf der Allowlist stehende Adresse identisch revertiert, egal ob er von einem EVM-Schlüssel oder einem Solana-Schlüssel signiert ist. Das Cash-Bein (wUSDC) ist die bewusste Ausnahme: Es ist SPL-gestützt und tut wird auf das eigene Token-Konto des Nutzers ausgeschüttet.


Schritt 7 — Nach dem Deploy wissen, wer die Autorität hält

ArcToken.initialize läuft aus dem Proxy-Konstruktor (Tx 1) und gewährt Rollen an msg.sender — den Wizard-Treiber, also den Issuer. Er gewährt fünf Rollen explizit:

Zwei Folgen, die ein Builder nicht übersehen darf:

  • MINTER_ROLE, BURNER_ROLE, und UPGRADER_ROLE werden bei initialize NICHT gewährt. Der anfängliche Supply wird innerhalb von initialize (ein internes _mint, keine Rolle nötig), aber ein späteres mint oder burn erfordert, dass der Issuer sich die Rolle zuerst selbst gewährt. Das können sie, weil sie DEFAULT_ADMIN_ROLE (der Admin jeder Rolle — nichts ruft _setRoleAdmin, also DEFAULT_ADMIN_ROLE verwaltet alle davon). Aber es ist ein bewusster zusätzlicher Schritt, keine allgegenwärtige Befugnis.

  • UPGRADER_ROLE wird dem Factory nie gewährt. Factory-vermittelte Upgrades (ArcTokenFactoryV2.upgradeToken) erfordern, dass die Factory selbst folgendes hält UPGRADER_ROLE auf dem Token — sie sich selbst zu gewähren bewirkt nichts. Diese Gewährung ist eine Einbahnstraße, die die Factory nicht rückgängig machen kann, also ist sie opt-in: Wenn du factory-vermittelte Upgrades willst, grantRole(UPGRADER_ROLE, factory) explizit gewähren; andernfalls upgraded der Issuer den Token direkt.

Das vollständige 21-Autoritäten-Modell (11 Rollennamen über sechs Verträge hinweg — derselbe Name ist auf jedem Vertrag eine andere Autorität) ist kodifiziert in arc/roles.ts. Frage rolesRequiredFor(contract, functionName) statt den eigenen Vertrag einer Rolle zu lesen, denn vier Storefront-Funktionen und beide Factory-Funktionen werden durch eine Autorität abgesichert, die auf einem anderen Vertrag.


Schritt 8 — Yield verteilen

Der Token zahlt Yield in wUSDC (festgelegt auf initialize, änderbar über setYieldToken unter YIELD_MANAGER_ROLE). Die Verteilung geht die Holder-Menge durch:

Die Mechanik, die für die korrekte Nutzung wichtig ist:

  • Der gesamte totalAmount wird vom Aufrufer nur im startIndex == 0 Fenster (safeTransferFrom(msg.sender, this, totalAmount)). Genehmige diesen Gesamtbetrag dem Token vor dem ersten Fenster; spätere Fenster zahlen aus dem bereits gehaltenen Guthaben aus.

  • nextIndex springt zu 0 wenn der Durchlauf abgeschlossen ist. Schleife distributeYieldWithLimit(total, nextIndex, …) bis nextIndex zurückkommt 0.

  • Die Anteile yield-beschränkter Holder bleiben im Token-Vertrag — sie werden übersprungen, nicht umverteilt.

Auf Rome ist die praktische Obergrenze maxHolders = 1 pro Transaktion — derselbe 62-Account-Cap aus Schritt 2 — daher wird Yield mit einem Holder pro Transaktion durchlaufen (gemessen etwa 318K Gas pro Holder). Jeder Whitelisted-Holder, ob EVM- oder Solana-nativ, erhält anteilig; das Referenzskript ist measure-yield-batch.ts und der Yield-Schritt des finanzierten Smoke-Tests prüft es end-to-end.


Schritt 9 — Überprüfen, was du deployt hast

Nichts reicht in Rome Quellcode automatisch irgendwo ein, daher ist die Verifikation ein Schritt, den du selbst ausführst. Nach jedem Deploy — Infrastruktur oder neuer Token — führe den schreibgeschützten, schlüssellosen, idempotenten Verifizierer aus (bereits verifizierte Verträge werden übersprungen, also verifiziert ein erneuter Lauf nach dem Ausgeben eines Tokens nur die neuen):

Er erwartet die drei Verträge pro Token (Proxy + beide Module) plus die Infrastruktur und meldet, was er nicht verifizieren konnte, statt ein Deploy fehlschlagen zu lassen. Das einmal von Hand zu machen, hat sieben Verträge übersehen.

Die Registrierung des Assets im Rome-Registry behandelt Verifikation als ein Gate, nicht als Dekoration (register-asset.ts): Ein Token erhält seinen apps/arc/<chain>.json Eintrag — mit standard: arc-permissioned-erc20 und ein transferRestriction und benennt sein Allowlist-Gate — nur wenn alle drei seiner Verträge auf Sourcify verifiziert sind. Dieser Eintrag liest seine Fakten aus der Chain (ein per Wizard deployter Token hat keinen festgeschriebenen Beleg) und schreibt nur einen lokalen Registry-Checkout; das Einreichen des PR ist die Aufgabe eines Menschen.

Für einen End-to-End-Beweis des gesamten Zyklus — erstellen, auf die Allowlist setzen, gaten, auf beiden Lanes verkaufen, Yield verteilen — führe den finanzierten Smoke-Test gegen eine beliebige Chain aus:


Schritt 10 — Wissen, was off-chain bleibt

Das Trust-Modell ist absichtlich offen, und ein Builder sollte es seinen eigenen Nutzern genauso darstellen:

  • Das Allowlist-Flag ist deine Off-Chain-Entscheidung. KYC/AML findet in deinem Prozess statt — deine Anbieter, deine Regeln. Die Chain protokolliert und erzwingt nur das Ergebnis, isWhitelisted(addr).

  • Der einzige On-Chain-Zustand ist ein Boolean pro Adresse. Keine personenbezogenen Daten, keine Dokumente, keine Identitätsbehauptungen, keine On-Chain-Bescheinigungen, kein kryptografischer Beweis, wem eine Adresse gehört. Das ist Arc's Modell, wie es auf Plume verwendet wird; es tauscht die schwereren Abläufe eines On-Chain-Identity-Standards (z. B. ERC-3643) gegen leichtere Mechanik und vom Issuer gehaltenes Vertrauen ein.

  • Wiederherstellung ist eine Befugnis des Issuers, kein Notausgang. Eine verlorene Wallet — EVM oder Solana — wird wiederhergestellt, indem eine Ersatzadresse auf die Allowlist gesetzt wird und, falls nötig, mint/burn/upgrade im Rahmen deines eigenen rechtlichen Prozesses verwendet werden (Arc hat keine eingebaute Forced-Transfer-Primitivfunktion). Die Schlüsselverwahrung des Issuers ist daher Teil der Compliance-Positionierung.

  • Kein Relayer, keine Verwahrungsfläche. Nutzer halten ihr eigenes Gas auf beiden Lanes. Ein Fee-Payer-Service würde bedeuten, Schlüssel zu halten — eine Fläche, die ein RWA-Produkt nicht hinzufügen sollte.


Referenz: die Tools

Jedes Skript läuft von scripts/ nach npm install, mit PRIVATE_KEY, CHAIN_ID, und REGISTRY_ROOT exportiert.

Skript
Was es tut

deploy-infra.ts

Einmal pro Chain: die vier gemeinsam genutzten Verträge, für wUSDC verdrahtet.

create-token.ts

Der schrittweise Wizard — acht Transaktionen, ein Token.

rotate-factory.ts

Nach einer Compiler-/Artefaktänderung eine frische Factory deployen; neu verdrahten.

verify-artifact-provenance.ts

Nachweisen, dass dein Proxy-Artefakt von der deployten Factory akzeptiert wird (nur lesen).

verify-deployments.ts

Alle drei Verträge pro Token + Infrastruktur auf Sourcify verifizieren (nur lesen).

register-asset.ts

Verifikations-Gate, dann den Compliance-Eintrag im Registry vorbereiten.

measure-yield-batch.ts

Die Yield-Obergrenze pro Tx auf einer Chain neu messen.

smoke.ts

Die gefundete End-to-End-Suite über beide Lanes hinweg.

sweep-synthetic-native.ts

Native Gas von einem synthetischen Konto zurückholen (Test-Hygiene).

Vertiefender Hintergrund findet sich neben diesem Leitfaden: docs/ARCHITECTURE.md (das geschichtete App-Modell), docs/LANES.md (die zwei Lanes und Verwahrung), docs/COMPLIANCE.md (das Trust-Modell), und docs/USAGE.md (das Operator-Runbook).

Zuletzt aktualisiert

War das hilfreich?