Robinhood 레일

볼트가 보유하는 토큰화 주식은 Arbitrum Orbit L2인 Robinhood Chain에 존재합니다. 프로토콜은 Paxos의 USDG OFT를 현금 레그로 삼아 LayerZero를 통해 이 체인에 도달합니다.

왜 이 레일인가

이 선택은 이전 레일을 배제한 뒤 2026-09-11에 확정되었습니다.

프라이머리 민트 레일에서는 볼트 컨트랙트가 발행사로부터 해당 자산을 보유할 자격을 인정받아야 합니다: KYB, 컨트랙트 주소 등록, 그리고 발행사가 한 번도 공개적으로 문서화한 적 없는 서면 확인이 필요합니다. 이것이 프로젝트에서 유일하게 정말로 피할 수 없는 걸림돌이었습니다.

Robinhood Chain의 세컨더리 풀에는 그런 것이 전혀 필요 없습니다: 누구에게나 열려 있습니다. StockFun은 발행사와 아무런 관계가 없으며, 필요하지도 않습니다.

그 자유의 대가는 크로스체인 의존성입니다: 브리지 하나, 허브 둘, 그리고 동결할 수 있는 제3자가 발행한 스테이블코인. 이는 회피한 위험이 아니라, 감수하고 문서화한 위험입니다.

흐름

flowchart LR V[TreasuryVault

Ethereum] -->|ETH → USDC

Uniswap v4| U[USDC] U -->|USDC → USDG

Curve| G[USDG] G --> BH[BridgeHub] BH -->|Paxos OFT

LayerZero| RH[RemoteHub

Robinhood Chain] RH --> MV[미러 볼트

CREATE2, 마켓당 하나] MV -->|v3 / v4 풀| S[Stock Tokens] S -->|주식 어댑터, 래핑| AD[AirdropDistributor

Ethereum] AD -->|청구| HO[Ethereum의

토큰 홀더]

Robinhood Chain에서 Ethereum으로 가는 USDG 역방향 경로는 크리에이터 바이백에만 쓰였으며, 둘 다 2026-09-28에 코드에서 제거되었습니다.

2026-10-04부터 미러 볼트는 자신의 주식을 Ethereum의 에어드랍 컨트랙트로 보냅니다: 각 주식은 Robinhood Chain에서 자신의 LayerZero 어댑터에 잠기고, Ethereum에서 래핑된 형태로 민트되며, 홀더는 그곳에서 이를 청구합니다. 이 경로는 주식만 운반합니다. 주식마다 하나인 어댑터는 메인넷용으로는 아직 저장소에 없으며, 테스트는 목을 사용하고, 2026-10-06의 LayerZero 테스트넷 실행은 테스트용 어댑터를 사용했습니다(아래 참고).

퍼미션리스인 것과 아닌 것

구성 요소 상태
LayerZero 엔드포인트 퍼미션리스
Stock Token 세컨더리 풀 퍼미션리스 — 프로토콜이 사용하는 것
Robinhood 프라이머리 민트 / 소각 KYB — 사용하지 않음
USDG Paxos가 민트와 소각을 통제하며, 일시 중지하거나 동결할 수 있음

마지막 행이 레일에서 가장 강한 의존성이며, 이는 현실입니다.

미러 볼트

모든 마켓은 Robinhood Chain에 미러 볼트를 하나씩 가지며, 이는 Ethereum에서 예측 가능한 주소에 CREATE2로 배포됩니다. 따라서 키퍼는 USDC가 도착하기 전에 리모트 허브가 미러 볼트를 미리 배포하게 할 수 있고, 전송이 코드 없는 주소에 도달하는 일은 없습니다. 2026-10-05부터 이는 키퍼와 StockFun의 오너만 할 수 있습니다(predeploy): 그 전까지는 아직 존재하지 않는 마켓에 대해서도 누구나 그렇게 할 수 있었고, 그 마켓의 미러 볼트는 그날의 연결 구성에 묶였습니다. 리모트 허브는 키퍼를 담고 있는 브리지 배치를 통해 키퍼를 알게 됩니다: 첫 배치 전에는 아는 키퍼가 없으므로, StockFun의 오너가 첫 마켓의 미러 볼트를 미리 배포합니다. 2026-10-05의 두 번째 감사 루프 이후로, 키퍼가 미러 볼트를 미리 배포할 수 없는 마켓(첫 배치 전, 또는 리모트 허브가 아직 알지 못하는 키퍼 변경 이후)은 볼트를 배포하기에 너무 적은 가스로 보내지는 대신 알림과 함께 배치에서 제외됩니다; 다른 마켓들은 건너가며, 그 배치에는 새 키퍼가 담겨 있습니다.

