네트워크에 쓰기

이전 섹션에서는 계정을 가져와 Solana 네트워크에서 데이터를 읽는 방법을 배웠습니다. Solana 네트워크에 데이터를 쓰려면 트랜잭션이 필요합니다. 트랜잭션에는 하나 이상의 명령어가 포함되며, 각 명령어는 프로그램을 호출합니다.

프로그램은 각 명령어의 비즈니스 로직을 정의합니다. 트랜잭션을 전송하면 Solana 런타임이 트랜잭션의 명령어를 순서대로 실행합니다. 트랜잭션은 원자적입니다. 트랜잭션 내의 모든 명령어가 성공하거나, 전체 트랜잭션이 실패합니다.

이 섹션의 예제에서는 다음을 수행하는 방법을 보여줍니다:

  1. 계정 간 SOL 전송
  2. 새 토큰 민트 생성

SOL 전송

아래 예제는 한 계정에서 다른 계정으로 SOL을 전송합니다. 계정의 소유자로 지정된 프로그램만 계정의 데이터를 수정하거나 잔액에서 lamport를 차감할 수 있습니다. 지갑 계정은 System Program이 소유하므로, 지갑 계정 간 SOL 전송에는 System Program의 transfer 명령어를 호출하는 명령어가 필요합니다. 소스 계정도 트랜잭션에 서명해야 합니다.

Transfer SOL
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getTransferSolInstruction } from "@solana-program/system";
const client = await createClient()
.use(generatedPayer())
.use(
solanaRpc({
rpcUrl: "http://localhost:8899",
rpcSubscriptionsUrl: "ws://localhost:8900"
})
)
.use(rpcAirdrop())
.use(airdropPayer(lamports(1_000_000_000n)));
const receiver = await generateKeyPairSigner();
const transferInstruction = getTransferSolInstruction({
source: client.payer,
destination: receiver.address,
amount: lamports(10_000_000n)
});
const result = await client.sendTransaction([transferInstruction]);
console.log("Transaction Signature:", result.context.signature);
const { value: senderBalance } = await client.rpc
.getBalance(client.payer.address)
.send();
const { value: receiverBalance } = await client.rpc
.getBalance(receiver.address)
.send();
console.log("Sender Balance:", senderBalance);
console.log("Receiver Balance:", receiverBalance);
Console
Click to execute the code.

로컬 테스트 validator용 Kit 클라이언트를 생성합니다. 이 코드 스니펫은 지불자 서명자를 추가하고, 로컬 RPC 엔드포인트에 연결하고, 에어드랍을 활성화하고, 전송을 위한 테스트 SOL로 지불자에게 자금을 공급합니다.

Client setup
const client = await createClient()
.use(generatedPayer())
.use(
solanaRpc({
rpcUrl: "http://localhost:8899",
rpcSubscriptionsUrl: "ws://localhost:8900"
})
)
.use(rpcAirdrop())
.use(airdropPayer(lamports(1_000_000_000n)));

수신자를 위한 서명자를 생성합니다. 송신자는 client.payer이며, 이는 generatedPayer()에 의해 생성되고 airdropPayer()에 의해 자금이 공급되었습니다.

Receiver signer
const receiver = await generateKeyPairSigner();

getTransferSolInstruction() 헬퍼는 System Program 명령어를 생성합니다. 이 명령어는 source 서명자에서 destination 주소로 지정된 amount lamport만큼 SOL을 전송합니다.

Transfer instruction
const transferInstruction = getTransferSolInstruction({
source: client.payer,
destination: receiver.address,
amount: lamports(10_000_000n)
});

명령어 배열과 함께 client.sendTransaction()를 호출합니다. Kit 클라이언트는 명령어들을 하나의 트랜잭션으로 구성하고, 명령어에 연결된 서명자로 서명한 후, 트랜잭션을 전송하고 확인을 기다립니다.

Send transaction
const result = await client.sendTransaction([transferInstruction]);
console.log("Transaction Signature:", result.context.signature);

트랜잭션이 확인된 후, client.rpc를 사용하여 두 잔액을 모두 가져옵니다.

Fetch balances
const { value: senderBalance } = await client.rpc
.getBalance(client.payer.address)
.send();
const { value: receiverBalance } = await client.rpc
.getBalance(receiver.address)
.send();

로컬 테스트 validator용 Kit 클라이언트를 생성합니다. 이 코드 스니펫은 지불자 서명자를 추가하고, 로컬 RPC 엔드포인트에 연결하고, 에어드랍을 활성화하고, 전송을 위한 테스트 SOL로 지불자에게 자금을 공급합니다.

