Sponsored 트랜잭션
Sui에서 트랜잭션을 실행하려면 gas payment가 필요하다. Payment는 0x2::coin::Coin<0x2::sui::SUI> 객체 목록이다.
Sponsored 트랜잭션을 사용하면 다른 사용자를 대신해 가스 수수료를 지불할 수 있다. 사용자는 SUI를 소유하거나 gas mechanism을 이해하지 않아도 트랜잭션을 실행할 수 있으므로 onboarding friction이 줄어든다. Sponsor는 트랜잭션에 사용할 gas payment 객체를 제공한다.
role
Sponsored 트랜잭션에는 세 가지 role이 있다:
-
User: 트랜잭션을 실행하려는 entity이다.
-
Gas station: user 트랜잭션에 gas payment 객체를 제공하는 service이다.
-
Sponsor: gas station에 자금을 제공하는 entity이다.
Gas station과 sponsor는 같은 entity인 경우가 많다. 예를 들어 Web3 gaming company는 user acquisition 중 free-to-play experience를 제공하기 위해 자체 gas station을 운영할 수 있다. 또는 자체 운영 대신 third-party gas station service를 사용할 수도 있다.
데이터 구조
Sponsored 트랜잭션의 data structure는 다음과 유사하다:
pub struct SenderSignedTransaction {
pub intent_message: IntentMessage<TransactionData>,
/// A list of signatures signed by all transaction participants.
/// 1. non participant signature must not be present.
/// 2. signature order does not matter.
pub tx_signatures: Vec<GenericSignature>,
}
pub struct TransactionDataV1 { // <-- A variant of `TransactionData`
pub kind: TransactionKind, // <-- This is the actual transaction details
pub sender: SuiAddress,
pub gas_data: GasData,
pub expiration: TransactionExpiration,
}
pub struct GasData {
pub payment: Vec<ObjectRef>,
pub owner: SuiAddress,
pub price: u64,
pub budget: u64,
}
앞의 code에서 주목할 부분은 다음과 같다:
-
sender(TransactionDataV1의 variant)의TransactionData는 user address이다. -
gas_data의TransactionDataV1는 gas payment이다. -
GasData는 gas 객체 목록을 허용하지만, 동일한 address가 이를 소유해야 한다. 즉owner의GasData인 sponsor가 소유해야 한다.owner가sender와 같으면 regular 또는 non-sponsored 트랜잭션이다. -
tx_signatures의SenderSignedTransaction는 signature 목록이다. Sponsored 트랜잭션에서는 user와 sponsor의 signature가 어떤 순서로든 모두 포함되어야 한다. Signature는TransactionData를 포함한 전체GasData에 대해 서명된다.
올바른 sponsored 트랜잭션을 구성하려면 먼저 TransactionData 객체를 build해야 한다. user도 sponsor도 아니라면 트랜잭션을 두 당사자 모두에게 전달해 서명하게 한다. sponsor라면 트랜잭션에 서명한 다음 트랜잭션과 signature를 다른 당사자에게(SenderSignedTransaction 형태로) 전달하여 서명하게 한다. 실제로는 후자가 더 일반적인 scenario이다.
GasData 객체를 사용해 sponsored 트랜잭션 생성
GasData 객체를 사용해 트랜잭션의 가스 수수료를 sponsor하려면 트랜잭션에 대해 결정된 fee를 충당하는 GasData 객체를 만든다. User는 fee가 얼마인지 알거나 승인할 필요가 없다.
GasData 객체를 사용하는 sponsor 트랜잭션은 다음 단계로 이루어진다:
-
sponsor가 user 에게
GasData객체를 제공한다. -
user가
TransactionData를 구성하고 서명하여Signature를 생성한다. -
user가
TransactionData와Signature를 sponsor에게 보낸다. -
sponsor가
TransactionData를 확인한 다음 서명한다. -
sponsor가 dual-signed
TransactionData를 full node에 submit하여 트랜잭션을 실행한다.
GasLessTransactionData
GasLessTransactionData는 TransactionData가 없는 GasData이다. 이는 sui-core data structure가 아니라 user와 sponsor 사이의 interface일 뿐이다.
다음 예시는 GasLessTransactionData 객체를 구성한다:
pub struct GasLessTransactionData {
pub kind: TransactionKind,
sender: SuiAddress,
…
}
User proposed 트랜잭션 단계
Gas payment를 제공하기 전에 트랜잭션이 승인된 application 범위 안에 있는지 검토한다.
User-proposed sponsored 트랜잭션은 다음 단계로 이루어진다:
-
user가
GasLessTransactionData트랜잭션을 초기화한다. -
user가
GasLessTransactionData를 sponsor에게 보낸다. -
sponsor가 트랜잭션을 validate하고 가스 수수료가 포함된
TransactionData를 구성한 다음TransactionData에 서명한다. -
sponsor가 signed
TransactionData와 sponsorSignature를 user에게 다 시 보낸다. -
user가
TransactionData를 verify한 다음 서명하고 dual-signed 트랜잭션을 full node 또는 sponsor를 통해 Sui network에 보낸다.