2026-10-02부터 각 미러 볼트는 프록시, 즉 MirrorVaultProxy이며, 볼트가 배포될 때 리모트 허브가 지정하는 볼트 구현 컨트랙트 앞에 놓입니다. 프록시의 생성자는 인자를 받지 않으므로, 그 생성 코드, 그리고 그와 함께 모든 미러 볼트의 주소는 구현 컨트랙트가 무엇이든 Ethereum에서 예측 가능한 상태로 유지됩니다. 볼트의 바스켓은 첫 배치와 함께 도착하며, 2026-10-05부터 이 첫 배치는 볼트의 주식 라우터와 오라클도 그 시점에 리모트 허브가 지정하는 것으로 갱신합니다: 어떤 주식이 등록되기 전에 배포된 볼트는 그 주식이 담긴 바스켓을 받아들입니다. 리모트 허브가 반영하는 StockFun의 오너는 미러 볼트를 하나씩, 마켓별로 업그레이드하며, 업그레이드는 즉시 효력을 가집니다.

스왑 경로는 하드코딩되어 있지 않습니다: calldata로 전달되며, abi.encode(uint8 version, bytes payload) 형식으로 인코딩됩니다 — 버전 3은 패킹된 Uniswap v3 경로, 버전 4는 v4 PathKey의 배열입니다. 볼트는 레그마다 여러 후보를 받아, 한도를 통과하는 첫 번째 후보로 체결합니다. 2026-10-01부터 금액의 일부만 체결하는 경로는 실패하고, 다음 후보를 시도합니다. 이전에는 v3 경로에서 부분 체결이 일어나면 지출되지 않은 USDG가 라우터에 묶였습니다.

2026-10-01 보안 파이프라인 이후로, v3 경로는 한 번에 풀 하나씩 실행됩니다. 각 풀은 입력 전체를 받아야 하며, 그렇지 않으면 경로가 실패합니다. 풀의 출력은 주식 라우터로 돌아와 다음 풀의 입력이 되고, 마지막 풀은 레그의 최소 수량 조건에 따라 볼트에 지급합니다. 풀 하나가 실패하면 같은 시도에서 앞서 실행된 풀들이 되돌려지고, 다음 후보를 시도합니다. 그 전까지 검사는 경로의 첫 번째 풀만 보았습니다: 그 뒤 풀에서의 부분 체결은 중간 토큰을 Uniswap의 v3 라우터인 SwapRouter02에 남겨 누구나 가져갈 수 있게 했고, 그런데도 레그는 성공했습니다. 이제 멀티홉 v3 레그에는 풀마다 스왑 한 번과 승인 한 번이 듭니다.

각 레그는 바스켓 비중에 따라 자신의 주식에 배정된 USDG만 지출합니다: TreasuryVault를 참고하십시오. 주식 피드 대비 그 가격 한도, 기본값 200 베이시스 포인트는 리모트 허브가 보유하고 모든 미러 볼트가 실시간으로 읽는 설정입니다(setStockMaxSlippageBps). 2026-10-05부터 볼트는 실제로 도착한 양에 키퍼 자신의 최소 수량을 적용하며, 이 최소 수량은 결코 그 한도보다 느슨하지 않습니다.

오라클이 가격을 보류할 때

2026-10-06부터 미러 볼트의 오라클에는 Robinhood 자체의 문서가 권장하는 두 가드가 있습니다; 둘 다 가격을 보류할 수만 있을 뿐, 결코 바꾸지 못합니다.

  • 기업 행위. 주식이 기업 행위(예를 들어 주식 분할)를 거치는 동안, 그 토큰은 자신의 오라클이 일시 중지되었다고 알리며(oraclePaused()), 그 Chainlink 피드는 마지막 값을 유지합니다. 그 값은 토큰의 승수가 바뀌는 동안에도 여전히 새것처럼 보일 수 있습니다. 그러면 오라클은 그 주식의 가격을 보류합니다: 그 매수 레그는 단독으로 실패하고(StockOraclePaused), 그 USDG는 그 주식에 배정된 채로 남으며, 바스켓의 다른 주식들은 매수됩니다. 이 검사는 모든 주식에서 켜져 있습니다; StockFun의 오너는 주식 하나에 대해 이를 끌 수 있으며(setOraclePauseCheck), 그러면 그 주식의 가격은 피드 자체의 검사에만 기댑니다. 응답하지 않는 토큰은 일시 중지되지 않은 것으로 칩니다.
  • 시퀀서. Robinhood Chain은 시퀀서가 하나뿐인 Arbitrum 체인입니다. Chainlink의 L2 시퀀서 업타임 피드가 설정되어 있으면(setSequencerUptimeFeed), 오라클은 피드가 시퀀서가 멈춰 있다고, 복구된 지 유예 기간(기본값 1시간)이 지나지 않았다고 알리는 동안, 또는 피드를 읽을 수 없는 동안 모든 가격을 보류합니다: 그때까지 어떤 레그도 매수하지 않습니다. 현재 Robinhood Chain에는 그런 피드가 없으므로, 레일은 이 검사를 끈 채로 배포됩니다; Chainlink가 그런 피드를 공개하면 StockFun의 오너가 이를 설정합니다.

