https://github.com/glamsystems/ix-mapper-java
Java SDK for mapping Solana instructions to GLAM program instructions.
https://github.com/glamsystems/ix-mapper-java
glam solana
Last synced: 18 days ago
JSON representation
Java SDK for mapping Solana instructions to GLAM program instructions.
- Host: GitHub
- URL: https://github.com/glamsystems/ix-mapper-java
- Owner: glamsystems
- License: apache-2.0
- Created: 2025-02-25T14:49:20.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2026-05-31T01:11:39.000Z (18 days ago)
- Last Synced: 2026-05-31T02:28:20.327Z (18 days ago)
- Topics: glam, solana
- Language: Java
- Homepage:
- Size: 349 KB
- Stars: 0
- Watchers: 4
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# ixProxy [](https://github.com/glamsystems/ix-proxy/actions/workflows/build.yml) [](https://github.com/glamsystems/ix-proxy/actions/workflows/publish.yml)
Facilitates the re-mapping of instructions from one program to another proxy program. The primary use case is to add
additional safety checks in the proxy program before and after forwarding the request to the original program.
## [Transaction Mapper](https://github.com/glamsystems/ix-proxy/blob/main/ix-proxy/src/main/java/systems/glam/ix/proxy/TransactionMapper.java)
The transaction mapper can be used to map a list of instructions or entire transactions.
### Example Construction
A dynamic account factory is needed from the user to provide the functions for wiring runtime accounts.
This example uses a simple version that could be used for the GLAM proxy program.
```java
record GlamVaultAccounts(AccountMeta readGlamState,
AccountMeta writeGlamState,
AccountMeta readGlamVault,
AccountMeta writeGlamVault) {
static GlamVaultAccounts createAccounts(final PublicKey stateAccount, final PublicKey vaultAccount) {
return new GlamVaultAccounts(
AccountMeta.createRead(stateAccount),
AccountMeta.createWrite(stateAccount),
AccountMeta.createRead(vaultAccount),
AccountMeta.createWrite(vaultAccount)
);
}
}
Function> dynamicAccountFactory = accountConfig -> {
final int index = accountConfig.index();
final boolean w = accountConfig.writable();
return switch (accountConfig.name()) {
case "glam_state" -> (mappedAccounts, _, _, vaultAccounts) -> mappedAccounts[index] = w
? vaultAccounts.writeGlamState() : vaultAccounts.readGlamState();
case "glam_vault" -> (mappedAccounts, _, _, vaultAccounts) -> mappedAccounts[index] = w
? vaultAccounts.writeGlamVault() : vaultAccounts.readGlamVault();
case "glam_signer" -> accountConfig.createFeePayerAccount();
case "cpi_program" -> accountConfig.createReadCpiProgram();
default -> throw new IllegalStateException("Unknown dynamic account type: " + accountConfig.name());
};
```
The following iterates over each mapping configuration file in a given directory.
Constructs the corresponding program proxy for each and puts them in a map with the key being the source CPI program.
Then finally the TransactionMapper is constructed.
```java
// Used to de-duplicate AccountMeta objects.
var accountMetaCache = new HashMap(256);
var indexedAccountMetaCache = new HashMap(256);
var proxyProgram = PublicKey.fromBase58Encoded("");
var invokedProxyProgram = AccountMeta.createInvoked(proxyProgram);
Function> dynamicAccountFactory = null; // See example above.
var programKeyToProgramProxyMap = new HashMap>();
var mappingFileDirectory = Path.of("path/to/mapping/config/files");
try (final var paths = Files.walk(mappingFileDirectory, 1)) {
paths
.filter(Files::isRegularFile)
.filter(Files::isReadable)
.filter(f -> f.getFileName().toString().endsWith(".json"))
.forEach(mappingFile -> ProgramMapConfig.createProxies(
mappingFile,
invokedProxyProgram,
programKeyToProgramProxyMap,
dynamicAccountFactory,
accountMetaCache,
indexedAccountMetaCache
));
var txMapper = TransactionMapper.createMapper(invokedProxyProgram, programProxies);
}
```
### Example Usage
```java
// Given some instructions or a transaction from any source.
var sourceInstructions = List.of();
var feePayer = AccountMeta.createFeePayer(PublicKey.fromBase58Encoded(""));
A runtimeAccounts = null; // See example above.
Instruction[] mappedInstructions = txMapper.mapInstructions(
feePayer,
runtimeAccounts,
sourceInstructions
);
```
## Program Mapping Configuration Files
Mapping files define the necessary information for translating a source program instruction that will be called via CPI
from the destination proxy program. More example configurations can be found in the [glam-sdk repository](https://github.com/glamsystems/glam-sdk/tree/main/remapping)
### Example Configuration
```json
{
"program_id": "dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH",
"instructions": [
{
"src_ix_name": "cancel_orders",
"src_discriminator": [
238,
225,
95,
158,
227,
103,
8,
194
],
"dst_ix_name": "drift_cancel_orders",
"dst_discriminator": [
98,
107,
48,
79,
97,
60,
99,
58
],
"dynamic_accounts": [
{
"name": "glam_state",
"index": 0,
"writable": false,
"signer": false
},
{
"name": "glam_vault",
"index": 1,
"writable": false,
"signer": false
},
{
"name": "glam_signer",
"index": 2,
"writable": true,
"signer": true
},
{
"name": "cpi_program",
"index": 3,
"writable": false,
"signer": false
}
],
"static_accounts": [],
"index_map": [
4,
5,
-1
]
}
]
}
```
### **src_discriminator**
The discriminator of the original instruction.
### **dst_discriminator**
The discriminator of the proxy instruction.
### **dynamic_accounts**
Account Meta information for accounts which can differ at runtime.
### **static_accounts**
Account Meta information for accounts which are always the same given a Solana cluster such as mainnet.
### **index_map**
Defines the parameter index for the destination instruction. If the account has been removed or replaced use a negative
number.
## Build & Tests
Mapping configuration files from the [glam-sdk repository](https://github.com/glamsystems/glam-sdk/tree/main/remapping)
are needed to run the tests. Run [./downloadMappings.sh](downloadMappings.sh) to pull only those files into this project.
### Sync Re-mapping JSON Files
```shell
./syncMappings.sh
```