
플러그 앤 플레이 토큰 확장
소개
토큰 확장을 사용하면 Solana에서 프로그래밍 가능한 토큰을 쉽게 만들 수 있습니다. 개발자는 새로운 토큰 확장 프로그램을 사용해 12개가 넘는 민트 및 계정 확장을 조합할 수 있습니다. 이 튜토리얼을 완료하면 대체 가능 및 대체 불가능 토큰, 이자 발생 토큰, 동결 토큰, 절대적인 권한을 보유한 토큰(소유하지 않은 계정에서 토큰을 이동하는 권한 포함)을 생성하고 상호작용할 수 있습니다. 또한 민트 계정을 닫아 자금을 회수할 수 있습니다.
플러그 앤 플레이 토큰 확장은 대화형 Solana Playground 예제를 통해 TypeScript로 다음 토큰을 만들며 토큰 확장을 학습하는 튜토리얼입니다.
이 튜토리얼의 코드는 Solana 개발자 가이드를 기반으로 수정했습니다. 토큰 확장을 생성하는 스크립트는 추가 자료 섹션에서 확인할 수 있습니다.
토큰 확장 계정
새로운 명령을 도입한 토큰 확장은 토큰 프로그램을 기반으로 구축되었습니다. 두 프로그램으로 생성한 계정은 토큰 프로그램 명령이 끝나고 토큰 확장 명령이 시작되는 지점까지 초기 길이가 동일합니다. 계정 데이터가 익숙하지 않다면 Anchor 소개에서 계정 공간을 알아보세요. 간단히 말해 Solana에서 계정을 생성할 때는 온체인에 데이터를 저장할 공간을 명시적으로 할당해야 합니다. 이 공간을 기준으로 계정의 임대료 면제에 필요한 lamport 금액을 계산할 수 있습니다.
확장이 포함된 민트 계정을 생성하는 방식은 다음과 같습니다. 토큰 확장을 위한 공간을 할당하려면 getMintLen 함수를 사용해 확장이 포함된 민트 계정의 크기를 구합니다. NonFungibleToken.ts 예제에서는 MetadataPointer 및 MintCloseAuthority 확장 유형의 민트 길이를 구합니다.
NonFungibleToken.ts 54번째 줄:
// Size of Mint Account with extension
const mintLen = getMintLen([
ExtensionType.MetadataPointer,
ExtensionType.MintCloseAuthority,
]);메타데이터 및 메타데이터 포인터 확장을 사용하면 타사 프로토콜에 의존하지 않고 메타데이터를 저장하고 가리킬 수 있습니다. TokenMetadata은 @solana/spl-token-metadata의 인터페이스이며 updateAuthority, mint, name, symbol, uri, additionalMetadata 등의 필드를 포함합니다. 메타데이터 길이는 메타데이터 객체에 pack 함수를 사용해 구합니다.
NonFungibleToken.ts 60번째 줄:
// Metadata to store in Mint Account
const metaData: TokenMetadata = {
updateAuthority: updateAuthority,
mint: mint,
name: "Solana Soldier",
symbol: "SOLD",
uri: "https://shdw-drive.genesysgo.net/G1Tzt42SDqCV3x9vPY5X826foA8fEk8BR4bB5wARh75d/OIG2.jpg",
additionalMetadata: [["armor", null]],
};
// Size of metadata
const metadataLen = pack(metaData).length;
// Size of MetadataExtension 2 bytes for type, 2 bytes for length
const metadataExtension = TYPE_SIZE + LENGTH_SIZE;민트 계정에 필요한 최소 lamport를 구하려면 민트 길이, 메타데이터 확장, 메타데이터 길이를 더합니다.
NonFungibleToken.ts 75번째 줄:
// Minimum lamports required for Mint Account
const lamports = await connection.getMinimumBalanceForRentExemption(
mintLen + metadataExtension + metadataLen
);토큰 확장 명령
@solana/spl-token, @solana/spl-token-metadata 같은 Solana 라이브러리는 토큰 확장 프로그램에 TypeScript 지원을 추가합니다. 먼저 @solana/web3.js의 SystemProgram을 사용해 적절한 공간과 임대료 면제에 필요한 lamport를 갖춘 계정을 생성합니다.
NonFungibleToken.ts 80번째 줄:
// Instruction to invoke System Program to create new account
const createAccountInstruction = SystemProgram.createAccount({
fromPubkey: payer.publicKey, // Account that will transfer lamports to created account
newAccountPubkey: mint, // Address of the account to create
space: mintLen, // Amount of bytes to allocate to the created account
lamports, // Amount of lamports transferred to created account
programId: TOKEN_2022_PROGRAM_ID, // Program assigned as owner of created account
});다음으로 민트를 지정하는 명령을 생성합니다. 다음 명령은 initializeMint을 호출하기 전에 실행해야 합니다. 플러그 앤 플레이에서 사용하는 민트 전 명령은 다음과 같습니다.
- 메타데이터 포인터 초기화: createInitializeMetadataPointerInstruction
- 민트 종료 권한 초기화: createInitializeMintCloseAuthorityInstruction
- 양도 불가 민트 초기화: createInitializeNonTransferableMintInstruction
- 영구 위임자 초기화: createInitializePermanentDelegateInstruction
- 이자 발생 토큰 민트 초기화: createInitializeInterestBearingMintInstruction
메타데이터 계정은 initializeMint과 별개로 초기화하고 업데이트할 수 있습니다. 하지만 메타데이터 포인터는 민트 전에 초기화해야 합니다. 트랜잭션 내 명령 순서에 따라 실행 순서가 결정됩니다. 민트 계정을 생성하고 메타데이터 포인터를 초기화한 다음, 민트의 공개 키로 민트 종료 권한을 초기화합니다. 이어서 민트 및 메타데이터 계정을 초기화하고 추가 메타데이터를 업데이트합니다.
NonFungibleToken.ts 135번째 줄:
transaction = new Transaction().add(
createAccountInstruction,
initializeMetadataPointerInstruction,
initializeMintCloseAuthorityInstruction,
initializeMintInstruction,
initializeMetadataInstruction,
updateFieldInstruction
);nonFungibleToken.ts, soulboundToken.ts, interestBearingToken.ts, delegateToken.ts 파일은 사용되는 확장과 명령만 다를 뿐 동일한 토큰 생성 구조를 따릅니다.
먼저 필요한 Solana 라이브러리에서 모든 필수 함수를 가져오고, 지불자를 정의한 다음 민트 주소를 생성합니다. 이어서 원하는 토큰 확장을 적용한 민트 주소에 필요한 공간과 lamport를 구합니다. @solana/spl-token 및 @solana/spl-token-metadata 라이브러리로 명령을 생성해 트랜잭션에 추가하고, 트랜잭션을 네트워크로 전송한 후 결과를 검증합니다.
전송 및 소각 같은 토큰 작업은 여러 토큰 확장에서 사용할 수 있습니다. 메타데이터 확장이 적용된 토큰은 각각 createUpdateFieldInstruction 및 createRemoveKeyInstruction 명령을 사용해 메타데이터를 업데이트하거나 제거할 수 있습니다.
플러그 앤 플레이
Solana Playground의 클라이언트에는 토큰 확장과 상호작용하는 데 필요한 함수가 포함되어 있습니다. 예를 들어 소울바운드 토큰은 양도 불가 확장과 메타데이터 확장을 사용해 소울바운드 NFT를 생성합니다. 토큰을 생성하고 상호작용하는 함수는 같은 파일에 있으며 가져와 사용할 수 있습니다. 단, Solana Playground에서는 가져오는 대신 코드를 복사해 붙여 넣어야 합니다.
quest.ts 파일에서 Solana 병사 퀘스트를 진행할 수 있습니다. 또는 토큰 확장이 포함된 각 파일을 실행해 개별 기능을 확인할 수 있습니다. 퀘스트를 실행하려면 Playground Wallet에 Devnet SOL이 필요합니다. Solana Devnet Faucet에서도 Devnet SOL을 에어드롭받을 수 있습니다.
퀘스트는 Solana 병사를 생성하면서 시작합니다. 이 NFT에서 지불자(pg.wallet.keypair)는 민트 종료 권한을 가지며, 민트 계정을 닫고 SOL을 회수할 수 있습니다. 이 메커니즘은 애플리케이션에서 더 이상 활성 상태가 아닌 계정의 SOL을 반환할 때 유용합니다.
Solana 병사를 생성한 후 민트 주소를 사용해 NFT의 메타데이터를 업데이트합니다. 병사의 방어구를 iron으로 업데이트해 보겠습니다. getMetadata, updateMetadata, removeMetadata 함수는 NonFungibleToken.ts 파일의 167번째 줄부터 확인할 수 있습니다. 이 함수들은 메타데이터 확장을 사용하는 민트 계정에서 호출할 수 있습니다. 편의를 위해 메타데이터 함수는 NonFungibleToken.ts 파일에만 포함됩니다.
다음은 레벨을 올릴 차례입니다. 이자 발생 토큰은 Solana 병사의 레벨을 나타냅니다. InterestBearingToken.ts에서 createInterestBearingToken을 가져오고 이 명령을 사용해 토큰을 생성합니다. 계정의 이자는 InterestBearingToken.ts의 43번째 줄에 설정된 비율에 따라 증가합니다. amountToUiAmount 함수를 사용하면 누적 이자가 반영된 토큰 수량을 확인할 수 있습니다. 이자는 시간에 따라 누적되며, amountToUiAmount을 호출해 Solana 병사의 레벨을 확인할 수 있습니다.
병사의 레벨이 오르기 시작하면 임무를 받아야 합니다. 임무는 소울바운드 토큰으로 표시됩니다. 병사는 이를 전송할 수 없으며(전송 함수를 호출해 오류를 포착해 보세요), 임무를 없애는 유일한 방법은 토큰을 소각하는 것입니다. 임무를 포기하지 말고 내용을 확인해 보겠습니다. 힌트: 메타데이터를 확인하세요!
임무를 읽으면 플러그 앤 플레이 튜토리얼이 군대를 토큰 주소로 배치합니다. 토큰이 배치된 후 Solana 병사는 군대를 지불자에게 다시 소환할 수 있어야 합니다. 토큰 확장은 위임 권한을 도입해 이를 가능하게 합니다. 위임 권한이 있으면 토큰 소유자와 관계없이 토큰을 전송하고 소각할 수 있습니다. 접근 가능한 키페어를 영구 위임자로 설정하세요. 토큰을 소각하고 전송하려면 이 키페어의 서명이 필요합니다.
위임 토큰은 Solana 군대를 나타냅니다. DelegateToken.ts의 33번째 줄에 있는 createDelegateTokens으로 적의 토큰 계정에 위임 토큰을 생성합니다. 토큰이 민팅되면 Solana 군대와 적이 가상의 전투를 벌입니다. 전투가 끝나면 DelegateTokens.ts의 176번째 줄에 있는 transferDelegateTokens 함수를 사용해 적의 계정에서 병사들을 소환합니다.
적의 주소에서 모든 병사가 소환되지는 않았습니다. 이들은 전사했다고 가정하겠습니다. @solana/spl-token의 burn 함수를 사용해 적의 토큰 계정(sourceTokenAccount)에 남은 토큰을 소각합니다.
전투에서 승리하면서 Solana 병사의 퀘스트가 끝납니다. @solana/spl-token의 closeAccount 함수를 사용해 계정을 닫고 임대료를 반환했습니다. 이 글에서 다루지 않은 토큰 확장에는 기밀 전송, 전송 수수료, 전송 훅이 있습니다. 전송 훅과 양도 불가 토큰 같은 일부 예외를 제외하면 거의 모든 토큰 확장을 자유롭게 조합할 수 있습니다. 이 튜토리얼에서 다룬 토큰 확장의 참조용 Solana Playground는 추가 자료에 링크되어 있습니다.
결론
CryptoZombies에서 영감을 받은 이 플러그 앤 플레이 튜토리얼에서는 여러 확장을 조합해 널리 사용되는 토큰 확장을 만드는 기본 과정을 다뤘습니다. 실습형 게임 경험을 통해 토큰 확장의 조합 가능성을 보여줍니다. 예제를 그대로 플러그 앤 플레이 방식으로 사용하거나 자체 토큰을 개발할 때 가이드로 활용할 수 있습니다. 계정 크기 계산부터 명령 순서 지정까지, 예제는 토큰 확장이 적용된 계정을 생성하는 간소화된 절차를 제공합니다. 게임형 학습 경험이 유익했다면 Discord에 의견을 남기거나 X에서 @helius를 태그해 주세요.
추가 자료
관련 아티클
Helius 구독하기
최신 Solana 개발 소식을 확인하고 새 게시물 알림을 받아보세요