키퍼는 무엇이든 견적하기 전에 두 가드를 모두 보며(키퍼 참고), Worker는 주식의 가격이 빠진 이유를 알려 주고, 디앱은 이를 표시합니다(디앱 참고).

주식을 에어드랍으로 보내기

2026-10-04부터 매수된 주식이 미러 볼트를 떠나는 길은 하나입니다: sendToAirdrop. 키퍼는 보낼 주식 목록을 담아 이를 호출하고 LayerZero 수수료를 지불하며, 초과 지불한 금액은 키퍼에게 환불됩니다. 각 주식에 대해 볼트는 그 주식의 어댑터를 통해 자신의 잔액 전체를 Ethereum의 에어드랍 컨트랙트로, 마켓 ID를 페이로드로 담아 보냅니다. 키퍼는 수량도 목적지도 지정하지 않습니다: 각 주식의 어댑터(setStockAdapter, 어댑터가 바로 그 토큰을 운반하는지 확인함)와, 에어드랍 컨트랙트(setAirdrop)는 리모트 허브에서 그 관리자인 StockFun의 오너가 지정합니다. 두 번 나열되거나 바스켓 밖에 있는 주식이 있으면 호출이 실패합니다.

2026-10-06부터 키퍼는 각 전달이 Ethereum에서 받는 가스를 지정합니다: sendToAirdrop(stocks, receiveGas, composeGas)이며, 주식 OFT의 lzReceive에 대해서는 그 OFT가 강제하는 가스에 더해지는 몫을, 에어드랍 컨트랙트에 대해서는 그 compose의 가스를 지정합니다. 리모트 허브는 각 값을 그 관리자가 정하는 하한과 상한 사이로 맞추며, 0은 기본값을 뜻합니다(airdropGas); 볼트는 허브가 허용하는 값으로 전송과 그 견적을 만듭니다; 주식만 지정하는 호출은 두 기본값을 씁니다. 키퍼는 Ethereum에서의 전달 시뮬레이션으로 그 값을 고릅니다(키퍼 참고): Sepolia에서 2026-10-06부터 활성화된 Ethereum의 Glamsterdam 업그레이드가 새 스토리지 슬롯의 비용을 약 다섯 배로 만들었으며, 예전의 단일 compose 수치인 600,000 가스로는 LayerZero 테스트넷 실행의 첫 주기에 있었던 전달이 모두 가스가 모자랐습니다. 정책이 없는 버전에서 업그레이드된 리모트 허브는 둘 다 설정될 때까지 모든 전송과 견적을 거부합니다(AirdropGasNotSet).

2026-10-05부터 각 주식은 따로 진행됩니다. 어댑터가 없는 주식, 잔액을 읽을 수 없는 주식, 그리고 전송이 실패한 주식 — 발행사의 동결, 설정되지 않은 피어, 키퍼의 지불액이 충당하지 못하는 수수료 — 은 이벤트(AirdropSendFailed)와 함께 볼트에 남고, 나머지는 진행됩니다; 아무것도 진행되지 않으면 호출은 실패하며 그 이유를 밝힙니다. 견적 함수 quoteSendToAirdrop은 가격을 매길 수 없는 것을 실패하는 대신 제외합니다.

LayerZero는 소수점 여섯 자리까지 운반합니다: 소수점 18자리 주식의 10^12 단위 미만, 즉 토큰 하나의 100만분의 1 미만은 건너갈 수 없어, 다음 전송을 위해 볼트에 남습니다.

