액션 요청
토큰과 코인의 주요 차이점은 토큰이 transfers, conversions, 또는 spends를 기본적으로 허용하지 않는다는 점이다. 하지만 이러한 액션을 허용하는 권한 부여 메커니즘이 있다. 이 메커니즘은 ActionRequest라고 한다. 각 액션을 독립적으로 허용하거나 허용하지 않도록 선택할 수 있다(요청 확정 섹션 참조).
protected 액션
Tokens에는 ActionRequest를 생성하는 네 가지 protected 액션이 있다:
| Function | Action name | Description | Special 필드 in ActionRequest |
|---|---|---|---|
token::from_coin | from_coin | 코인을 토큰으로 변환한다 | - |
token::to_coin | to_coin | 토큰을 코인으로 변환한다 | - |
token::transfer | transfer | 토큰을 recipient에게 전송한다 | recipient 필드를 포함한다 |
token::spend | spend | 토큰을 spend한다 | spent_balance 필드를 포함한다 |
ActionRequest 구조
ActionRequest는 sui::token 모듈에 정의되어 있으며 다음 필드를 포함한다:
name: 수행된 액션의 이름이며, 표준 액션은transfer,spend,to_coin,from_coin이고, 커스텀 액션을 생성할 수 있다.amount: 전송, spend, 변환 등 수행 중인 토큰의 amount이다.sender: 액션을 시작한 계정이다.recipient:transfer액션에서 토큰을 수신하는 계정이다(커스텀 액션에 사용한다).spent_balance:spend액션에서 spend된 토큰의 잔액이다(커스텀 액션에 사용한다).
규칙은 이러한 필드를 사용해 액션을 허용해야 하는지 여부를 결정할 수 있다. 규칙은 제한 로직을 구현하는 커스텀 모듈이다. 자세한 내용은 규칙를 참조한다.
ActionRequest를 생성하는 함수의 예시는 다음과 같다:
// module: sui::token
public fun transfer<T>(
t: Token<T>, recipient: address, ctx: &mut TxContext
): ActionRequest<T>;
요청 확정
다음을 사용하여 ActionRequest를 확정하는 세 가지 방법이 있다:
TreasuryCap- 사용자(또는TreasuryCap을 저장하는 애플리케이션)는token::confirm_with_treasury_cap함수를 호출하여 어떤 요청이든 확정할 수 있다. 이 방법은TreasuryCap을 저장하고 커스텀 로직을 구현하는 애플리케이션에 유용하다; 또한 제한을 우회하여 토큰을mint하고transfer할 수 있다.TokenPolicy- 공유TokenPolicy를 생성하고 각 액션에 대해 허용된 액션과 요구 사항을 설정한다. 이 방식으로 애플리케이션 또는 지갑은 어떤 액션이public으로 간주되는지 알 수 있으며, 따라서 이를 수행할 수 있다.TokenPolicyCap-TokenPolicy를 관리하는 capability를 사용하여 요청을 확정한다. 이 방법은TreasuryCap이 wrapped되어 접근할 수 없는 애플리케이션에서 유용할 수 있다; 그리고 일부 관리자 액션을 authorize해야 한다.
TokenPolicyCap을 사용해 spend 요청을 확정할 수 없다.
TreasuryCap으로 확정
TreasuryCap을 사용해 토큰에 대한 어떤 액션 요청이든 확정한다. 이는 관리자 액션(예: mint와 transfer)에 유용하며, 토큰 정책이 필요하지 않고 TreasuryCap을 main 객체에 wrap하는 단순한 애플리케이션에도 유용하다.
token::confirm_with_treasury_cap 함수의 서명은 다음과 같다:
// module: sui::token
public fun confirm_with_treasury_cap<T>(
treasury_cap: &mut TreasuryCap<T>,
request: ActionRequest<T>,
ctx: &mut TxContext
): (String, u64, address, Option<address>);
TypeScript와 sui.js로 구현된 트랜잭션 예시로, TreasuryCap을 사용해 액션 요청을 확정한다. 여기서 관리자 계정은 TreasuryCap을 소유하며, 이를 사용해 토큰을 민트하고 토큰의 전송 요청을 확정한다:
let tx = new Transaction();
let tokenType = '0x....::my_token::MY_TOKEN';
let treasuryCapArg = tx.object('0x....');
// mint 10 tokens using the `TreasuryCap`
let token = tx.moveCall({
target: '0x2::token::mint',
arguments: [treasuryCapArg, tx.pure.u64(10)],
typeArguments: [tokenType],
});
// transfer the token to a recipient; receive an `ActionRequest`
let request = tx.moveCall({
target: '0x2::token::transfer',
arguments: [token, tx.pure.address('0x...')],
typeArguments: [tokenType],
});
// confirm the request with the `TreasuryCap`
tx.moveCall({
target: '0x2::token::confirm_with_treasury_cap',
arguments: [treasuryCapArg, request],
typeArguments: [tokenType],
});
// submit the transaction
// ...
TokenPolicy로 확정
TokenPolicy는 네트워크 전반에서 특정 액션을 활성화하는 방법이다. share 이후에는 TokenPolicy를 모두가 사용할 수 있다. 따라서 지갑 또는 다른 클라이언트는 이를 사용해 허용된 operation을 확정할 수 있다.
token::confirm_request 함수의 서명은 다음과 같다:
// module: sui::token
public fun confirm_request<T>(
treasury_cap: &TokenPolicy<T>,
request: ActionRequest<T>,
ctx: &mut TxContext
): (String, u64, address, Option<address>);
spend 요청인 경우에는 대신 confirm_request_mut 함수를 사용한다.
JavaScript에서 클라이언트 전송 요청을 확정하는 예시는 다음과 같다:
let tx = new Transaction();
let tokenType = '0x....::my_token::MY_TOKEN';
let myTokenArg = tx.object('0x...token_object');
let receiverArg = tx.pure.address('0x...receiver');
let tokenPolicyArg = tx.object('0x...token_policy');
let request = tx.moveCall({
target: '0x2::token::transfer',
arguments: [myTokenArg, receiverArg],
typeArguments: [tokenType],
});
// expecting the `TokenPolicy` to have the `transfer` operation allowed
tx.moveCall({
target: '0x2::token::confirm_request',
arguments: [tokenPolicyArg, request],
typeArguments: [tokenType],
});
// submit the transaction
// ...
TokenPolicyCap으로 확정
TokenPolicyCap을 사용해 액션 요청을 확정한다. 이는 TreasuryCap이 다른 객체에 wrapped되어 있고, TokenPolicy가 특정 액션을 허용하지 않거나 규칙으로 인해 기본 확정 방식이 불가능한 경우에 편리한 접근 방식이다.
TokenPolicyCap을 사용해 spend 요청을 확정할 수 없다.
// module: sui::token
public fun confirm_with_policy_cap<T>(
token_policy_cap: &TokenPolicyCap<T>,
request: ActionRequest<T>,
ctx: &mut TxContext
): (String, u64, address, Option<address>);
JavaScript에서 클라이언트 전송 요청을 확정하는 예시는 다음과 같다:
let tx = new Transaction();
let tokenType = '0x....::my_token::MY_TOKEN';
let myTokenArg = tx.object('0x...token_object');
let receiverArg = tx.pure.address('0x...receiver');
let tokenPolicyCapArg = tx.object('0x...token_policy_cap');
let request = tx.moveCall({
target: '0x2::token::transfer',
arguments: [myTokenArg, receiverArg],
typeArguments: [tokenType],
});
// confirming the request with the TokenPolicyCap
tx.moveCall({
target: '0x2::token::confirm_with_policy_cap',
arguments: [tokenPolicyCapArg, request],
typeArguments: [tokenType],
});
// submit the transaction
// ...
액션 승인
ActionRequest는 approvals를 수집할 수 있으며, 이는 애플리케이션 또는 규칙의 witness stamp이다. 특정 모듈 또는 규칙이 액션을 승인했음을 나타내는 확정을 담는다. 이 메커니즘은 특정 요구 사항을 충족해야 액션을 허용할 수 있게 한다.
token::add_approval 함수의 서명은 다음과 같다:
// module: sui::token
public fun add_approval<T, W: drop>(
_t: W, request: &mut ActionRequest<T>, _ctx: &mut TxContext
);
Approvals는 주로 규칙에 사용되지만, 어떤 모듈에서든 확정을 담을 수 있다.
커스텀 요청 생성
누구나 ActionRequest 함수를 사용해 새로운 token::new_request를 생성할 수 있다. 이를 사용해 토큰 자체와 직접 관련되지 않은 커스텀 액션과 규칙을 생성할 수 있다.
어떤 type ActionRequest에 대해서도 T를 자유롭게 생성할 수 있기 때문에, 이를 액션의 proof로 사용할 수 없다. 그 목적은 proof가 아니라 authorization이다.
token::new_request 함수의 서명은 다음과 같다:
public fun new_request<T>(
name: vector<u8>,
amount: u64,
recipient: option<address>,
spent_balance: option<Balance<T>>,
ctx: &mut TxContext
): ActionRequest<T>;