Skip to content

Commit

Permalink
add integration test for mintTo instruction
Browse files Browse the repository at this point in the history
  • Loading branch information
ml-james committed Jun 19, 2024
1 parent 4602a3c commit 610c293
Show file tree
Hide file tree
Showing 13 changed files with 467 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,32 @@ void beforeEachTest()
}

@ParameterizedTokenTest
void shouldInitializeTokenMint(final String messageEncoding, final String tokenProgram)
void shouldCreateTokenMint(final String messageEncoding, final String tokenProgram)
{
solana.setMessageEncoding(messageEncoding);

solana.createKeyPair("tokenMintAddress");
solana.createKeyPair("mintAuthority");
solana.createKeyPair("freezeAuthority");

solana.createMintAccount("tokenMintAddress", "payer", tokenProgram);
solana.initializeMint("tokenMintAddress", "18", "mintAuthority", "freezeAuthority", "payer", tokenProgram);
solana.createMintAccount("tokenMintAddress", "18", "mintAuthority", "freezeAuthority", "payer", tokenProgram);
}

@ParameterizedTokenTest
void shouldMintToToken(final String messageEncoding, final String tokenProgram)
{
solana.setMessageEncoding(messageEncoding);

solana.createKeyPair("tokenMint");
solana.createKeyPair("mintAuthority");
solana.createKeyPair("freezeAuthority");
solana.createKeyPair("tokenAccount");
solana.createKeyPair("tokenAccountOwner");

solana.createMintAccount("tokenMint", "18", "mintAuthority", "freezeAuthority", "payer", tokenProgram);
solana.createTokenAccount("tokenAccount", "tokenAccountOwner", "tokenMint", "payer", tokenProgram);

solana.mintTo("tokenMint", "tokenAccount", "mintAuthority", "payer", "100", tokenProgram);
solana.tokenBalance("tokenAccount", "0.0000000000000001");
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.lmax.solana4j.encoding;
package com.lmax.solana4j.api;

import java.nio.ByteBuffer;

interface ByteBufferWriter
public interface ByteBufferWriter
{
void write(References references, ByteBuffer buffer);
}
6 changes: 6 additions & 0 deletions src/main/java/com/lmax/solana4j/api/References.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.lmax.solana4j.api;

public interface References
{
int indexOfAccount(PublicKey account);
}
8 changes: 0 additions & 8 deletions src/main/java/com/lmax/solana4j/encoding/References.java

This file was deleted.

2 changes: 2 additions & 0 deletions src/main/java/com/lmax/solana4j/encoding/SolanaBlockhash.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.lmax.solana4j.encoding;

import com.lmax.solana4j.api.Blockhash;
import com.lmax.solana4j.api.ByteBufferWriter;
import com.lmax.solana4j.api.References;

import java.nio.ByteBuffer;
import java.util.Arrays;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public static Slot slot(final long slot)
return new SolanaSlot(recentSlotBuffer.array());
}