Ethereum에서는 주식의 OFT가 래핑된 주식을 에어드랍 컨트랙트에 민트하고, 이어서 LayerZero의 엔드포인트가 페이로드와 함께 컨트랙트를 호출합니다. 컨트랙트는 전달이 자신의 엔드포인트에서, 오너가 등록한 주식 OFT로부터, Robinhood Chain에서 온 것이고, 페이로드가 지정하는 마켓에 대해 브리지 허브가 도출한 미러 볼트가 보낸 것일 때에만 그 전달을 적립합니다. 그 전달은 전송이 담아 온 가스로 실행됩니다(위 참고); 가스가 부족한 전달은 아무것도 잃지 않고 실패하며, LayerZero의 엔드포인트에 저장되고, compose만 실패한 경우 래핑된 주식은 이미 에어드랍 컨트랙트에 있으며, 누구나 더 많은 가스로 이를 다시 실행할 수 있습니다. 2026-10-06부터는 키퍼가 자신의 키에서, 한도 안에서 이를 하며, 두 번째 실패에는 알림을 보냅니다. 자세한 내용과 측정값은 배포와 에어드랍에 있습니다.

업그레이드와 연결

2026-10-02부터 레일의 모든 StockFun 컨트랙트는 업그레이드할 수 있으며, 예외는 모든 미러 볼트의 주소가 그 주소에서 도출되는 미러 볼트 배포자뿐입니다. Ethereum에서는 브리지 허브와 그 어댑터들이 팩토리의 오너를 따릅니다. Robinhood Chain에서는 리모트 허브가 업그레이드 권한자입니다: 리모트 허브는 자신의 긴급 관리자, 즉 마지막 배치가 전달한 Ethereum 오너로 답하므로, 리모트 허브, 미러 볼트, 주식 라우터, 오라클은 StockFun의 오너가 업그레이드하며, 업그레이드는 즉시 효력을 가집니다.

리모트 허브는 자신의 체인에서 초기 관리자와 함께 가장 먼저 배포되며, 이 관리자가 이후 주식 라우터, 오라클, 앞으로 생길 미러 볼트의 구현 컨트랙트, 그리고 주어진 경우 에어드랍 경로와 주식 어댑터를 지정합니다. 첫 배치가 이 관리자를 StockFun의 오너로 교체합니다.

2026-10-05부터 같은 관리자가 리모트 허브의 설정을 보유합니다: 스윕 한 번이 지급하는 기록 수, 기본값 64(setMaxRecordsPerSweep, 결코 0이 아님), 미러 볼트의 매수 가격 한도, 그리고 각 에어드랍 전달의 가스(setAirdrop); 그리고 2026-10-06부터는 오라클의 두 가드와, Ethereum에서의 에어드랍 전달을 위한 두 가스 정책으로, 각각 기본값, 하한, 상한으로 이루어집니다(setAirdropReceiveGas는 200,000과 1,500,000 사이의 650,000; setAirdropComposeGas는 600,000과 4,000,000 사이의 1,250,000; 0인 하한, 상한보다 높은 하한, 그 범위를 벗어난 기본값은 거부됨). 리모트 허브는 초기화할 때 둘 다 설정하며, DeployRemote는 그 환경 변수에서 이를 다시 설정합니다. 관리자가 지정하는 교체 오라클(setOracle)은 두 가드가 꺼진 상태로 시작하므로, 관리자는 그 오라클에 대해 가드를 다시 켭니다; 이미 초기화된 미러 볼트는 초기화될 때의 오라클을 유지합니다.

Ethereum에서 브리지 허브는 더 이상 자신의 어댑터를 배포하지 않습니다: 어댑터는 허브를 대상으로 배포된 뒤, StockFun의 오너가 한 번 지정하며(setAdapter), 이 호출이 어댑터의 고정값을 확인합니다. 이후의 교체인 changeAdapter는 2026-10-05부터 즉시 이루어집니다. 이 호출은 고정값이 현재 어댑터와 정확히 같은 어댑터만 받아들입니다: 같은 허브, 팩토리, 현금 토큰, 리모트 허브, 목적지 체인, 전송 방식. 가스 수치, 옵션, Curve 풀은 바꿀 수 있지만 목적지는 결코 바꿀 수 없습니다; 리모트 허브는 여전히 자신이 상정하고 만들어진 어댑터의 배치만 받아들입니다(M-2, 긴급 모드 참고). 따라서 어댑터는 같은 주소를 유지한 채 제자리에서 업그레이드하는 방식으로 바꿉니다; 새 주소를 쓰려면 먼저 리모트 허브를 업그레이드해 그 주소를 받아들이게 해야 합니다. 2026-10-05에 오너는 이를 그대로 유지하기로 결정했습니다.