Client setup
const client = await createClient()
.use(generatedPayer())
.use(
solanaRpc({
rpcUrl: "http://localhost:8899",
rpcSubscriptionsUrl: "ws://localhost:8900"
})
)
.use(rpcAirdrop())
.use(airdropPayer(lamports(1_000_000_000n)));

수신자를 위한 서명자를 생성합니다. 송신자는 client.payer이며, 이는 generatedPayer()에 의해 생성되고 airdropPayer()에 의해 자금이 공급되었습니다.

Receiver signer
const receiver = await generateKeyPairSigner();

getTransferSolInstruction() 헬퍼는 System Program 명령어를 생성합니다. 이 명령어는 source 서명자에서 destination 주소로 지정된 amount lamport만큼 SOL을 전송합니다.

Transfer instruction
const transferInstruction = getTransferSolInstruction({
source: client.payer,
destination: receiver.address,
amount: lamports(10_000_000n)
});

명령어 배열과 함께 client.sendTransaction()를 호출합니다. Kit 클라이언트는 명령어들을 하나의 트랜잭션으로 구성하고, 명령어에 연결된 서명자로 서명한 후, 트랜잭션을 전송하고 확인을 기다립니다.

Send transaction
const result = await client.sendTransaction([transferInstruction]);
console.log("Transaction Signature:", result.context.signature);

트랜잭션이 확인된 후, client.rpc를 사용하여 두 잔액을 모두 가져옵니다.

Fetch balances
const { value: senderBalance } = await client.rpc
.getBalance(client.payer.address)
.send();
const { value: receiverBalance } = await client.rpc
.getBalance(receiver.address)
.send();
Transfer SOL
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getTransferSolInstruction } from "@solana-program/system";
const client = await createClient()
.use(generatedPayer())
.use(
solanaRpc({
rpcUrl: "http://localhost:8899",
rpcSubscriptionsUrl: "ws://localhost:8900"
})
)
.use(rpcAirdrop())
.use(airdropPayer(lamports(1_000_000_000n)));

토큰 생성

아래 예제는 Token Extensions Program을 사용하여 새로운 토큰 mint를 생성합니다. mint account는 소수점 자릿수, 공급량, mint 권한 및 동결 권한과 같은 토큰의 전역 설정을 정의하는 계정입니다.

mint account를 생성하려면 두 가지 명령어가 필요합니다:

  1. System Program을 호출하여 Token Extensions Program이 소유하는 새 계정을 생성합니다.
  2. Token Extensions Program을 호출하여 해당 계정을 mint로 초기화합니다.
