-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
JUP-setup jupiter program to swap solana tokens and added functionali…
…ty to deserialize transactions
- Loading branch information
Chintan Patel
authored and
Chintan Patel
committed
Aug 13, 2024
1 parent
a5173cb
commit 2d4f179
Showing
52 changed files
with
1,033 additions
and
420 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
package org.p2p.solanaj.core; | ||
|
||
import java.nio.ByteBuffer; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import org.bitcoinj.core.Base58; | ||
|
||
import org.p2p.solanaj.utils.Shortvec; | ||
|
||
public class LegacyMessage { | ||
private static class MessageHeader { | ||
static final int HEADER_LENGTH = 3; | ||
|
||
byte numRequiredSignatures = 0; | ||
byte numReadonlySignedAccounts = 0; | ||
byte numReadonlyUnsignedAccounts = 0; | ||
|
||
byte[] toByteArray() { | ||
return new byte[] { numRequiredSignatures, numReadonlySignedAccounts, numReadonlyUnsignedAccounts }; | ||
} | ||
} | ||
|
||
private static class CompiledInstruction { | ||
byte programIdIndex; | ||
byte[] keyIndicesCount; | ||
byte[] keyIndices; | ||
byte[] dataLength; | ||
byte[] data; | ||
|
||
int getLength() { | ||
// 1 = programIdIndex length | ||
return 1 + keyIndicesCount.length + keyIndices.length + dataLength.length + data.length; | ||
} | ||
} | ||
|
||
private static final int RECENT_BLOCK_HASH_LENGTH = 32; | ||
|
||
private String recentBlockhash; | ||
private final AccountKeysList accountKeys; | ||
private final List<TransactionInstruction> instructions; | ||
private Account feePayer; | ||
|
||
public LegacyMessage() { | ||
this.accountKeys = new AccountKeysList(); | ||
this.instructions = new ArrayList<>(); | ||
} | ||
|
||
public LegacyMessage addInstruction(TransactionInstruction instruction) { | ||
accountKeys.addAll(instruction.getKeys()); | ||
accountKeys.add(new AccountMeta(instruction.getProgramId(), false, false)); | ||
instructions.add(instruction); | ||
|
||
return this; | ||
} | ||
|
||
public void setRecentBlockHash(String recentBlockhash) { | ||
this.recentBlockhash = recentBlockhash; | ||
} | ||
|
||
public byte[] serialize() { | ||
|
||
if (recentBlockhash == null) { | ||
throw new IllegalArgumentException("recentBlockhash required"); | ||
} | ||
|
||
if (instructions.isEmpty()) { | ||
throw new IllegalArgumentException("No instructions provided"); | ||
} | ||
|
||
MessageHeader messageHeader = new MessageHeader(); | ||
|
||
List<AccountMeta> keysList = getAccountKeys(); | ||
int accountKeysSize = keysList.size(); | ||
|
||
byte[] accountAddressesLength = Shortvec.encodeLength(accountKeysSize); | ||
|
||
int compiledInstructionsLength = 0; | ||
List<CompiledInstruction> compiledInstructions = new ArrayList<>(); | ||
|
||
for (TransactionInstruction instruction : instructions) { | ||
int keysSize = instruction.getKeys().size(); | ||
|
||
byte[] keyIndices = new byte[keysSize]; | ||
for (int i = 0; i < keysSize; i++) { | ||
keyIndices[i] = (byte) findAccountIndex(keysList, instruction.getKeys().get(i).getPublicKey()); | ||
} | ||
|
||
CompiledInstruction compiledInstruction = new CompiledInstruction(); | ||
compiledInstruction.programIdIndex = (byte) findAccountIndex(keysList, instruction.getProgramId()); | ||
compiledInstruction.keyIndicesCount = Shortvec.encodeLength(keysSize); | ||
compiledInstruction.keyIndices = keyIndices; | ||
compiledInstruction.dataLength = Shortvec.encodeLength(instruction.getData().length); | ||
compiledInstruction.data = instruction.getData(); | ||
|
||
compiledInstructions.add(compiledInstruction); | ||
|
||
compiledInstructionsLength += compiledInstruction.getLength(); | ||
} | ||
|
||
byte[] instructionsLength = Shortvec.encodeLength(compiledInstructions.size()); | ||
|
||
int bufferSize = MessageHeader.HEADER_LENGTH + RECENT_BLOCK_HASH_LENGTH + accountAddressesLength.length | ||
+ (accountKeysSize * PublicKey.PUBLIC_KEY_LENGTH) + instructionsLength.length | ||
+ compiledInstructionsLength; | ||
|
||
ByteBuffer out = ByteBuffer.allocate(bufferSize); | ||
|
||
ByteBuffer accountKeysBuff = ByteBuffer.allocate(accountKeysSize * PublicKey.PUBLIC_KEY_LENGTH); | ||
for (AccountMeta accountMeta : keysList) { | ||
accountKeysBuff.put(accountMeta.getPublicKey().toByteArray()); | ||
|
||
if (accountMeta.isSigner()) { | ||
messageHeader.numRequiredSignatures += 1; | ||
if (!accountMeta.isWritable()) { | ||
messageHeader.numReadonlySignedAccounts += 1; | ||
} | ||
} else { | ||
if (!accountMeta.isWritable()) { | ||
messageHeader.numReadonlyUnsignedAccounts += 1; | ||
} | ||
} | ||
} | ||
|
||
out.put(messageHeader.toByteArray()); | ||
|
||
out.put(accountAddressesLength); | ||
out.put(accountKeysBuff.array()); | ||
|
||
out.put(Base58.decode(recentBlockhash)); | ||
|
||
out.put(instructionsLength); | ||
for (CompiledInstruction compiledInstruction : compiledInstructions) { | ||
out.put(compiledInstruction.programIdIndex); | ||
out.put(compiledInstruction.keyIndicesCount); | ||
out.put(compiledInstruction.keyIndices); | ||
out.put(compiledInstruction.dataLength); | ||
out.put(compiledInstruction.data); | ||
} | ||
|
||
return out.array(); | ||
} | ||
|
||
protected void setFeePayer(Account feePayer) { | ||
this.feePayer = feePayer; | ||
} | ||
|
||
private List<AccountMeta> getAccountKeys() { | ||
List<AccountMeta> keysList = accountKeys.getList(); | ||
int feePayerIndex = findAccountIndex(keysList, feePayer.getPublicKey()); | ||
|
||
List<AccountMeta> newList = new ArrayList<>(); | ||
AccountMeta feePayerMeta = keysList.get(feePayerIndex); | ||
newList.add(new AccountMeta(feePayerMeta.getPublicKey(), true, true)); | ||
keysList.remove(feePayerIndex); | ||
newList.addAll(keysList); | ||
|
||
return newList; | ||
} | ||
|
||
private int findAccountIndex(List<AccountMeta> accountMetaList, PublicKey key) { | ||
for (int i = 0; i < accountMetaList.size(); i++) { | ||
if (accountMetaList.get(i).getPublicKey().equals(key)) { | ||
return i; | ||
} | ||
} | ||
|
||
throw new RuntimeException("unable to find account index"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package org.p2p.solanaj.core; | ||
|
||
import java.nio.ByteBuffer; | ||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
import org.bitcoinj.core.Base58; | ||
import org.p2p.solanaj.utils.Shortvec; | ||
import org.p2p.solanaj.utils.TweetNaclFast; | ||
|
||
public class LegacyTransaction { | ||
|
||
public static final int SIGNATURE_LENGTH = 64; | ||
|
||
private final LegacyMessage legacyMessage; | ||
private final List<String> signatures; | ||
private byte[] serializedLegacyMessage; | ||
|
||
public LegacyTransaction() { | ||
this.legacyMessage = new LegacyMessage(); | ||
this.signatures = new ArrayList<>(); | ||
} | ||
|
||
public LegacyTransaction addInstruction(TransactionInstruction instruction) { | ||
legacyMessage.addInstruction(instruction); | ||
|
||
return this; | ||
} | ||
|
||
public void setRecentBlockHash(String recentBlockhash) { | ||
legacyMessage.setRecentBlockHash(recentBlockhash); | ||
} | ||
|
||
public void sign(Account signer) { | ||
sign(Collections.singletonList(signer)); | ||
} | ||
|
||
public void sign(List<Account> signers) { | ||
|
||
if (signers.isEmpty()) { | ||
throw new IllegalArgumentException("No signers"); | ||
} | ||
|
||
Account feePayer = signers.get(0); | ||
legacyMessage.setFeePayer(feePayer); | ||
|
||
serializedLegacyMessage = legacyMessage.serialize(); | ||
|
||
for (Account signer : signers) { | ||
TweetNaclFast.Signature signatureProvider = new TweetNaclFast.Signature(new byte[0], signer.getSecretKey()); | ||
byte[] signature = signatureProvider.detached(serializedLegacyMessage); | ||
|
||
signatures.add(Base58.encode(signature)); | ||
} | ||
} | ||
|
||
public byte[] serialize() { | ||
int signaturesSize = signatures.size(); | ||
byte[] signaturesLength = Shortvec.encodeLength(signaturesSize); | ||
|
||
ByteBuffer out = ByteBuffer | ||
.allocate(signaturesLength.length + signaturesSize * SIGNATURE_LENGTH + serializedLegacyMessage.length); | ||
|
||
out.put(signaturesLength); | ||
|
||
for (String signature : signatures) { | ||
byte[] rawSignature = Base58.decode(signature); | ||
out.put(rawSignature); | ||
} | ||
|
||
out.put(serializedLegacyMessage); | ||
|
||
return out.array(); | ||
} | ||
} |
Oops, something went wrong.