어댑터 자체의 수치도 StockFun 오너의 설정입니다: USDG 레일에서는 Curve에서 허용하는 최악의 USDC당 USDG 비율, 기본값 30 베이시스 포인트와, Robinhood Chain에서의 전달 마지막 단계의 가스(setSettings); 열 번째 감사 루프 이후로, 2026-10-06부터, 그 가스는 모든 배치에 필요한 기본분(기본값 200,000)에 배치의 마켓마다의 몫(기본값 400,000)을 더한 것이며, 배치 하나는 많아야 마켓 17개를 담습니다(setBatchGas; 아래의 "배치의 compose 가스" 참고). 그 전까지는 수치 하나(기본값 1,200,000)가 무엇을 담았든 모든 배치에 지급되었습니다. 정식 브리지 레일에서는 두 티켓의 가스(setTicketGas). 2026-10-05부터 정식 브리지 레일의 회계 정보 티켓은 브리지의 인박스가 현재 base fee에서 배치 크기에 대해 요구하는 금액을 지불하며, 이 설정은 그 하한입니다. 가스 가격 없이 오프체인에서 읽은 견적은 base fee를 0으로 보고 그 티켓의 가격을 하한만으로 매겼으므로, 긴 배치는 실제 base fee에서 실패했습니다; 그날의 두 번째 감사 루프 이후로 키퍼는 자신이 지정하는 base fee, 즉 최신 base fee의 두 배로 견적을 요청하며(quoteBridgeAt), 초과분을 돌려받습니다. 네 번째 루프 이후로는 입금 티켓의 가격도 같은 방식으로 매겨집니다: 인박스가 base fee에서 depositCalldataLength() 바이트에 대해 요구하는 금액이며, tokenSubmissionCost 설정이 그 하한입니다. 그 길이도 오너의 설정입니다(setDepositCalldataLength, 결코 0이 아님): 기본값 1,024바이트로, 게이트웨이의 USDC 입금이 쓰는 740바이트보다 큽니다. 그 전까지 입금의 제출 비용은 고정 설정이었으며, base fee가 이를 넘어서면 모든 배치가 실패했습니다.

번지지 않는 장애

2026-09-29 보안 감사 이후, 2026-10-01부터:

  • 거부된 바스켓은 자신의 마켓만 막습니다. Robinhood Chain이 어떤 마켓의 바스켓을 거부하면(예를 들어 그곳의 라우터나 오라클이 지원하지 않는 주식이 있는 경우), 그 마켓의 미러 볼트는 초기화되지 않은 상태로 남아 현금을 보유하며, 이 현금은 긴급 모드로 회수할 수 있습니다. 같은 브리지 배치의 다른 마켓들은 그대로 처리됩니다. 이전에는 배치 전체가 실패했고, 누구나 정상 마켓들을 거부되는 마켓과 한데 묶을 수 있었습니다.
  • 원격 토큰 하나에 식별자 하나. 브리지 허브는 이미 매핑된 Robinhood Chain 토큰에 두 번째 바스켓 식별자를 매핑하는 것을 거부합니다.
  • 일시 중지된 리모트 허브도 역할은 적용합니다. 각 배치는 현재의 키퍼와 긴급 관리자를 담고 있습니다. 일시 중지된 허브도 이를 그대로 적용하므로, StockFun의 오너 변경은 항상 Robinhood Chain에 전달됩니다. 현금은 마켓별로 기록되며, 일시 중지 해제 후 스윕을 통해 미러 볼트로 지급됩니다.
  • 정식 브리지의 기록은 순서대로 지급됩니다. 테스트넷에서, 그리고 폴백으로 쓰이는 정식 Orbit 브리지에서는 토큰과 회계 정보가 별개의 티켓 두 개로 도착합니다. 허브는 누가 스윕을 트리거하든, 대기 중인 기록을 그 메시지가 도착한 순서대로 온전히 지급합니다. 2026-10-01 보안 파이프라인 이후로, 회계 정보 티켓은 자신이 대기열에 추가한 수만큼의 기록까지만 가장 오래된 것부터 지급하며, 그 기록은 이전 배치의 것일 수도 있습니다. 나머지는 스윕이 호출당 기본값으로 최대 64개 기록까지 지급합니다. 이전에는 일시 중지나 늦은 입금으로 쌓인 적체 때문에 티켓이 자동 실행의 고정 가스를 넘어설 수 있었고, 누군가 7일 안에 티켓을 수동으로 재실행하지 않으면 그 배치는 기록되지 않은 채로 남았습니다.

