Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

보장된 릴레이 트랜잭션

@stablechain/enterprise와 함께 두 가지 Enterprise 레일을 결합합니다. 보장된 릴레이 트랜잭션은 가스 면제 트랜잭션보장된 블록 공간을 통해 라우팅하는 것입니다. 즉, 면제 기능이 가스를 후원하므로 사용자는 잔액이나 수수료 필드가 필요 없으며, 트랜잭션은 예약된 Enterprise 레인으로 전달됩니다.

guaranteedWaiver 모듈은 양쪽을 모두 처리합니다. 사용자는 내부 0x3F CustomTx에 서명하고, 화이트리스트에 등록된 면제 계정은 동일한 Enterprise nonceKey를 공유하는 외부 0x3F CustomTx로 이를 래핑한 후, Enterprise RPC 게이트웨이를 통해 브로드캐스트합니다. 모든 메서드는 사용자 트랜잭션 해시인 H_inner를 반환합니다.

전제 조건

  • Node.js 20 이상, 그리고 @stablechain/enterpriseviem이 설치되어 있어야 합니다. Enterprise SDK 참조를 참조하세요.
  • 거버넌스에 등록된 면제 키와 Enterprise RPC 게이트웨이 API 키가 필요합니다. Enterprise SDK는 Stable Mainnet 및 Stable Testnet에서 실행되며, 접근은 요청 시 가능합니다. 둘 다 얻으려면 Stable에 문의하세요.

1. 보장된 면제 모듈을 사용하여 클라이언트 생성

guaranteedWaiverenterpriseRpcEndpointscreateStableEnterprise에 전달합니다. 이 모듈은 화이트리스트에 등록된 면제 키(외부 래퍼에 서명)와 Enterprise 레인을 사용합니다. 또한 gasWaiver와 동일한 allowedTargets, maxGasLimit, maxDataLength 정책 제한도 허용합니다.

import { createStableEnterprise, stable } from "@stablechain/enterprise";
import { privateKeyToAccount } from "viem/accounts";
 
const enterprise = createStableEnterprise({
  chain: stable,
  enterpriseRpcEndpoints: [process.env.ENTERPRISE_RPC_URL], // Stable이 제공하는 게이트웨이 URL
  guaranteedWaiver: {
    account: privateKeyToAccount(process.env.WAIVER_PRIVATE_KEY as `0x${string}`),
    laneId: 0n, // Enterprise 레인
  },
});
 
const gw = enterprise.guaranteedWaiver;
StableEnterpriseClient { gasWaiver: undefined, guaranteedBlock: undefined, guaranteedWaiver }

2. 단일 트랜잭션 릴레이

사용자의 계정과 변경되는 필드를 사용하여 send를 호출합니다. 가스가 면제되므로 사용자는 잔액이나 수수료 필드가 필요 없습니다. 내부 0x3F CustomTx, 해당 Enterprise nonceKey, 그리고 (게이트웨이에서 발견된) 2D 논스는 자동으로 처리됩니다.

const user = privateKeyToAccount(process.env.USER_PRIVATE_KEY as `0x${string}`);
 
const { txHash } = await gw.send(user, { to: recipient });
console.log("H_inner:", txHash);
H_inner: 0x8f3a...2d41

gas는 공유된 내부 가스 기본값으로 설정됩니다. 이를 재정의하려면 gas를 전달합니다. 값 전송이 허용되므로 value도 전달할 수 있습니다.

3. 배치 릴레이

한 사용자로부터 여러 트랜잭션을 릴레이하려면 sendBatch를 호출합니다. 내부 논스는 발견된 기본값에서 자동으로 순서가 지정되며, 입력 순서대로 입력당 하나의 결과를 얻습니다. 실패하면 후속 작업이 중단됩니다.

const results = await gw.sendBatch(user, [{ to: a }, { to: b }]);
 
for (const r of results) {
  console.log(r.success ? `[${r.index}] ✔ ${r.txHash}` : `[${r.index}] ✖ ${r.error?.code}`);
}
[0] ✔ 0x8f3a...2d41
[1] ✔ 0x2b7c...9e04

4. 사전 서명된 트랜잭션 릴레이

비수탁 흐름의 경우, 사용자는 자신의 환경에서 내부 0x3F CustomTx에 서명하고 서명된 헥스만 전달합니다. buildGuaranteedTx를 사용하여 이를 구성하고, Enterprise 논스 키에는 nonceKeyForLane을 사용하며 수수료는 0으로 설정합니다(가스는 면제됩니다). 백엔드는 이를 면제 키로 래핑하고 relay를 사용하여 릴레이합니다.

import { buildGuaranteedTx, nonceKeyForLane, toSigner } from "@stablechain/enterprise";
 
// 사용자 측 — buildGuaranteedTx는 Signer를 통해 서명합니다. toSigner는 viem 계정을 조정합니다.
const signedInner = await buildGuaranteedTx(toSigner(user), stable.id, {
  to: recipient,
  gas: 100_000n,
  gasFeeCap: 0n, // 면제됨
  gasTipCap: 0n,
  nonce, // 사용자의 현재 2D-레인 논스
  nonceKey: nonceKeyForLane(0n), // Enterprise 레인 0
});
 
// 백엔드에서
const { txHash } = await gw.relay(signedInner); // 면제 래핑 + 브로드캐스트 → H_inner
console.log("H_inner:", txHash);
H_inner: 0x8f3a...2d41

여러 개의 사전 서명된 트랜잭션에는 relayBatch를 사용하세요.

거절 처리

sendrelay는 거절 시 StableEnterpriseRelayError를 발생시킵니다. 이 흐름은 게이트웨이를 통해 라우팅되므로 GATEWAY_UNAUTHORIZEDQUOTA_EXCEEDED와 같은 게이트웨이 코드와 TARGET_NOT_ALLOWED와 같은 면제 정책 코드가 적용됩니다.

import { StableEnterpriseRelayError } from "@stablechain/enterprise";
 
try {
  await gw.send(user, { to: recipient });
} catch (err) {
  if (err instanceof StableEnterpriseRelayError && err.code === "GATEWAY_UNAUTHORIZED") {
    // Enterprise RPC 게이트웨이가 API 키를 거부했습니다.
  }
  throw err;
}
StableEnterpriseRelayError: relay failed [GATEWAY_UNAUTHORIZED]: invalid api key

모든 거절 이유에 대한 전체 ErrorCode 표를 참조하세요.

다음 단계