Sponsor proposed 트랜잭션 단계
Sponsor는 rewards claim 또는 promotional offer 같은 트랜잭션을 제안하고 user는 이를 실행할지 결정한다. Sponsor proposed sponsored 트랜잭션은 다음 단계로 이루어진다:
-
sponsor가 트랜잭션 detail과 관련 가스 수수료 data를 포함하는
TransactionData객체를 구성한다. Sponsor는 user에게 보내기 전에 서명하여Signature를 생성한다. UnsignedTransactionData는 email, SMS 또는 application interface를 통해 보낼 수 있다. -
user가 트랜잭션을 확인하고 서명하여 트랜잭션의 두 번째
Signature를 생성한다. -
user가 dual-signed 트랜잭션을 Sui full node 또는 sponsor에 submit하여 실행한다.
Sponsor proposed 트랜잭션은 advertiser로서 사용하거나 user가 가스 수수료를 지불하지 않고 특정 action을 수행하도록 incentive를 제공할 때 사용할 수 있다.

Wildcard gas payment 처리
Sponsor는 제한이 거의 없는 모든 valid 트랜잭션을 sponsor한다.
-
Gasless wallets: user가 제안하는 모든 valid 트랜잭션을 sponsor하는 데 동의한다.
-
Rewards or discounts: budget 내에서 어떤 트랜잭션이든 실행하는 wildcard gas payment를 제공한다.

API endpoint 예시
// User-initiated: receive GaslessTransaction, return signed TransactionData
pub fn request_gas_and_signature(gasless_tx: GaslessTransaction) -> Result<SenderSignedData, Error>;
// Wildcard: return a GasData object for the user
pub fn request_gas(/* requirements */) -> Result<GasData, Error>;
// Submit a single-signed transaction, sponsor signs and executes
pub fn submit_sole_signed_transaction(sole_signed_data: SenderSignedData) -> Result<(Transaction, CertifiedTransactionEffects), Error>;
// Submit a dual-signed transaction for execution
pub fn submit_dual_signed_transaction(dual_signed_data: SenderSignedData) -> Result<(Transaction, CertifiedTransactionEffects), Error>;
Risk consideration
Sponsored 트랜잭션에는 여러 party가 관여하므로 추가 risk가 생긴다.
Client equivocation
Client equivocation은 같은 version의 소유 객체(예: 가스 코인)를 하나 이상 공유하는 여러 valid 트랜잭션이 network에 동시에 submit될 때 발생한다.
Transaction이 submit되면 validator는 소유 객체를 현재 version에서 lock한다. 각 validator는 객체 version마다 하나의 트랜잭션만 accept하고 나머지는 reject한다. Validator가 competing 트랜잭션을 서 로 다른 순서로 받을 수 있으므로 서로 다른 트랜잭션을 accept할 수 있다. 단일 트랜잭션이 validator의 3분의 2 이상에게 accept되지 않으면 소유 객체는 epoch 끝까지 locked 상태로 남는다.
Client equivocation은 드물며 보통 buggy client software에서 발생한다. 그러나 sponsored 트랜잭션는 counterparty risk를 추가한다:
-
malicious user가 gas station의 signed 트랜잭션에 포함된 소유 객체를 사용하는 competing 트랜잭션을 submit하여 gas station의 가스 코인을 lock할 수 있다.
-
malicious gas station도 user-소유 객체를 유사하게 lock할 수 있다.
이러한 risk를 완화하려면:
-
gas station은 user behavior를 monitor하고 anomaly를 flag해야 한다.
-
user와 sponsor 모두 counterparty의 reputation을 고려해야 한다.
-
양 당사자는
TransactionData를 포함한 전체GasData에 서명해야 한다. 이렇게 하면 malicious full node 같은 third party가 partially signed data를 intercept하여 equivocation을 일으키는 것을 방지할 수 있다.
Censorship risk
Dual-signed 트랜잭션을 full node에 직접 submit하지 않고 sponsor 또는 gas station을 통해 submit하면 sponsor가 트랜잭션을 network에서 delay하거나 withhold할 수 있다.
이 risk를 피하려면 트랜잭션을 full node에 직접 submit한다.