Create mint account
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getCreateAccountInstruction } from "@solana-program/system";
import {
fetchMint,
getInitializeMintInstruction,
getMintSize,
TOKEN_2022_PROGRAM_ADDRESS
} from "@solana-program/token-2022";
const client = await createClient()
.use(generatedPayer())
.use(
solanaRpc({
rpcUrl: "http://localhost:8899",
rpcSubscriptionsUrl: "ws://localhost:8900"
})
)
.use(rpcAirdrop())
.use(airdropPayer(lamports(1_000_000_000n)));
const mint = await generateKeyPairSigner();
const space = BigInt(getMintSize());
const rent = await client.rpc.getMinimumBalanceForRentExemption(space).send();
const createAccountInstruction = getCreateAccountInstruction({
payer: client.payer,
newAccount: mint,
space,
lamports: rent,
programAddress: TOKEN_2022_PROGRAM_ADDRESS
});
const initializeMintInstruction = getInitializeMintInstruction({
mint: mint.address,
decimals: 2,
mintAuthority: client.payer.address,
freezeAuthority: client.payer.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
const result = await client.sendTransaction([
createAccountInstruction,
initializeMintInstruction
]);
console.log("Mint Address:", mint.address);
console.log("Transaction Signature:", result.context.signature);
const mintAccount = await fetchMint(client.rpc, mint.address);
console.log("Mint Account:", mintAccount);
Console
Click to execute the code.

Kit 클라이언트를 생성하고 자금을 지원한 다음, 새 mint account의 주소로 사용할 서명자를 생성합니다. 클라이언트 페이어는 계정 생성 비용을 지불하고 트랜잭션 수수료를 납부합니다.

Client and mint setup
const client = await createClient()
.use(generatedPayer())
.use(
solanaRpc({
rpcUrl: "http://localhost:8899",
rpcSubscriptionsUrl: "ws://localhost:8900"
})
)
.use(rpcAirdrop())
.use(airdropPayer(lamports(1_000_000_000n)));
const mint = await generateKeyPairSigner();

mint account 크기를 바이트 단위로 계산한 후, 해당 데이터를 계정에 저장하는 데 필요한 lamport를 계산하기 위해 RPC 요청을 보냅니다. 이 필수 잔액을 rent라고 합니다.

Mint account size and rent
const space = BigInt(getMintSize());
const rent = await client.rpc.getMinimumBalanceForRentExemption(space).send();

첫 번째 명령어는 System Program을 호출합니다. 이 명령어는 payer를 사용하여 newAccount에 자금을 지원하고, mint account space를 할당하며, rent 면제 lamports를 전송하고, Token Extensions Program에 소유권을 programAddress로 할당합니다.

Create account instruction
const createAccountInstruction = getCreateAccountInstruction({
payer: client.payer,
newAccount: mint,
space,
lamports: rent,
programAddress: TOKEN_2022_PROGRAM_ADDRESS
});

두 번째 명령어는 Token Extensions Program을 호출합니다. 이 명령어는 mint 주소를 decimals 값, mintAuthority, freezeAuthority로 초기화하고, mint account를 소유하는 tokenProgram을 지정합니다.

Initialize mint instruction
const initializeMintInstruction = getInitializeMintInstruction({
mint: mint.address,
decimals: 2,
mintAuthority: client.payer.address,
freezeAuthority: client.payer.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

두 명령어를 하나의 트랜잭션으로 전송합니다. 계정 생성 명령어는 민트 초기화 명령어보다 먼저 와야 합니다. Token Extensions Program이 계정에 민트 데이터를 기록하려면 mint account가 먼저 존재해야 하기 때문입니다.

Send transaction
const result = await client.sendTransaction([
createAccountInstruction,
initializeMintInstruction
]);

트랜잭션이 확인된 후 mint account를 가져옵니다.

Fetch mint account
const mintAccount = await fetchMint(client.rpc, mint.address);
console.log("Mint Account:", mintAccount);

Kit 클라이언트를 생성하고 자금을 지원한 다음, 새 mint account의 주소로 사용할 서명자를 생성합니다. 클라이언트 페이어는 계정 생성 비용을 지불하고 트랜잭션 수수료를 납부합니다.

Client and mint setup
const client = await createClient()
.use(generatedPayer())
.use(
solanaRpc({
rpcUrl: "http://localhost:8899",
rpcSubscriptionsUrl: "ws://localhost:8900"
})
)
.use(rpcAirdrop())
.use(airdropPayer(lamports(1_000_000_000n)));
const mint = await generateKeyPairSigner();

mint account 크기를 바이트 단위로 계산한 후, 해당 데이터를 계정에 저장하는 데 필요한 lamport를 계산하기 위해 RPC 요청을 보냅니다. 이 필수 잔액을 rent라고 합니다.

Mint account size and rent
const space = BigInt(getMintSize());
const rent = await client.rpc.getMinimumBalanceForRentExemption(space).send();

첫 번째 명령어는 System Program을 호출합니다. 이 명령어는 payer를 사용하여 newAccount에 자금을 지원하고, mint account space를 할당하며, rent 면제 lamports를 전송하고, Token Extensions Program에 소유권을 programAddress로 할당합니다.

Create account instruction
const createAccountInstruction = getCreateAccountInstruction({
payer: client.payer,
newAccount: mint,
space,
lamports: rent,
programAddress: TOKEN_2022_PROGRAM_ADDRESS
});

두 번째 명령어는 Token Extensions Program을 호출합니다. 이 명령어는 mint 주소를 decimals 값, mintAuthority, freezeAuthority로 초기화하고, mint account를 소유하는 tokenProgram을 지정합니다.

Initialize mint instruction
const initializeMintInstruction = getInitializeMintInstruction({
mint: mint.address,
decimals: 2,
mintAuthority: client.payer.address,
freezeAuthority: client.payer.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});

두 명령어를 하나의 트랜잭션으로 전송합니다. 계정 생성 명령어는 민트 초기화 명령어보다 먼저 와야 합니다. Token Extensions Program이 계정에 민트 데이터를 기록하려면 mint account가 먼저 존재해야 하기 때문입니다.

Send transaction
const result = await client.sendTransaction([
createAccountInstruction,
initializeMintInstruction
]);

트랜잭션이 확인된 후 mint account를 가져옵니다.

Fetch mint account
const mintAccount = await fetchMint(client.rpc, mint.address);
console.log("Mint Account:", mintAccount);
Create mint account
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getCreateAccountInstruction } from "@solana-program/system";
import {
fetchMint,
getInitializeMintInstruction,
getMintSize,
TOKEN_2022_PROGRAM_ADDRESS
} from "@solana-program/token-2022";
const client = await createClient()
.use(generatedPayer())
.use(
solanaRpc({
rpcUrl: "http://localhost:8899",
rpcSubscriptionsUrl: "ws://localhost:8900"
})
)
.use(rpcAirdrop())
.use(airdropPayer(lamports(1_000_000_000n)));
const mint = await generateKeyPairSigner();

Is this page helpful?

목차

페이지 편집