부분적으로 번지던 장애가 하나 있었습니다. 2026-10-01에 진행된 감사의 두 번째 라운드는 현금 토큰이 미러 볼트 하나를 거부하면(예를 들어 발행사가 그 주소를 동결한 경우) 정식 브리지의 대기열이 멈추고, 두 레일 모두에서 그 마켓과 한데 묶인 모든 배치가 실패한다는 것을 발견했습니다(R2H-2). 2026-10-05의 두 번째 감사 루프가 이를 완화했고, 같은 날 네 번째 루프가 이를 종결했습니다: 이제 그런 전달은 따로 대기하며, 배치는 계속 진행됩니다(아래).

2026-10-05 감사 루프 이후, 그날부터:

  • 브리징은 키퍼만 합니다. 브리지 배치 bridgeReady는 키퍼만 보낼 수 있습니다. 그 전까지는 누구나 브리지 배치를 보낼 수 있었습니다: 제3자가 Curve 풀에서 자신의 두 거래 사이에 어댑터가 허용하는 가장 느슨한 최소 수량으로 배치 하나를 끼워 넣거나, 키퍼의 배치에 든 볼트 하나를 먼저 브리지로 보내 그 배치를 실패하게 만들 수 있었습니다.
  • 리모트 허브에서의 긴급 회수는 정산될 뿐, 다른 마켓이 지급하지 않습니다. USDG 레일에서는 허브가 지급해야 할 것을 뒷받침하는 현금이 모자라는 동안 그것을 내주기를 거부합니다. 그 현금은 그날의 두 번째 감사 루프 이후로 허브가 스스로 세는 값으로, 아직 전달 중인 배치의 현금도 담고 있는 잔액이 결코 아닙니다; 현금은 restore를 통해 돌아옵니다. 정식 브리지 레일에서는 StockFun의 오너가 이동 전에 허브를 일시 중지하고, 긴급 회수가 그 현금을 가져간 기록을 제거한 뒤, 일시 중지를 해제합니다. 긴급 모드를 참고하십시오.

창업자의 규칙, 즉 하나의 실패가 결코 나머지를 막지 않는다는 규칙을 적용한 2026-10-05의 네 번째 감사 루프 이후로(아키텍처 참고):

  • 거부된 전달은 따로 대기합니다. USDG 레일에서는 현금 토큰이 거부하는 미러 볼트의 몫이, 그 마켓에 지급해야 할 것으로서 뒷받침된 채 리모트 허브에 남으며(DeliveryRefused), 배치의 다른 마켓들은 지급받습니다. 정식 브리지 레일에서는 그런 기록이 대기열을 떠나 그 마켓을 위해 별도로 보관되므로(undeliverable), 그 뒤의 기록들과 다음 티켓들은 지급됩니다. 두 레일 모두에서, 그 볼트가 다시 현금을 받게 되면 누구나 sweep(marketId)로 이를 지급할 수 있습니다. 2026-10-06부터 정식 브리지 레일에서는 키퍼가, 거부된 기록을 스윕 한 번이 한꺼번에 지급했거나 StockFun의 오너가 그 마켓에 차감한 전송도 닫으므로, 어떤 전송도 영원히 추적된 채 남지 않습니다.
  • 배치의 각 마켓은 따로 진행됩니다. bridgeReady는 목록에 있는 마켓 중 볼트가 현금을 내줄 수 없는 마켓 — 일시 중지되었거나, 비어 있거나, 발행사에게 거부되었거나, 다섯 번째 루프 이후로는 지정되기 전의 프로토콜 마켓의 볼트처럼 아직 코드가 없는 볼트 —, 알 수 없는 마켓, 또는 어댑터가 페이로드를 만들 수 없는 마켓을 제외하며(MarketSkipped), 나머지는 진행됩니다. 키퍼의 최소 수량은 목록에 있는 그대로의 배치를 기준으로 하며, 실제로 떠난 양에 비례해 줄어듭니다; Bridged는 떠난 마켓만 나열합니다. 아무것도 떠나지 않는 배치는 첫 번째 마켓의 이유와 함께 실패합니다.
  • 각 매수 레그는 따로 진행됩니다. Ethereum 볼트에서와 마찬가지로 미러 볼트에서도 그렇습니다(LegFailed): TreasuryVault를 참고하십시오.
  • 긴급 이동을 한 마켓에 차감할 수 있습니다. StockFun의 오너는 한 마켓의 현금을 옮기고 같은 호출에서 그 마켓의 장부를 정산하므로, 다른 어떤 마켓도 기다리지 않습니다: emergencyTransferFromPending은 USDG 레일에서 허브가 그 마켓에 지급해야 할 것을, 또는 정식 브리지 레일에서 그 마켓의 거부된 몫을 가져가며, emergencyTransferRecord는 대기열에 있는 정식 브리지 기록 하나를 통째로 가져갑니다. 다섯 번째 루프 이후로 후자는 입금이 도착한 기록을 위한 것입니다: 대기열의 현금은 한데 모여 있으므로, 거부된 몫을 위해 보관된 것이 아닌 현금을 넘는 금액은 거부합니다(RecordNotCovered). 입금을 잃어버린 기록은 상각합니다(writeOffRecord). USDG 레일에서 어느 마켓에도 차감되지 않는 이동은 설계상 전반적인 대기를 유지합니다: 현금이 반환되거나 상각될 때까지 장부에는 부족분이 나타납니다.
  • 보류된 가격은 자신의 레그만 멈춥니다(2026-10-06부터): 기업 행위 중인 주식은 모든 미러 볼트에서 자신의 레그만 단독으로 실패시킵니다; 시퀀서 검사가 설정되어 있으면, 시퀀서 중단은 시퀀서가 복구된 뒤 유예 기간이 지날 때까지 모든 레그를 멈추며, 현금은 볼트에서 기다립니다(위의 "오라클이 가격을 보류할 때").