public static Destination destinationAddress(final PublicKey destination, final long amount)
public static Destination destination(final PublicKey destination, final long amount)
{
return new SolanaDestination(destination, amount);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.lmax.solana4j.api.MessageVisitor;
import com.lmax.solana4j.api.MessageVisitor.InstructionView;
import com.lmax.solana4j.api.PublicKey;
import com.lmax.solana4j.api.References;
import com.lmax.solana4j.api.TransactionInstruction;

import java.nio.ByteBuffer;
Expand Down
83 changes: 75 additions & 8 deletions src/test-support/java/com/lmax/solana4j/SolanaDriver.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
import com.lmax.solana4j.api.PublicKey;
import com.lmax.solana4j.api.Slot;
import com.lmax.solana4j.client.api.AccountInfo;
import com.lmax.solana4j.client.api.Blockhash;
import com.lmax.solana4j.client.api.Commitment;
import com.lmax.solana4j.client.api.SolanaApi;
import com.lmax.solana4j.client.api.TransactionResponse;
import com.lmax.solana4j.domain.TestKeyPair;
import com.lmax.solana4j.domain.TestPublicKey;
import com.lmax.solana4j.encoding.SolanaEncoding;
import com.lmax.solana4j.programs.AddressWithBumpSeed;
import com.lmax.solana4j.transaction.LegacyTransactionFactory;
import com.lmax.solana4j.transaction.TransactionFactory;
Expand Down Expand Up @@ -95,26 +97,29 @@ public String extendAddressLookupTable(final TestPublicKey addressLookupTable,
return solanaApi.sendTransaction(transactionBlob, Commitment.FINALIZED);
}

public String initializeMint(
final TokenProgramFactory tokenProgramFactory,
final TestPublicKey mintAddress,
public String createMintAccount(
final TokenProgram tokenProgram,
final TestKeyPair account,
final int decimals,
final TestKeyPair mintAuthority,
final TestKeyPair freezeAuthority,
final TestKeyPair payer,
final TestKeyPair payer, final int accountSpan,
final List<AddressLookupTable> addressLookupTables)
{
final com.lmax.solana4j.client.api.Blockhash recentBlockhash = solanaApi.getRecentBlockHash();
final long rentExemption = solanaApi.getMinimalBalanceForRentExemption(accountSpan);

final String transactionBlob = getTransactionFactory().initializeMint(
tokenProgramFactory,
mintAddress.getSolana4jPublicKey(),
final String transactionBlob = getTransactionFactory().createMintAccount(
tokenProgram,
account.getSolana4jPublicKey(),
decimals,
mintAuthority.getSolana4jPublicKey(),
freezeAuthority.getSolana4jPublicKey(),
rentExemption,
accountSpan,
Solana.blockhash(recentBlockhash.getBytes()),
payer.getSolana4jPublicKey(),
List.of(payer, mintAuthority),
List.of(payer, account),
addressLookupTables
);

Expand Down Expand Up @@ -145,6 +150,68 @@ public String createAccount(
return solanaApi.sendTransaction(transactionBlob, Commitment.FINALIZED);
}

public String mintTo(
final TokenProgramFactory tokenProgramFactory,
final TestPublicKey tokenMintAddress,
final TestPublicKey to,
final long amount,
final TestKeyPair authority,
final TestKeyPair payer,
final List<AddressLookupTable> addressLookupTables)
{
final com.lmax.solana4j.client.api.Blockhash recentBlockhash = solanaApi.getRecentBlockHash();

final String transactionBlob = getTransactionFactory().mintTo(
tokenProgramFactory,
tokenMintAddress.getSolana4jPublicKey(),
authority.getSolana4jPublicKey(),
SolanaEncoding.destination(to.getSolana4jPublicKey(), amount),
SolanaEncoding.blockhash(recentBlockhash.getBytes()),
payer.getSolana4jPublicKey(),
List.of(payer, authority),
addressLookupTables
);

return solanaApi.sendTransaction(transactionBlob, Commitment.FINALIZED);
}

public String createTokenAccount(
final TokenProgram tokenProgram,
final TestKeyPair account,
final TestPublicKey owner,
final TestPublicKey tokenMintAddress,
final TestKeyPair payer,
final int accountSpan,
final List<AddressLookupTable> addressLookupTables)
{
final Long rentExemption = solanaApi.getMinimalBalanceForRentExemption(accountSpan);
final Blockhash blockhash = solanaApi.getRecentBlockHash();

final String transactionBlob = getTransactionFactory().initializeTokenAccount(
tokenProgram,
rentExemption,
accountSpan,
account.getSolana4jPublicKey(),
owner.getSolana4jPublicKey(),
tokenMintAddress.getSolana4jPublicKey(),
Solana.blockhash(blockhash.getBytes()),
payer.getSolana4jPublicKey(),
List.of(payer, account),
addressLookupTables);

return solanaApi.sendTransaction(transactionBlob, Commitment.FINALIZED);
}

public long getBalance(final String address, final Commitment commitment)
{
return solanaApi.getBalance(address, commitment);
}

public String getTokenBalance(final String address, final Commitment commitment)
{
return solanaApi.getTokenAccountBalance(address, commitment).getUiAmountString();
}

private TransactionFactory getTransactionFactory()
{
if (transactionFactory == null)
Expand Down
88 changes: 82 additions & 6 deletions src/test-support/java/com/lmax/solana4j/SolanaNodeDsl.java
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,11 @@ public void waitForSlot(final String... args)
new Waiter().waitFor(new IsEqualToAssertion<>(true, () -> solanaDriver.getSlot(FINALIZED) > params.valueAsLong("slot")));
}

public void initializeMint(final String... args)
public void createMintAccount(final String... args)
{
final DslParams params = DslParams.create(
args,
new RequiredArg("tokenMintAddress"),
new RequiredArg("account"),
new RequiredArg("decimals"),
new RequiredArg("mintAuthority"),
new RequiredArg("freezeAuthority"),
Expand All @@ -171,7 +171,7 @@ public void initializeMint(final String... args)
new OptionalArg("addressLookupTables").setAllowMultipleValues()
);

final TestPublicKey tokenMintAddress = testContext.getPublicKey(params.value("tokenMintAddress"));
final TestKeyPair account = testContext.getKeyPair(params.value("account"));
final int decimals = params.valueAsInt("decimals");
final TestKeyPair mintAuthority = testContext.getKeyPair(params.value("mintAuthority"));
final TestKeyPair freezeAuthority = testContext.getKeyPair(params.value("freezeAuthority"));
Expand All @@ -181,12 +181,12 @@ public void initializeMint(final String... args)
.map(testContext::getAddressLookupTable)
.toList();

final String transactionSignature = solanaDriver.initializeMint(tokenProgram.getFactory(), tokenMintAddress, decimals, mintAuthority, freezeAuthority, payer, addressLookupTables);
final String transactionSignature = solanaDriver.createMintAccount(tokenProgram, account, decimals, mintAuthority, freezeAuthority, payer, MINT_LAYOUT_SPAN, addressLookupTables);

new Waiter().waitFor(new IsNotNullAssertion<>(() -> solanaDriver.getTransactionResponse(transactionSignature, FINALIZED).getTransaction()));
}

public void createMintAccount(final String... args)
public void createAccount(final String... args)
{
final DslParams params = DslParams.create(
args,
Expand All @@ -203,8 +203,84 @@ public void createMintAccount(final String... args)
.map(testContext::getAddressLookupTable)
.toList();

final String transactionSignature = solanaDriver.createAccount(tokenProgram.getProgram(), account, payer, MINT_LAYOUT_SPAN, addressLookupTables);
final String transactionSignature = solanaDriver.createAccount(tokenProgram.getProgram(), account, payer, ACCOUNT_LAYOUT_SPAN, addressLookupTables);

new Waiter().waitFor(new IsNotNullAssertion<>(() -> solanaDriver.getTransactionResponse(transactionSignature, FINALIZED).getTransaction()));
}

public void mintTo(final String... args)
{
final DslParams params = DslParams.create(
args,
new RequiredArg("tokenMint"),
new RequiredArg("to"),
new RequiredArg("authority"),
new RequiredArg("payer"),
new RequiredArg("amount"),
new OptionalArg("tokenProgram").setAllowedValues("Token", "Token2022").setDefault("Token"),
new OptionalArg("addressLookupTables").setAllowMultipleValues()
);

final TestPublicKey tokenMint = testContext.getPublicKey(params.value("tokenMint"));
final TestKeyPair authority = testContext.getKeyPair(params.value("authority"));
final TestKeyPair payer = testContext.getKeyPair(params.value("payer"));
final TestPublicKey to = testContext.getPublicKey(params.value("to"));
final long amount = params.valueAsLong("amount");
final TokenProgram tokenProgram = TokenProgram.fromName(params.value("tokenProgram"));
final List<AddressLookupTable> addressLookupTables = params.valuesAsList("addressLookupTables").stream()
.map(testContext::getAddressLookupTable)
.toList();

final String transactionSignature = solanaDriver.mintTo(tokenProgram.getFactory(), tokenMint, to, amount, authority, payer, addressLookupTables);

new Waiter().waitFor(new IsNotNullAssertion<>(() -> solanaDriver.getTransactionResponse(transactionSignature, FINALIZED).getTransaction()));
}

public void createTokenAccount(final String... args)
{
final DslParams params = DslParams.create(
args,
new RequiredArg("account"),
new RequiredArg("owner"),
new RequiredArg("tokenMint"),
new RequiredArg("payer"),
new OptionalArg("tokenProgram").setAllowedValues("Token", "Token2022").setDefault("Token"),
new OptionalArg("addressLookupTables").setAllowMultipleValues()
);

final TestKeyPair account = testContext.getKeyPair(params.value("account"));
final TestPublicKey owner = testContext.getPublicKey(params.value("owner"));
final TestPublicKey tokenMint = testContext.getPublicKey(params.value("tokenMint"));
final TestKeyPair payer = testContext.getKeyPair(params.value("payer"));
final TokenProgram tokenProgram = TokenProgram.fromName(params.value("tokenProgram"));
final List<AddressLookupTable> addressLookupTables = params.valuesAsList("addressLookupTables").stream()
.map(testContext::getAddressLookupTable)
.toList();

final String transactionSignature = solanaDriver.createTokenAccount(
tokenProgram,
account,
owner,
tokenMint,
payer,
ACCOUNT_LAYOUT_SPAN,
addressLookupTables);

new Waiter().waitFor(new IsNotNullAssertion<>(() -> solanaDriver.getTransactionResponse(transactionSignature, FINALIZED).getTransaction()));
}

public void tokenBalance(final String... args)
{
final DslParams params = DslParams.create(
args,
new RequiredArg("address"),
new RequiredArg("amount"),
new OptionalArg("commitment").setDefault("FINALIZED").setAllowedValues(Commitment.class));

final TestPublicKey address = testContext.getPublicKey(params.value("address"));
final String amount = params.value("amount");
final Commitment commitment = params.valueAs("commitment", Commitment.class);

new Waiter().waitFor(new IsEqualToAssertion<>(amount, () -> solanaDriver.getTokenBalance(address.getPublicKeyBase58(), commitment)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,19 @@ public TransactionResponse getTransactionResponse(final String transactionSignat
{
},
"getTransaction",
// solana config set --url http://localhost:8899 on the node
transactionSignature, Map.of(
transactionSignature,
Map.of(
"commitment", commitment.name().toLowerCase(Locale.UK),
"econding", "jsonParsed",
"maxSupportedTransactionVersion", 0)
"maxSupportedTransactionVersion", 0
)
);
}

@Override
public String sendTransaction(final String transactionBlob, final Commitment commitment)
{
// there is something wrong here
return rpcClient.queryForObject(new TypeReference<RpcWrapperDTO<String>>()
return rpcClient.queryForObject(new TypeReference<>()
{
},
"sendTransaction",
Expand All @@ -59,13 +59,25 @@ public String sendTransaction(final String transactionBlob, final Commitment com
@Override
public Long getBalance(final String address, final Commitment commitment)
{
throw new UnsupportedOperationException();
return rpcClient.queryForObject(new TypeReference<RpcWrapperDTO<BalanceDTO>>()
{
},
"getBalance",
address,
Map.of("commitment", commitment.name().toLowerCase(Locale.UK))
).getValue();
}

@Override
public TokenAmount getTokenAccountBalance(final String address, final Commitment commitment)
{
throw new UnsupportedOperationException();
return rpcClient.queryForObject(new TypeReference<RpcWrapperDTO<TokenAmountDTO>>()
{
},
"getTokenAccountBalance",
address,
Map.of("commitment", commitment.name().toLowerCase(Locale.UK))
).getValue();
}

@Override
Expand All @@ -84,7 +96,9 @@ public AccountInfo getAccountInfo(final String address, final Commitment commitm
@Override
public Long getBlockHeight()
{
throw new UnsupportedOperationException();
return rpcClient.queryForObject(new TypeReference<>()
{
}, "getBlockHeight");
}

@Override
Expand Down
Loading

0 comments on commit 610c293

Please sign in to comment.