결제고급 결제
Solana의 토큰 프로그램은 위임을 지원합니다. 이는 다른 계정에 지정된 한도까지 귀하의 토큰 계정에서 토큰을 전송할 수 있는 권한을 부여하는 것입니다. 이를 통해 자금의 보관권을 포기하지 않으면서도 자동 결제, 에스크로 서비스, 제3자 결제 처리와 같은 사용 사례를 구현할 수 있습니다.
위임 작동 방식
위임자를 승인하면 특정 계정이 귀하를 대신하여 토큰을 전송할 수 있도록 권한을 부여하는 것입니다.
- 소유자가 보관권 유지: 귀하는 여전히 토큰을 소유하며 언제든지 전송하거나 취소할 수 있습니다
- 지출 한도 설정: 위임자는 승인된 금액까지만 전송할 수 있습니다
- 계정당 단일 위임자: 각 토큰 계정은 하나의 활성 위임자만 가질 수 있습니다
- 새 승인이 이전 승인 대체: 새 위임자를 승인하면 이전 위임자가 자동으로 취소됩니다
위임은 비수탁 방식입니다. 위임자는 한도까지 토큰을 지출할 수 있지만, 승인된 금액을 초과하여 계정에 접근하거나 인출할 수 없습니다. 소유자는 언제든지 취소할 수 있습니다.
비즈니스 사용 사례
| 사용 사례 | 위임이 도움이 되는 방식 |
|---|---|
| 결제 처리업체 | 판매자가 처리업체에 거래 정산 권한 부여 |
| 자동 급여 지급 | 재무부가 급여 서비스에 급여 지급 승인 |
| 에스크로 서비스 | 구매자가 조건부 출금을 위해 에스크로 대리인에게 위임 |
| 거래 플랫폼 | 사용자가 거래소에 대신 거래 실행 승인 |
| 카드 발급 | 사용자가 카드 발급사에 토큰 계정에서 구매 대금 청구 승인 |
위임자 승인
다른 계정에 귀하의 계정에서 토큰을 사용할 수 있는 권한을 부여합니다:
import { getApproveCheckedInstruction } from "@solana-program/token";// Approve delegate to spend up to 1,000 USDC (6 decimals)const approveInstruction = getApproveCheckedInstruction({source: tokenAccountAddress, // Your token accountmint: usdcMintAddress, // USDC mintdelegate: delegateAddress, // Account receiving permissionowner: ownerKeypair, // You (must sign)amount: 1_000_000_000n, // 1,000 USDC in base unitsdecimals: 6});
매개변수:
source: 권한을 부여하는 토큰 계정delegate: 사용 권한을 갖게 될 계정owner: 토큰 계정의 현재 소유자(트랜잭션에 서명해야 함)amount: 위임자가 전송할 수 있는 최대 토큰 수decimals: 검증을 위한 토큰 소수점 자릿수(소수점 오류 방지)
데모
Approve Delegate
// Generate keypairs for sender and delegateconst sender = (await generateKeypair()).signer;const delegate = (await generateKeypair()).signer;console.log("Sender Address:", sender.address);console.log("Delegate Address:", delegate.address);// Demo Setup: Create client, mint account, token account, and fund with initial tokensconst { client, mint, senderAta } = await demoSetup(sender);console.log("\nMint Address:", mint.address);console.log("Sender ATA:", senderAta);// =============================================================================// Approve Delegate// =============================================================================// Create instruction to approve delegateconst approveInstruction = getApproveCheckedInstruction({source: senderAta,mint: mint.address,delegate: delegate.address,owner: sender,amount: 1_000_000n, // 1.0 tokens with 6 decimalsdecimals: 6});// Send approve transactionconst signature = await client.transaction.prepareAndSend({authority: sender,instructions: [approveInstruction]});console.log("\n=== Approve Delegate ===");console.log("Transaction Signature:", signature);// Fetch token account data to show delegate is setconst tokenData = await fetchToken(client.runtime.rpc, senderAta);console.log("\nSender Token Account Data:", tokenData.data);// =============================================================================// Demo Setup Helper Function// =============================================================================
Console
Click to execute the code.
위임자 권한 취소
현재 위임자의 모든 지출 권한을 제거합니다:
import { getRevokeInstruction } from "@solana-program/token";const revokeInstruction = getRevokeInstruction({source: tokenAccountAddress, // Your token accountowner: ownerKeypair // You (must sign)});
취소는 모든 위임자 권한을 제거합니다—부분 취소는 불가능합니다. 한도를 줄여야 하는 경우, 동일한 위임자에게 더 낮은 금액으로 다시 승인하세요.
데모
Revoke Delegate
// Generate keypairs for sender and delegateconst sender = (await generateKeypair()).signer;const delegate = (await generateKeypair()).signer;console.log("Sender Address:", sender.address);console.log("Delegate Address:", delegate.address);// Demo Setup: Create client, mint account, token account, and fund with initial tokensconst { client, mint, senderAta } = await demoSetup(sender);console.log("\nMint Address:", mint.address);console.log("Sender ATA:", senderAta);// =============================================================================// Transaction 1: Approve Delegate// =============================================================================// Create instruction to approve delegateconst approveInstruction = getApproveCheckedInstruction({source: senderAta,mint: mint.address,delegate: delegate.address,owner: sender,amount: 1_000_000n, // 1.0 tokens with 6 decimalsdecimals: 6});// Send approve transactionconst approveSignature = await client.transaction.prepareAndSend({authority: sender,instructions: [approveInstruction]});console.log("\n=== Transaction 1: Approve Delegate ===");console.log("Transaction Signature:", approveSignature);// Fetch token account data to show delegate is setconst tokenDataAfterApprove = await fetchToken(client.runtime.rpc, senderAta);console.log("\nSender Token Account Data:", tokenDataAfterApprove.data);// =============================================================================// Transaction 2: Revoke Delegate// =============================================================================// Create instruction to revoke delegateconst revokeInstruction = getRevokeInstruction({source: senderAta,owner: sender});// Send revoke transactionconst revokeSignature = await client.transaction.prepareAndSend({authority: sender,instructions: [revokeInstruction]});console.log("\n=== Transaction 2: Revoke Delegate ===");console.log("Transaction Signature:", revokeSignature);// Fetch token account data to show delegate is revokedconst tokenDataAfterRevoke = await fetchToken(client.runtime.rpc, senderAta);console.log("\nSender Token Account Data:", tokenDataAfterRevoke.data);// =============================================================================// Demo Setup Helper Function// =============================================================================
Console
Click to execute the code.
위임자로서 전송하기
위임자로 활동할 때는 표준 전송을 사용하되 소유자 대신 위임자 keypair로 서명합니다:
Transfer as Delegate
import { getTransferCheckedInstruction } from "@solana-program/token";const transferInstruction = getTransferCheckedInstruction({source: ownerTokenAccount, // The account you have permission to spend frommint: usdcMintAddress,destination: recipientTokenAccount,authority: delegateKeypair, // You (the delegate) sign, not the owneramount: 100_000_000n, // 100 USDCdecimals: 6});
다음 조건이 충족되면 전송이 성공합니다:
- 출처 계정에 충분한 잔액이 있음
- 위임자가 트랜잭션에 서명함
각 전송은 남은 허용량을 감소시킵니다. 허용량이 0에 도달하면 위임자는 더 이상 토큰을 전송할 수 없습니다.
데모
Transfer as Delegate
// Generate keypairs for sender, delegate, and recipientconst sender = (await generateKeypair()).signer;const delegate = (await generateKeypair()).signer;const recipient = (await generateKeypair()).signer;console.log("Sender Address:", sender.address);console.log("Delegate Address:", delegate.address);console.log("Recipient Address:", recipient.address);// Demo Setup: Create client, mint account, token accounts, and fund with initial tokensconst { client, mint, senderAta, recipientAta } = await demoSetup(sender,delegate,recipient);console.log("\nMint Address:", mint.address);console.log("Sender ATA:", senderAta);console.log("Recipient ATA:", recipientAta);// =============================================================================// Transaction 1: Approve Delegate// =============================================================================// Create instruction to approve delegateconst approveInstruction = getApproveCheckedInstruction({source: senderAta,mint: mint.address,delegate: delegate.address,owner: sender,amount: 1_000_000n, // 1.0 tokens with 6 decimalsdecimals: 6});// Send approve transactionconst approveSignature = await client.transaction.prepareAndSend({authority: sender,instructions: [approveInstruction]});console.log("\n=== Transaction 1: Approve Delegate ===");console.log("Delegate Address:", delegate.address);console.log("Transaction Signature:", approveSignature);// =============================================================================// Fetch Token Account Data to Demonstrate Delegate is Set// =============================================================================const tokenAccountData = await fetchToken(client.runtime.rpc, senderAta);console.log("\nSender Token Account Data:", tokenAccountData.data);// =============================================================================// Transaction 2: Transfer Using Delegate// =============================================================================// Create instruction to transfer tokens using delegate// Note: delegate is the authority here, not the ownerconst transferInstruction = getTransferCheckedInstruction({source: senderAta,mint: mint.address,destination: recipientAta,authority: delegate, // Delegate signs this transactionamount: 500_000n, // 0.5 tokens with 6 decimalsdecimals: 6});// Send transfer transaction// Delegate pays for the transaction and authorizes the transfer (sender not needed)const transferSignature = await client.transaction.prepareAndSend({authority: delegate, // Delegate pays fee and signsinstructions: [transferInstruction]});// =============================================================================// Fetch Final Token Account Balances// =============================================================================const finalSenderToken = await fetchToken(client.runtime.rpc, senderAta);const finalRecipientToken = await fetchToken(client.runtime.rpc, recipientAta);console.log("\n=== Transaction 2: Transfer Using Delegate ===");console.log("Transaction Signature:", transferSignature);console.log("\nSender Token Account Data:", finalSenderToken.data);console.log("\nRecipient Token Account Data:", finalRecipientToken.data);// =============================================================================// Demo Setup Helper Function// =============================================================================
Console
Click to execute the code.
위임 상태 확인
토큰 계정을 조회하여 현재 위임자와 남은 허용량을 확인합니다:
import { fetchToken } from "@solana-program/token";const tokenAccount = await fetchToken(rpc, tokenAccountAddress);if (tokenAccount.data.delegate) {console.log("Delegate:", tokenAccount.data.delegate);console.log("Remaining allowance:", tokenAccount.data.delegatedAmount);} else {console.log("No delegate set");}
데모
Check Delegation Status
// Demo Setup: Create client, mint, two token accounts (one with delegate, one without)const { client, ataWithDelegate, ataWithoutDelegate } = await demoSetup();// =============================================================================// Fetch Token Accounts// =============================================================================// Fetch token account with delegateconst tokenWithDelegate = await fetchToken(client.runtime.rpc, ataWithDelegate);console.log("Token Account with Delegate:", tokenWithDelegate);// Fetch token account without delegateconst tokenWithoutDelegate = await fetchToken(client.runtime.rpc,ataWithoutDelegate);console.log("\nToken Account without Delegate:", tokenWithoutDelegate);// =============================================================================// Demo Setup Helper Function// =============================================================================
Console
Click to execute the code.
보안 고려사항
계정 소유자의 경우:
- 신뢰할 수 있는 위임자만 승인하세요
- 필요한 최소한의 지출 한도를 설정하세요
- 더 이상 필요하지 않을 때 위임을 취소하세요
- 예상치 못한 전송이 있는지 계정을 모니터링하세요
서비스 제공자(위임자)의 경우:
- 사용자에게 요청된 지출 한도를 명확하게 전달하세요
- 위임자 계정에 대한 적절한 키 관리를 구현하세요
- 한도가 소진되기 전에 재승인을 요청할 수 있도록 허용량 소비를 추적하세요
위임 vs. 보관
| 측면 | 위임 | 완전 보관 |
|---|---|---|
| 토큰 소유권 | 사용자가 보유 | 사용자가 보관자에게 이전 |
| 지출 통제 | 승인된 금액으로 제한 | 이전된 자금에 대한 전체 접근 |
| 취소 | 소유자가 즉시 가능 | 보관자의 협조 필요 |
| 위험 노출 | 승인된 금액으로 제한 | 전체 잔액 |
| 필요한 신뢰 | 제한적 | 높음 |
위임은 중간 지점을 제공합니다—승인된 금액으로 위험 노출을 제한하면서 자동 결제를 가능하게 합니다.
관련 리소스
Is this page helpful?