배치의 compose 가스

열 번째 감사 루프 이후로, 2026-10-06부터. Robinhood Chain에서 브리지 배치의 마지막 단계, 즉 리모트 허브의 compose는 각 마켓의 미러 볼트를 초기화하고 자금을 넣으므로, 그 가스는 배치와 함께 커집니다. 예전에는 배치에 무엇이 담겼든 고정된 수치 하나, 기본값 1,200,000을 받았습니다: 주식 다섯 개짜리 바스켓의 새 마켓 네 개가 그 가스를 바닥냈습니다. 그러자 그 USDG는 아무 기록 없이 리모트 허브에 머물렀고, 같은 마켓이 든 이후의 모든 배치도 같은 식으로 실패했으며, Robinhood Chain의 엔드포인트에서 수동으로 실행해야만 움직였습니다. 잃은 것은 없었지만, 그동안 그 배치의 어떤 마켓도 매수되거나 에어드랍되지 않았습니다.

  • 기본분과 마켓당 몫. USDG 어댑터는 마켓 n개의 배치에 composeGas + n × composeGasPerMarket의 compose 가스를 주며, 기본값은 200,000에 마켓마다 400,000을 더한 것으로, 전송과 모든 견적에 똑같이 적용됩니다. LayerZero 자체의 엔드포인트를 통한 Robinhood Chain 테스트넷의 포크에서, 주식 다섯 개짜리 마켓의 첫 배치에는 약 294,000 가스(측정한 주식 한 개에서 세 개까지로부터 외삽한 값), 이미 설정된 마켓에는 21,000~39,000이 필요합니다
  • 배치 하나에 많아야 마켓 17개. LayerZero는 경로의 크기 제한(기본값 10,000바이트)을 넘는 메시지를 거부하며, 주식 다섯 개짜리 마켓은 각각 배치의 메시지에 많아야 544바이트를 더합니다: 17개 마켓은 들어가고, 18개는 들어가지 않습니다. 그보다 큰 배치는 무엇이든 움직이기 전에 통째로 거부되며, 각 볼트는 자신의 USDC를 유지합니다. 키퍼는 그 이상은 보내지 않고, 가장 오래 기다린 마켓부터 보내며, 나머지는 다음 바퀴에 나가므로 영원히 기다리는 마켓은 없습니다. 정식 브리지 레일에는 그런 상한이 없습니다
  • Robinhood Chain의 한도 안에서. 가장 큰 배치의 compose 가스는 많아야 24,000,000으로, Robinhood Chain이 트랜잭션 하나에서 실행하는 32,000,000 가스보다 낮습니다; 오너의 설정은 이를 넘을 수 없습니다. 메인넷 전에 오너는 Paxos의 USDG가 쓰는 경로의 크기 제한을 읽고, 다르면 상한을 그에 맞게 설정합니다
  • 비용은 작습니다. LayerZero의 익스큐터는 추가 가스를 Robinhood Chain의 가스 가격으로 청구합니다: 테스트넷에서 배치의 수수료는 가스 100만당 0.00001 ETH씩 늘어납니다
  • 이전 어댑터는 오너가 두 새 설정을 할 때까지 모든 배치를 거부하며, 어댑터의 업그레이드가 같은 트랜잭션에서 그 설정을 합니다. 테스트넷의 어댑터는 2026-10-06에 이렇게 업그레이드되었고, 그 다음 배치는 LayerZero의 익스큐터가 새 옵션, 즉 마켓 하나에 600,000 가스로 compose했으며, 그중 115,990이 쓰였습니다
  • 멈춘 compose는 그렇다고 알려 줍니다. 제때 적립되지 않은 전송에 대한 키퍼의 알림은 이제 Robinhood Chain의 엔드포인트에서 배치의 메시지를 읽습니다: 아직 그곳에 전달되지 않음; compose되었고 적립이 뒤따름; 또는 저장됨. 저장된 경우 그 USDG는 리모트 허브에 있으며 더 많은 가스로 수동으로 다시 실행되기를 기다리고, 이는 누구나 할 수 있으며, 알림은 저장된 메시지의 해시를 알려 줍니다. 키퍼는 여전히 브리지 compose를 스스로 실행하지 않습니다

검증된 것과 검증되지 않은 것

먼저 현재 상태입니다. 메인넷 배포도, 실제 자금의 이동도 이루어지지 않았습니다. 로컬 테스트는 전달을 시뮬레이션할 뿐, 실제 LayerZero 전달을 증명하지 않습니다. 2026-10-04에 코딩된 에어드랍 전송은 LayerZero와 주식 어댑터의 목을 상대로 테스트됩니다.

LayerZero 테스트넷 실행, 2026-10-06. 프로토콜은 Sepolia와 Robinhood Chain의 테스트넷에 배포되었으며(배포 트랜잭션 167개, 모두 성공), LayerZero의 실제 테스트넷 엔드포인트, DVN, 익스큐터 위에서 13:50부터 19:07 UTC까지 키퍼에 의해 처음부터 끝까지 실행되었습니다. 1시간짜리 측정 구간 7개에서, 각 측정 구간의 ETH는 한 번 전환되고, LayerZero 배치 하나로 브리지되며, 리모트 허브에서 compose를 거쳐 미러 볼트로 들어가, 테스트 주식 세 개에 쓰였습니다. 에어드랍 주기 6개가 열려 LayerZero로 되돌려 보내졌고, 에어드랍 컨트랙트에서 compose되었습니다; 처음 4개는 홀더 다섯 명이 전부 청구했고, 다섯 번째는 일부만 청구되었으며, 여섯 번째는 청구되지 않은 채 남았고, 각 지급은 보유량 기록기에서 독립적으로 계산한 몫과 정확히 같았습니다. 사고 대응 훈련(일시 중지, 긴급 이동과 restore, rescue, 트랜잭션이 대기 중인 채로 종료된 키퍼, 수동으로 실행한 compose, 오래된 피드, 일시 중지된 주식, 시퀀서 가드, 현금 토큰이 거부하는 전달)은 실제 메시지 위에서 진행되었고, 문서에 적힌 대로 복구되었으며, 예외는 두 개의 절반뿐이었습니다: Sepolia 브리지 허브의 일시 중지, 그리고 수동으로 실행한 브리지 compose. 실행 도중에 Sepolia가 Ethereum의 Glamsterdam 업그레이드를 활성화했습니다: 첫 에어드랍 전달들은 LayerZero의 익스큐터에서 가스가 바닥나 수동으로 실행되었고, 전달 가스의 수정(위 참고)이 업그레이드로 적용되어 이후의 주기들을 감당했습니다. 키퍼는 18:25에 아홉 번째 감사 루프의 코드로 재시작되었으며, 자신의 시뮬레이션으로 고른 가스로 마지막 측정 구간을 문제없이 실행했습니다.

그 실행이 증명하지 않는 것: Paxos의 USDG. 그 테스트넷 토큰은 이 테스트넷들에서 OFT 기능이 없으므로, 메인넷 쌍과 같은 모양을 한, LayerZero의 MintBurnOFTAdapter 아래의 테스트 USDG가 그 자리를 대신했으며, 그 쌍의 DVN, 동결, 일시 중지는 어느 것도 시험되지 않았습니다; Robinhood의 주식과 그 어댑터. LayerZero의 OFTAdapter 아래의 테스트 주식이 그 자리를 대신했습니다; 실제 가격 피드와 실제 유동성; 메인넷의 가스, 수수료, 완결성. 메인넷 시험, 즉 검증용 볼트에서의 첫 소규모 주기가 아직 남아 있습니다.

예전 Sepolia 스크립트는 정식 Orbit 브리지를 사용하며 LayerZero를 검증하지 않습니다. 포크에서의 성공도, 테스트넷에서의 성공도 메인넷에서의 실제 전달의 증거가 아닙니다.