Build token migration program
Change-Id: I78b10931fb09f5bca457c1fb36095fdbcea9e65f
This commit is contained in:
parent
c116b3c813
commit
88933d13e2
|
@ -59,6 +59,9 @@ spec:
|
||||||
- --bpf-program
|
- --bpf-program
|
||||||
- P2WH424242424242424242424242424242424242424
|
- P2WH424242424242424242424242424242424242424
|
||||||
- /opt/solana/deps/pyth2wormhole.so
|
- /opt/solana/deps/pyth2wormhole.so
|
||||||
|
- --bpf-program
|
||||||
|
- Ex9bCdVMSfx7EzB3pgSi2R4UHwJAXvTw18rBQm5YQ8gK
|
||||||
|
- /opt/solana/deps/wormhole_migration.so
|
||||||
- --log
|
- --log
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 8001
|
- containerPort: 8001
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
| Bridge Core | SOL | Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o | |
|
| Bridge Core | SOL | Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o | |
|
||||||
| Token Bridge | SOL | B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE | |
|
| Token Bridge | SOL | B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE | |
|
||||||
| NFT Bridge | SOL | NFTWqJR8YnRVqPDvTJrYuLrQDitTG5AScqbeghi4zSA | |
|
| NFT Bridge | SOL | NFTWqJR8YnRVqPDvTJrYuLrQDitTG5AScqbeghi4zSA | |
|
||||||
|
| Migration Contract | SOL | Ex9bCdVMSfx7EzB3pgSi2R4UHwJAXvTw18rBQm5YQ8gK | |
|
||||||
| Test Wallet | Terra | terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v | Mnemonic: `notice oak worry limit wrap speak medal online prefer cluster roof addict wrist behave treat actual wasp year salad speed social layer crew genius` |
|
| Test Wallet | Terra | terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v | Mnemonic: `notice oak worry limit wrap speak medal online prefer cluster roof addict wrist behave treat actual wasp year salad speed social layer crew genius` |
|
||||||
| Example Token | Terra | terra13nkgqrfymug724h8pprpexqj9h629sa3ncw7sh | Tokens minted to Test Wallet |
|
| Example Token | Terra | terra13nkgqrfymug724h8pprpexqj9h629sa3ncw7sh | Tokens minted to Test Wallet |
|
||||||
| Bridge Core | Terra | terra18eezxhys9jwku67cm4w84xhnzt4xjj77w2qt62 | |
|
| Bridge Core | Terra | terra18eezxhys9jwku67cm4w84xhnzt4xjj77w2qt62 | |
|
||||||
|
|
|
@ -48,13 +48,16 @@ RUN --mount=type=cache,target=bridge/target \
|
||||||
--mount=type=cache,target=modules/token_bridge/target \
|
--mount=type=cache,target=modules/token_bridge/target \
|
||||||
--mount=type=cache,target=modules/nft_bridge/target \
|
--mount=type=cache,target=modules/nft_bridge/target \
|
||||||
--mount=type=cache,target=pyth2wormhole/target \
|
--mount=type=cache,target=pyth2wormhole/target \
|
||||||
|
--mount=type=cache,target=migration/target \
|
||||||
cargo build-bpf --manifest-path "bridge/program/Cargo.toml" && \
|
cargo build-bpf --manifest-path "bridge/program/Cargo.toml" && \
|
||||||
cargo build-bpf --manifest-path "bridge/cpi_poster/Cargo.toml" && \
|
cargo build-bpf --manifest-path "bridge/cpi_poster/Cargo.toml" && \
|
||||||
cargo build-bpf --manifest-path "modules/token_bridge/program/Cargo.toml" && \
|
cargo build-bpf --manifest-path "modules/token_bridge/program/Cargo.toml" && \
|
||||||
cargo build-bpf --manifest-path "pyth2wormhole/program/Cargo.toml" && \
|
cargo build-bpf --manifest-path "pyth2wormhole/program/Cargo.toml" && \
|
||||||
cargo build-bpf --manifest-path "modules/nft_bridge/program/Cargo.toml" && \
|
cargo build-bpf --manifest-path "modules/nft_bridge/program/Cargo.toml" && \
|
||||||
|
cargo build-bpf --manifest-path "migration/Cargo.toml" && \
|
||||||
cp bridge/target/deploy/bridge.so /opt/solana/deps/bridge.so && \
|
cp bridge/target/deploy/bridge.so /opt/solana/deps/bridge.so && \
|
||||||
cp bridge/target/deploy/cpi_poster.so /opt/solana/deps/cpi_poster.so && \
|
cp bridge/target/deploy/cpi_poster.so /opt/solana/deps/cpi_poster.so && \
|
||||||
|
cp migration/target/deploy/wormhole_migration.so /opt/solana/deps/wormhole_migration.so && \
|
||||||
cp modules/token_bridge/target/deploy/token_bridge.so /opt/solana/deps/token_bridge.so && \
|
cp modules/token_bridge/target/deploy/token_bridge.so /opt/solana/deps/token_bridge.so && \
|
||||||
cp modules/nft_bridge/target/deploy/nft_bridge.so /opt/solana/deps/nft_bridge.so && \
|
cp modules/nft_bridge/target/deploy/nft_bridge.so /opt/solana/deps/nft_bridge.so && \
|
||||||
cp modules/token_bridge/token-metadata/spl_token_metadata.so /opt/solana/deps/spl_token_metadata.so && \
|
cp modules/token_bridge/token-metadata/spl_token_metadata.so /opt/solana/deps/spl_token_metadata.so && \
|
||||||
|
|
|
@ -16,6 +16,7 @@ ENV BRIDGE_ADDRESS="Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o"
|
||||||
COPY bridge bridge
|
COPY bridge bridge
|
||||||
COPY modules modules
|
COPY modules modules
|
||||||
COPY solitaire solitaire
|
COPY solitaire solitaire
|
||||||
|
COPY migration migration
|
||||||
|
|
||||||
# Compile Wormhole
|
# Compile Wormhole
|
||||||
RUN --mount=type=cache,target=/root/.cache \
|
RUN --mount=type=cache,target=/root/.cache \
|
||||||
|
@ -35,6 +36,11 @@ RUN --mount=type=cache,target=/root/.cache \
|
||||||
--mount=type=cache,target=modules/token_bridge/target \
|
--mount=type=cache,target=modules/token_bridge/target \
|
||||||
cd modules/token_bridge/program && /usr/local/cargo/bin/wasm-pack build --target nodejs -d nodejs -- --features wasm
|
cd modules/token_bridge/program && /usr/local/cargo/bin/wasm-pack build --target nodejs -d nodejs -- --features wasm
|
||||||
|
|
||||||
|
# Compile Migration
|
||||||
|
RUN --mount=type=cache,target=/root/.cache \
|
||||||
|
--mount=type=cache,target=migration/target \
|
||||||
|
cd migration && /usr/local/cargo/bin/wasm-pack build --target bundler -d bundler -- --features wasm
|
||||||
|
|
||||||
# Compile NFT Bridge
|
# Compile NFT Bridge
|
||||||
RUN --mount=type=cache,target=/root/.cache \
|
RUN --mount=type=cache,target=/root/.cache \
|
||||||
--mount=type=cache,target=modules/nft_bridge/target \
|
--mount=type=cache,target=modules/nft_bridge/target \
|
||||||
|
@ -48,6 +54,7 @@ FROM scratch AS export
|
||||||
|
|
||||||
COPY --from=build /usr/src/bridge/bridge/program/bundler sdk/js/src/solana/core
|
COPY --from=build /usr/src/bridge/bridge/program/bundler sdk/js/src/solana/core
|
||||||
COPY --from=build /usr/src/bridge/modules/token_bridge/program/bundler sdk/js/src/solana/token
|
COPY --from=build /usr/src/bridge/modules/token_bridge/program/bundler sdk/js/src/solana/token
|
||||||
|
COPY --from=build /usr/src/bridge/migration/bundler sdk/js/src/solana/migration
|
||||||
COPY --from=build /usr/src/bridge/modules/nft_bridge/program/bundler sdk/js/src/solana/nft
|
COPY --from=build /usr/src/bridge/modules/nft_bridge/program/bundler sdk/js/src/solana/nft
|
||||||
|
|
||||||
COPY --from=build /usr/src/bridge/bridge/program/nodejs clients/solana/pkg
|
COPY --from=build /usr/src/bridge/bridge/program/nodejs clients/solana/pkg
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
[package]
|
||||||
|
name = "wormhole-migration"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Created with Rocksalt"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib", "lib"]
|
||||||
|
name = "wormhole_migration"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
no-entrypoint = ["solitaire/no-entrypoint", "rand"]
|
||||||
|
trace = ["solitaire/trace"]
|
||||||
|
wasm = ["no-entrypoint"]
|
||||||
|
client = ["solitaire-client", "solitaire/client", "no-entrypoint"]
|
||||||
|
cpi = ["no-entrypoint"]
|
||||||
|
default = []
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
borsh = "0.8.1"
|
||||||
|
byteorder = "1.4.3"
|
||||||
|
rocksalt = { path = "../solitaire/rocksalt" }
|
||||||
|
solitaire = { path = "../solitaire/program" }
|
||||||
|
sha3 = "0.9.1"
|
||||||
|
solana-program = "*"
|
||||||
|
spl-token = { version = "=3.1.0", features = ["no-entrypoint"] }
|
||||||
|
solitaire-client = { path = "../solitaire/client", optional = true }
|
||||||
|
wasm-bindgen = { version = "0.2.74", features = ["serde-serialize"] }
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
rand = { version = "0.7.3", optional = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
hex = "*"
|
||||||
|
hex-literal = "0.3.1"
|
||||||
|
libsecp256k1 = { version = "0.3.5", features = [] }
|
||||||
|
solana-client = "1.7.0"
|
||||||
|
solana-sdk = "=1.7.0"
|
||||||
|
spl-token = { version = "=3.1.0", features = ["no-entrypoint"] }
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
memmap2 = { path = "../bridge/memmap2-rs" }
|
|
@ -0,0 +1,11 @@
|
||||||
|
# Merge similar crates together to avoid multiple use statements.
|
||||||
|
imports_granularity = "Crate"
|
||||||
|
|
||||||
|
# Consistency in formatting makes tool based searching/editing better.
|
||||||
|
empty_item_single_line = false
|
||||||
|
|
||||||
|
# Easier editing when arbitrary mixed use statements do not collapse.
|
||||||
|
imports_layout = "Vertical"
|
||||||
|
|
||||||
|
# Default rustfmt formatting of match arms with branches is awful.
|
||||||
|
match_arm_leading_pipes = "Preserve"
|
|
@ -0,0 +1,84 @@
|
||||||
|
use crate::types::{
|
||||||
|
PoolData,
|
||||||
|
SplAccount,
|
||||||
|
SplMint,
|
||||||
|
};
|
||||||
|
use solana_program::pubkey::Pubkey;
|
||||||
|
use solitaire::{
|
||||||
|
processors::seeded::Seeded,
|
||||||
|
AccountState,
|
||||||
|
Data,
|
||||||
|
Derive,
|
||||||
|
Info,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub type ShareMint<'a, const STATE: AccountState> = Data<'a, SplMint, { STATE }>;
|
||||||
|
|
||||||
|
pub struct ShareMintDerivationData {
|
||||||
|
pub pool: Pubkey,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b, const STATE: AccountState> Seeded<&ShareMintDerivationData> for ShareMint<'b, { STATE }> {
|
||||||
|
fn seeds(accs: &ShareMintDerivationData) -> Vec<Vec<u8>> {
|
||||||
|
vec![
|
||||||
|
String::from("share_mint").as_bytes().to_vec(),
|
||||||
|
accs.pool.to_bytes().to_vec(),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type FromCustodyTokenAccount<'a, const STATE: AccountState> = Data<'a, SplAccount, { STATE }>;
|
||||||
|
|
||||||
|
pub struct FromCustodyTokenAccountDerivationData {
|
||||||
|
pub pool: Pubkey,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b, const STATE: AccountState> Seeded<&FromCustodyTokenAccountDerivationData>
|
||||||
|
for FromCustodyTokenAccount<'b, { STATE }>
|
||||||
|
{
|
||||||
|
fn seeds(accs: &FromCustodyTokenAccountDerivationData) -> Vec<Vec<u8>> {
|
||||||
|
vec![
|
||||||
|
String::from("from_custody").as_bytes().to_vec(),
|
||||||
|
accs.pool.to_bytes().to_vec(),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type ToCustodyTokenAccount<'a, const STATE: AccountState> = Data<'a, SplAccount, { STATE }>;
|
||||||
|
|
||||||
|
pub struct ToCustodyTokenAccountDerivationData {
|
||||||
|
pub pool: Pubkey,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b, const STATE: AccountState> Seeded<&ToCustodyTokenAccountDerivationData>
|
||||||
|
for ToCustodyTokenAccount<'b, { STATE }>
|
||||||
|
{
|
||||||
|
fn seeds(accs: &ToCustodyTokenAccountDerivationData) -> Vec<Vec<u8>> {
|
||||||
|
vec![
|
||||||
|
String::from("to_custody").as_bytes().to_vec(),
|
||||||
|
accs.pool.to_bytes().to_vec(),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type MigrationPool<'a, const STATE: AccountState> = Data<'a, PoolData, { STATE }>;
|
||||||
|
|
||||||
|
pub struct MigrationPoolDerivationData {
|
||||||
|
pub from: Pubkey,
|
||||||
|
pub to: Pubkey,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'b, const STATE: AccountState> Seeded<&MigrationPoolDerivationData>
|
||||||
|
for MigrationPool<'b, { STATE }>
|
||||||
|
{
|
||||||
|
fn seeds(accs: &MigrationPoolDerivationData) -> Vec<Vec<u8>> {
|
||||||
|
vec![
|
||||||
|
String::from("pool").as_bytes().to_vec(),
|
||||||
|
accs.from.to_bytes().to_vec(),
|
||||||
|
accs.to.to_bytes().to_vec(),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type CustodySigner<'a> = Derive<Info<'a>, "custody_signer">;
|
||||||
|
pub type AuthoritySigner<'a> = Derive<Info<'a>, "authority_signer">;
|
|
@ -0,0 +1,4 @@
|
||||||
|
pub mod add_liquidity;
|
||||||
|
pub mod claim_shares;
|
||||||
|
pub mod create_pool;
|
||||||
|
pub mod migrate_tokens;
|
|
@ -0,0 +1,112 @@
|
||||||
|
use crate::{
|
||||||
|
accounts::{
|
||||||
|
AuthoritySigner,
|
||||||
|
CustodySigner,
|
||||||
|
MigrationPool,
|
||||||
|
ShareMint,
|
||||||
|
ShareMintDerivationData,
|
||||||
|
ToCustodyTokenAccount,
|
||||||
|
ToCustodyTokenAccountDerivationData,
|
||||||
|
},
|
||||||
|
types::{
|
||||||
|
SplAccount,
|
||||||
|
SplMint,
|
||||||
|
},
|
||||||
|
MigrationError::WrongMint,
|
||||||
|
};
|
||||||
|
use borsh::{
|
||||||
|
BorshDeserialize,
|
||||||
|
BorshSerialize,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::accounts::MigrationPoolDerivationData;
|
||||||
|
use solitaire::*;
|
||||||
|
|
||||||
|
#[derive(FromAccounts)]
|
||||||
|
pub struct AddLiquidity<'b> {
|
||||||
|
pub pool: Mut<MigrationPool<'b, { AccountState::Initialized }>>,
|
||||||
|
pub from_mint: Data<'b, SplMint, { AccountState::Initialized }>,
|
||||||
|
pub to_mint: Data<'b, SplMint, { AccountState::Initialized }>,
|
||||||
|
pub to_token_custody: Mut<ToCustodyTokenAccount<'b, { AccountState::Initialized }>>,
|
||||||
|
pub share_mint: Mut<ShareMint<'b, { AccountState::Initialized }>>,
|
||||||
|
|
||||||
|
pub to_lp_acc: Mut<Data<'b, SplAccount, { AccountState::Initialized }>>,
|
||||||
|
pub lp_share_acc: Mut<Data<'b, SplAccount, { AccountState::Initialized }>>,
|
||||||
|
pub custody_signer: CustodySigner<'b>,
|
||||||
|
pub authority_signer: AuthoritySigner<'b>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BorshDeserialize, BorshSerialize, Default)]
|
||||||
|
pub struct AddLiquidityData {
|
||||||
|
pub amount: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_liquidity(
|
||||||
|
ctx: &ExecutionContext,
|
||||||
|
accs: &mut AddLiquidity,
|
||||||
|
data: AddLiquidityData,
|
||||||
|
) -> Result<()> {
|
||||||
|
if *accs.from_mint.info().key != accs.pool.from {
|
||||||
|
return Err(WrongMint.into());
|
||||||
|
}
|
||||||
|
if *accs.to_mint.info().key != accs.pool.to {
|
||||||
|
return Err(WrongMint.into());
|
||||||
|
}
|
||||||
|
if accs.lp_share_acc.mint != *accs.share_mint.info().key {
|
||||||
|
return Err(WrongMint.into());
|
||||||
|
}
|
||||||
|
accs.to_token_custody.verify_derivation(
|
||||||
|
ctx.program_id,
|
||||||
|
&ToCustodyTokenAccountDerivationData {
|
||||||
|
pool: *accs.pool.info().key,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
accs.share_mint.verify_derivation(
|
||||||
|
ctx.program_id,
|
||||||
|
&ShareMintDerivationData {
|
||||||
|
pool: *accs.pool.info().key,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
accs.pool.verify_derivation(
|
||||||
|
ctx.program_id,
|
||||||
|
&MigrationPoolDerivationData {
|
||||||
|
from: accs.pool.from,
|
||||||
|
to: accs.pool.to,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Transfer out-tokens in
|
||||||
|
let transfer_ix = spl_token::instruction::transfer(
|
||||||
|
&spl_token::id(),
|
||||||
|
accs.to_lp_acc.info().key,
|
||||||
|
accs.to_token_custody.info().key,
|
||||||
|
accs.authority_signer.key,
|
||||||
|
&[],
|
||||||
|
data.amount,
|
||||||
|
)?;
|
||||||
|
invoke_seeded(&transfer_ix, ctx, &accs.authority_signer, None)?;
|
||||||
|
|
||||||
|
// The share amount should be equal to the amount of from tokens an lp would be getting
|
||||||
|
let share_amount = if accs.from_mint.decimals > accs.to_mint.decimals {
|
||||||
|
data.amount
|
||||||
|
.checked_mul(10u64.pow((accs.from_mint.decimals - accs.to_mint.decimals) as u32))
|
||||||
|
.unwrap()
|
||||||
|
} else {
|
||||||
|
data.amount
|
||||||
|
.checked_div(10u64.pow((accs.to_mint.decimals - accs.from_mint.decimals) as u32))
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mint LP shares
|
||||||
|
let mint_ix = spl_token::instruction::mint_to(
|
||||||
|
&spl_token::id(),
|
||||||
|
accs.from_mint.info().key,
|
||||||
|
accs.lp_share_acc.info().key,
|
||||||
|
accs.custody_signer.key,
|
||||||
|
&[],
|
||||||
|
share_amount,
|
||||||
|
)?;
|
||||||
|
invoke_seeded(&mint_ix, ctx, &accs.custody_signer, None)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
use crate::{
|
||||||
|
accounts::{
|
||||||
|
AuthoritySigner,
|
||||||
|
CustodySigner,
|
||||||
|
FromCustodyTokenAccountDerivationData,
|
||||||
|
MigrationPool,
|
||||||
|
ShareMint,
|
||||||
|
ShareMintDerivationData,
|
||||||
|
ToCustodyTokenAccount,
|
||||||
|
},
|
||||||
|
types::{
|
||||||
|
SplAccount,
|
||||||
|
SplMint,
|
||||||
|
},
|
||||||
|
MigrationError::WrongMint,
|
||||||
|
};
|
||||||
|
use borsh::{
|
||||||
|
BorshDeserialize,
|
||||||
|
BorshSerialize,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::accounts::MigrationPoolDerivationData;
|
||||||
|
use solitaire::{
|
||||||
|
processors::seeded::{
|
||||||
|
invoke_seeded,
|
||||||
|
Seeded,
|
||||||
|
},
|
||||||
|
*,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(FromAccounts)]
|
||||||
|
pub struct ClaimShares<'b> {
|
||||||
|
pub pool: Mut<MigrationPool<'b, { AccountState::Initialized }>>,
|
||||||
|
pub to_mint: Data<'b, SplMint, { AccountState::Initialized }>,
|
||||||
|
pub from_token_custody: Mut<ToCustodyTokenAccount<'b, { AccountState::Initialized }>>,
|
||||||
|
pub share_mint: Mut<ShareMint<'b, { AccountState::Initialized }>>,
|
||||||
|
|
||||||
|
pub from_lp_acc: Mut<Data<'b, SplAccount, { AccountState::Initialized }>>,
|
||||||
|
pub lp_share_acc: Mut<Data<'b, SplAccount, { AccountState::Initialized }>>,
|
||||||
|
pub custody_signer: CustodySigner<'b>,
|
||||||
|
pub authority_signer: AuthoritySigner<'b>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BorshDeserialize, BorshSerialize, Default)]
|
||||||
|
pub struct ClaimSharesData {
|
||||||
|
pub amount: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn claim_shares(
|
||||||
|
ctx: &ExecutionContext,
|
||||||
|
accs: &mut ClaimShares,
|
||||||
|
data: ClaimSharesData,
|
||||||
|
) -> Result<()> {
|
||||||
|
if *accs.to_mint.info().key != accs.pool.to {
|
||||||
|
return Err(WrongMint.into());
|
||||||
|
}
|
||||||
|
if accs.lp_share_acc.mint != *accs.share_mint.info().key {
|
||||||
|
return Err(WrongMint.into());
|
||||||
|
}
|
||||||
|
accs.from_token_custody.verify_derivation(
|
||||||
|
ctx.program_id,
|
||||||
|
&FromCustodyTokenAccountDerivationData {
|
||||||
|
pool: *accs.pool.info().key,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
accs.share_mint.verify_derivation(
|
||||||
|
ctx.program_id,
|
||||||
|
&ShareMintDerivationData {
|
||||||
|
pool: *accs.pool.info().key,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
accs.pool.verify_derivation(
|
||||||
|
ctx.program_id,
|
||||||
|
&MigrationPoolDerivationData {
|
||||||
|
from: accs.pool.from,
|
||||||
|
to: accs.pool.to,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Transfer claimed tokens to LP
|
||||||
|
let transfer_ix = spl_token::instruction::transfer(
|
||||||
|
&spl_token::id(),
|
||||||
|
accs.from_token_custody.info().key,
|
||||||
|
accs.from_lp_acc.info().key,
|
||||||
|
accs.custody_signer.key,
|
||||||
|
&[],
|
||||||
|
data.amount,
|
||||||
|
)?;
|
||||||
|
invoke_seeded(&transfer_ix, ctx, &accs.custody_signer, None)?;
|
||||||
|
|
||||||
|
// Burn LP shares
|
||||||
|
let mint_ix = spl_token::instruction::burn(
|
||||||
|
&spl_token::id(),
|
||||||
|
accs.lp_share_acc.info().key,
|
||||||
|
accs.share_mint.info().key,
|
||||||
|
accs.authority_signer.key,
|
||||||
|
&[],
|
||||||
|
data.amount,
|
||||||
|
)?;
|
||||||
|
invoke_seeded(&mint_ix, ctx, &accs.authority_signer, None)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -0,0 +1,119 @@
|
||||||
|
use crate::{
|
||||||
|
accounts::{
|
||||||
|
CustodySigner,
|
||||||
|
FromCustodyTokenAccount,
|
||||||
|
FromCustodyTokenAccountDerivationData,
|
||||||
|
MigrationPool,
|
||||||
|
MigrationPoolDerivationData,
|
||||||
|
ShareMint,
|
||||||
|
ShareMintDerivationData,
|
||||||
|
ToCustodyTokenAccount,
|
||||||
|
ToCustodyTokenAccountDerivationData,
|
||||||
|
},
|
||||||
|
types::SplMint,
|
||||||
|
};
|
||||||
|
use borsh::{
|
||||||
|
BorshDeserialize,
|
||||||
|
BorshSerialize,
|
||||||
|
};
|
||||||
|
use solana_program::program::invoke_signed;
|
||||||
|
use solitaire::{
|
||||||
|
processors::seeded::Seeded,
|
||||||
|
CreationLamports::Exempt,
|
||||||
|
*,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(FromAccounts)]
|
||||||
|
pub struct CreatePool<'b> {
|
||||||
|
pub payer: Mut<Signer<Info<'b>>>,
|
||||||
|
|
||||||
|
pub pool: Mut<MigrationPool<'b, { AccountState::Uninitialized }>>,
|
||||||
|
pub from_mint: Data<'b, SplMint, { AccountState::Initialized }>,
|
||||||
|
pub to_mint: Data<'b, SplMint, { AccountState::Initialized }>,
|
||||||
|
pub from_token_custody: Mut<FromCustodyTokenAccount<'b, { AccountState::Uninitialized }>>,
|
||||||
|
pub to_token_custody: Mut<ToCustodyTokenAccount<'b, { AccountState::Uninitialized }>>,
|
||||||
|
pub pool_mint: Mut<ShareMint<'b, { AccountState::Uninitialized }>>,
|
||||||
|
|
||||||
|
pub custody_signer: CustodySigner<'b>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BorshDeserialize, BorshSerialize, Default)]
|
||||||
|
pub struct CreatePoolData {}
|
||||||
|
|
||||||
|
pub fn create_pool(
|
||||||
|
ctx: &ExecutionContext,
|
||||||
|
accs: &mut CreatePool,
|
||||||
|
_data: CreatePoolData,
|
||||||
|
) -> Result<()> {
|
||||||
|
// Create from custody account
|
||||||
|
accs.from_token_custody.create(
|
||||||
|
&FromCustodyTokenAccountDerivationData {
|
||||||
|
pool: *accs.pool.info().key,
|
||||||
|
},
|
||||||
|
ctx,
|
||||||
|
accs.payer.key,
|
||||||
|
Exempt,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let init_ix = spl_token::instruction::initialize_account(
|
||||||
|
&spl_token::id(),
|
||||||
|
accs.from_token_custody.info().key,
|
||||||
|
accs.from_mint.info().key,
|
||||||
|
accs.custody_signer.info().key,
|
||||||
|
)?;
|
||||||
|
invoke_signed(&init_ix, ctx.accounts, &[])?;
|
||||||
|
|
||||||
|
// Create to custody account
|
||||||
|
accs.to_token_custody.create(
|
||||||
|
&ToCustodyTokenAccountDerivationData {
|
||||||
|
pool: *accs.pool.info().key,
|
||||||
|
},
|
||||||
|
ctx,
|
||||||
|
accs.payer.key,
|
||||||
|
Exempt,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let init_ix = spl_token::instruction::initialize_account(
|
||||||
|
&spl_token::id(),
|
||||||
|
accs.to_token_custody.info().key,
|
||||||
|
accs.to_mint.info().key,
|
||||||
|
accs.custody_signer.info().key,
|
||||||
|
)?;
|
||||||
|
invoke_signed(&init_ix, ctx.accounts, &[])?;
|
||||||
|
|
||||||
|
// Create to pool mint
|
||||||
|
accs.pool_mint.create(
|
||||||
|
&ShareMintDerivationData {
|
||||||
|
pool: *accs.pool.info().key,
|
||||||
|
},
|
||||||
|
ctx,
|
||||||
|
accs.payer.key,
|
||||||
|
Exempt,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let init_ix = spl_token::instruction::initialize_mint(
|
||||||
|
&spl_token::id(),
|
||||||
|
accs.pool_mint.info().key,
|
||||||
|
accs.custody_signer.info().key,
|
||||||
|
None,
|
||||||
|
accs.from_mint.decimals,
|
||||||
|
)?;
|
||||||
|
invoke_signed(&init_ix, ctx.accounts, &[])?;
|
||||||
|
|
||||||
|
// Set fields on pool
|
||||||
|
accs.pool.from = *accs.from_mint.info().key;
|
||||||
|
accs.pool.to = *accs.to_mint.info().key;
|
||||||
|
|
||||||
|
// Create pool
|
||||||
|
accs.pool.create(
|
||||||
|
&MigrationPoolDerivationData {
|
||||||
|
from: *accs.from_mint.info().key,
|
||||||
|
to: *accs.to_mint.info().key,
|
||||||
|
},
|
||||||
|
ctx,
|
||||||
|
accs.payer.key,
|
||||||
|
Exempt,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
use crate::{
|
||||||
|
accounts::{
|
||||||
|
AuthoritySigner,
|
||||||
|
CustodySigner,
|
||||||
|
FromCustodyTokenAccount,
|
||||||
|
FromCustodyTokenAccountDerivationData,
|
||||||
|
MigrationPool,
|
||||||
|
ToCustodyTokenAccount,
|
||||||
|
ToCustodyTokenAccountDerivationData,
|
||||||
|
},
|
||||||
|
types::{
|
||||||
|
SplAccount,
|
||||||
|
SplMint,
|
||||||
|
},
|
||||||
|
MigrationError::WrongMint,
|
||||||
|
};
|
||||||
|
use borsh::{
|
||||||
|
BorshDeserialize,
|
||||||
|
BorshSerialize,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::accounts::MigrationPoolDerivationData;
|
||||||
|
use solitaire::{
|
||||||
|
processors::seeded::{
|
||||||
|
invoke_seeded,
|
||||||
|
Seeded,
|
||||||
|
},
|
||||||
|
*,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(FromAccounts)]
|
||||||
|
pub struct MigrateTokens<'b> {
|
||||||
|
pub pool: Mut<MigrationPool<'b, { AccountState::Initialized }>>,
|
||||||
|
pub from_mint: Data<'b, SplMint, { AccountState::Initialized }>,
|
||||||
|
pub to_mint: Data<'b, SplMint, { AccountState::Initialized }>,
|
||||||
|
pub to_token_custody: Mut<ToCustodyTokenAccount<'b, { AccountState::Initialized }>>,
|
||||||
|
pub from_token_custody: Mut<FromCustodyTokenAccount<'b, { AccountState::Initialized }>>,
|
||||||
|
|
||||||
|
pub user_from_acc: Mut<Data<'b, SplAccount, { AccountState::Initialized }>>,
|
||||||
|
pub user_to_acc: Mut<Data<'b, SplAccount, { AccountState::Initialized }>>,
|
||||||
|
pub custody_signer: CustodySigner<'b>,
|
||||||
|
pub authority_signer: AuthoritySigner<'b>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BorshDeserialize, BorshSerialize, Default)]
|
||||||
|
pub struct MigrateTokensData {
|
||||||
|
pub amount: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn migrate_tokens(
|
||||||
|
ctx: &ExecutionContext,
|
||||||
|
accs: &mut MigrateTokens,
|
||||||
|
data: MigrateTokensData,
|
||||||
|
) -> Result<()> {
|
||||||
|
if *accs.from_mint.info().key != accs.pool.from {
|
||||||
|
return Err(WrongMint.into());
|
||||||
|
}
|
||||||
|
if *accs.to_mint.info().key != accs.pool.to {
|
||||||
|
return Err(WrongMint.into());
|
||||||
|
}
|
||||||
|
if accs.user_from_acc.mint != accs.pool.from {
|
||||||
|
return Err(WrongMint.into());
|
||||||
|
}
|
||||||
|
if accs.user_to_acc.mint != accs.pool.to {
|
||||||
|
return Err(WrongMint.into());
|
||||||
|
}
|
||||||
|
accs.to_token_custody.verify_derivation(
|
||||||
|
ctx.program_id,
|
||||||
|
&ToCustodyTokenAccountDerivationData {
|
||||||
|
pool: *accs.pool.info().key,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
accs.from_token_custody.verify_derivation(
|
||||||
|
ctx.program_id,
|
||||||
|
&FromCustodyTokenAccountDerivationData {
|
||||||
|
pool: *accs.pool.info().key,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
accs.pool.verify_derivation(
|
||||||
|
ctx.program_id,
|
||||||
|
&MigrationPoolDerivationData {
|
||||||
|
from: accs.pool.from,
|
||||||
|
to: accs.pool.to,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Transfer in-tokens in
|
||||||
|
let transfer_ix = spl_token::instruction::transfer(
|
||||||
|
&spl_token::id(),
|
||||||
|
accs.user_from_acc.info().key,
|
||||||
|
accs.from_token_custody.info().key,
|
||||||
|
accs.authority_signer.key,
|
||||||
|
&[],
|
||||||
|
data.amount,
|
||||||
|
)?;
|
||||||
|
invoke_seeded(&transfer_ix, ctx, &accs.authority_signer, None)?;
|
||||||
|
|
||||||
|
// The share amount should be equal to the amount of from tokens an lp would be getting
|
||||||
|
let out_amount = if accs.from_mint.decimals > accs.to_mint.decimals {
|
||||||
|
data.amount
|
||||||
|
.checked_div(10u64.pow((accs.from_mint.decimals - accs.to_mint.decimals) as u32))
|
||||||
|
.unwrap()
|
||||||
|
} else {
|
||||||
|
data.amount
|
||||||
|
.checked_mul(10u64.pow((accs.to_mint.decimals - accs.from_mint.decimals) as u32))
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Transfer out-tokens to user
|
||||||
|
let transfer_ix = spl_token::instruction::transfer(
|
||||||
|
&spl_token::id(),
|
||||||
|
accs.to_token_custody.info().key,
|
||||||
|
accs.user_to_acc.info().key,
|
||||||
|
accs.custody_signer.key,
|
||||||
|
&[],
|
||||||
|
out_amount,
|
||||||
|
)?;
|
||||||
|
invoke_seeded(&transfer_ix, ctx, &accs.custody_signer, None)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -0,0 +1,242 @@
|
||||||
|
use crate::{
|
||||||
|
accounts::{
|
||||||
|
AuthoritySigner,
|
||||||
|
CustodySigner,
|
||||||
|
FromCustodyTokenAccount,
|
||||||
|
FromCustodyTokenAccountDerivationData,
|
||||||
|
MigrationPool,
|
||||||
|
MigrationPoolDerivationData,
|
||||||
|
ShareMint,
|
||||||
|
ShareMintDerivationData,
|
||||||
|
ToCustodyTokenAccount,
|
||||||
|
ToCustodyTokenAccountDerivationData,
|
||||||
|
},
|
||||||
|
api::{
|
||||||
|
add_liquidity::AddLiquidityData,
|
||||||
|
claim_shares::ClaimSharesData,
|
||||||
|
create_pool::CreatePoolData,
|
||||||
|
migrate_tokens::MigrateTokensData,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use borsh::BorshSerialize;
|
||||||
|
use solana_program::{
|
||||||
|
instruction::{
|
||||||
|
AccountMeta,
|
||||||
|
Instruction,
|
||||||
|
},
|
||||||
|
pubkey::Pubkey,
|
||||||
|
};
|
||||||
|
use solitaire::{
|
||||||
|
processors::seeded::Seeded,
|
||||||
|
AccountState,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn add_liquidity(
|
||||||
|
program_id: Pubkey,
|
||||||
|
from_mint: Pubkey,
|
||||||
|
to_mint: Pubkey,
|
||||||
|
liquidity_token_account: Pubkey,
|
||||||
|
lp_share_token_account: Pubkey,
|
||||||
|
amount: u64,
|
||||||
|
) -> solitaire::Result<Instruction> {
|
||||||
|
let pool = MigrationPool::<'_, { AccountState::Initialized }>::key(
|
||||||
|
&MigrationPoolDerivationData {
|
||||||
|
from: from_mint,
|
||||||
|
to: to_mint,
|
||||||
|
},
|
||||||
|
&program_id,
|
||||||
|
);
|
||||||
|
Ok(Instruction {
|
||||||
|
program_id,
|
||||||
|
accounts: vec![
|
||||||
|
AccountMeta::new(pool, false),
|
||||||
|
AccountMeta::new_readonly(from_mint, false),
|
||||||
|
AccountMeta::new_readonly(to_mint, false),
|
||||||
|
AccountMeta::new(
|
||||||
|
ToCustodyTokenAccount::<'_, { AccountState::Uninitialized }>::key(
|
||||||
|
&ToCustodyTokenAccountDerivationData { pool },
|
||||||
|
&program_id,
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
AccountMeta::new(
|
||||||
|
ShareMint::<'_, { AccountState::Uninitialized }>::key(
|
||||||
|
&ShareMintDerivationData { pool },
|
||||||
|
&program_id,
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
AccountMeta::new(liquidity_token_account, false),
|
||||||
|
AccountMeta::new(lp_share_token_account, false),
|
||||||
|
AccountMeta::new_readonly(CustodySigner::key(None, &program_id), false),
|
||||||
|
AccountMeta::new_readonly(AuthoritySigner::key(None, &program_id), false),
|
||||||
|
// Dependencies
|
||||||
|
AccountMeta::new(solana_program::sysvar::rent::id(), false),
|
||||||
|
AccountMeta::new(solana_program::system_program::id(), false),
|
||||||
|
AccountMeta::new_readonly(spl_token::id(), false),
|
||||||
|
],
|
||||||
|
data: (
|
||||||
|
crate::instruction::Instruction::AddLiquidity,
|
||||||
|
AddLiquidityData { amount },
|
||||||
|
)
|
||||||
|
.try_to_vec()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn claim_shares(
|
||||||
|
program_id: Pubkey,
|
||||||
|
from_mint: Pubkey,
|
||||||
|
to_mint: Pubkey,
|
||||||
|
output_token_account: Pubkey,
|
||||||
|
lp_share_token_account: Pubkey,
|
||||||
|
amount: u64,
|
||||||
|
) -> solitaire::Result<Instruction> {
|
||||||
|
let pool = MigrationPool::<'_, { AccountState::Initialized }>::key(
|
||||||
|
&MigrationPoolDerivationData {
|
||||||
|
from: from_mint,
|
||||||
|
to: to_mint,
|
||||||
|
},
|
||||||
|
&program_id,
|
||||||
|
);
|
||||||
|
Ok(Instruction {
|
||||||
|
program_id,
|
||||||
|
accounts: vec![
|
||||||
|
AccountMeta::new(pool, false),
|
||||||
|
AccountMeta::new_readonly(to_mint, false),
|
||||||
|
AccountMeta::new(
|
||||||
|
FromCustodyTokenAccount::<'_, { AccountState::Uninitialized }>::key(
|
||||||
|
&FromCustodyTokenAccountDerivationData { pool },
|
||||||
|
&program_id,
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
AccountMeta::new(
|
||||||
|
ShareMint::<'_, { AccountState::Uninitialized }>::key(
|
||||||
|
&ShareMintDerivationData { pool },
|
||||||
|
&program_id,
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
AccountMeta::new(output_token_account, false),
|
||||||
|
AccountMeta::new(lp_share_token_account, false),
|
||||||
|
AccountMeta::new_readonly(CustodySigner::key(None, &program_id), false),
|
||||||
|
AccountMeta::new_readonly(AuthoritySigner::key(None, &program_id), false),
|
||||||
|
// Dependencies
|
||||||
|
AccountMeta::new(solana_program::sysvar::rent::id(), false),
|
||||||
|
AccountMeta::new(solana_program::system_program::id(), false),
|
||||||
|
AccountMeta::new_readonly(spl_token::id(), false),
|
||||||
|
],
|
||||||
|
data: (
|
||||||
|
crate::instruction::Instruction::ClaimShares,
|
||||||
|
ClaimSharesData { amount },
|
||||||
|
)
|
||||||
|
.try_to_vec()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_pool(
|
||||||
|
program_id: Pubkey,
|
||||||
|
payer: Pubkey,
|
||||||
|
from_mint: Pubkey,
|
||||||
|
to_mint: Pubkey,
|
||||||
|
) -> solitaire::Result<Instruction> {
|
||||||
|
let pool = MigrationPool::<'_, { AccountState::Initialized }>::key(
|
||||||
|
&MigrationPoolDerivationData {
|
||||||
|
from: from_mint,
|
||||||
|
to: to_mint,
|
||||||
|
},
|
||||||
|
&program_id,
|
||||||
|
);
|
||||||
|
Ok(Instruction {
|
||||||
|
program_id,
|
||||||
|
accounts: vec![
|
||||||
|
AccountMeta::new(payer, true),
|
||||||
|
AccountMeta::new(pool, false),
|
||||||
|
AccountMeta::new_readonly(from_mint, false),
|
||||||
|
AccountMeta::new_readonly(to_mint, false),
|
||||||
|
AccountMeta::new(
|
||||||
|
FromCustodyTokenAccount::<'_, { AccountState::Uninitialized }>::key(
|
||||||
|
&FromCustodyTokenAccountDerivationData { pool },
|
||||||
|
&program_id,
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
AccountMeta::new(
|
||||||
|
ToCustodyTokenAccount::<'_, { AccountState::Uninitialized }>::key(
|
||||||
|
&ToCustodyTokenAccountDerivationData { pool },
|
||||||
|
&program_id,
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
AccountMeta::new(
|
||||||
|
ShareMint::<'_, { AccountState::Uninitialized }>::key(
|
||||||
|
&ShareMintDerivationData { pool },
|
||||||
|
&program_id,
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
AccountMeta::new_readonly(CustodySigner::key(None, &program_id), false),
|
||||||
|
// Dependencies
|
||||||
|
AccountMeta::new(solana_program::sysvar::rent::id(), false),
|
||||||
|
AccountMeta::new(solana_program::system_program::id(), false),
|
||||||
|
AccountMeta::new_readonly(spl_token::id(), false),
|
||||||
|
],
|
||||||
|
data: (
|
||||||
|
crate::instruction::Instruction::CreatePool,
|
||||||
|
CreatePoolData {},
|
||||||
|
)
|
||||||
|
.try_to_vec()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn migrate_tokens(
|
||||||
|
program_id: Pubkey,
|
||||||
|
from_mint: Pubkey,
|
||||||
|
to_mint: Pubkey,
|
||||||
|
input_token_account: Pubkey,
|
||||||
|
output_token_account: Pubkey,
|
||||||
|
amount: u64,
|
||||||
|
) -> solitaire::Result<Instruction> {
|
||||||
|
let pool = MigrationPool::<'_, { AccountState::Initialized }>::key(
|
||||||
|
&MigrationPoolDerivationData {
|
||||||
|
from: from_mint,
|
||||||
|
to: to_mint,
|
||||||
|
},
|
||||||
|
&program_id,
|
||||||
|
);
|
||||||
|
Ok(Instruction {
|
||||||
|
program_id,
|
||||||
|
accounts: vec![
|
||||||
|
AccountMeta::new(pool, false),
|
||||||
|
AccountMeta::new_readonly(from_mint, false),
|
||||||
|
AccountMeta::new_readonly(to_mint, false),
|
||||||
|
AccountMeta::new(
|
||||||
|
ToCustodyTokenAccount::<'_, { AccountState::Uninitialized }>::key(
|
||||||
|
&ToCustodyTokenAccountDerivationData { pool },
|
||||||
|
&program_id,
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
AccountMeta::new(
|
||||||
|
FromCustodyTokenAccount::<'_, { AccountState::Uninitialized }>::key(
|
||||||
|
&FromCustodyTokenAccountDerivationData { pool },
|
||||||
|
&program_id,
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
AccountMeta::new(input_token_account, false),
|
||||||
|
AccountMeta::new(output_token_account, false),
|
||||||
|
AccountMeta::new_readonly(CustodySigner::key(None, &program_id), false),
|
||||||
|
AccountMeta::new_readonly(AuthoritySigner::key(None, &program_id), false),
|
||||||
|
// Dependencies
|
||||||
|
AccountMeta::new(solana_program::sysvar::rent::id(), false),
|
||||||
|
AccountMeta::new(solana_program::system_program::id(), false),
|
||||||
|
AccountMeta::new_readonly(spl_token::id(), false),
|
||||||
|
],
|
||||||
|
data: (
|
||||||
|
crate::instruction::Instruction::MigrateTokens,
|
||||||
|
MigrateTokensData { amount },
|
||||||
|
)
|
||||||
|
.try_to_vec()?,
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(const_generics)]
|
||||||
|
|
||||||
|
use api::{
|
||||||
|
add_liquidity::*,
|
||||||
|
claim_shares::*,
|
||||||
|
create_pool::*,
|
||||||
|
migrate_tokens::*,
|
||||||
|
};
|
||||||
|
use solitaire::{
|
||||||
|
solitaire,
|
||||||
|
SolitaireError,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod accounts;
|
||||||
|
pub mod api;
|
||||||
|
pub mod types;
|
||||||
|
|
||||||
|
#[cfg(feature = "no-entrypoint")]
|
||||||
|
pub mod instructions;
|
||||||
|
|
||||||
|
#[cfg(feature = "wasm")]
|
||||||
|
#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
|
||||||
|
extern crate wasm_bindgen;
|
||||||
|
|
||||||
|
#[cfg(feature = "wasm")]
|
||||||
|
#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
|
||||||
|
pub mod wasm;
|
||||||
|
|
||||||
|
pub enum MigrationError {
|
||||||
|
WrongMint,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<MigrationError> for SolitaireError {
|
||||||
|
fn from(t: MigrationError) -> SolitaireError {
|
||||||
|
SolitaireError::Custom(t as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
solitaire! {
|
||||||
|
AddLiquidity(AddLiquidityData) => add_liquidity,
|
||||||
|
ClaimShares(ClaimSharesData) => claim_shares,
|
||||||
|
CreatePool(CreatePoolData) => create_pool,
|
||||||
|
MigrateTokens(MigrateTokensData) => migrate_tokens,
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
use borsh::{
|
||||||
|
BorshDeserialize,
|
||||||
|
BorshSerialize,
|
||||||
|
};
|
||||||
|
use serde::{
|
||||||
|
Deserialize,
|
||||||
|
Serialize,
|
||||||
|
};
|
||||||
|
use solana_program::pubkey::Pubkey;
|
||||||
|
use solitaire::{
|
||||||
|
pack_type,
|
||||||
|
processors::seeded::{
|
||||||
|
AccountOwner,
|
||||||
|
Owned,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use spl_token::state::{
|
||||||
|
Account,
|
||||||
|
Mint,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Default, Clone, Copy, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
|
||||||
|
pub struct PoolData {
|
||||||
|
pub from: Pubkey,
|
||||||
|
pub to: Pubkey,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Owned for PoolData {
|
||||||
|
fn owner(&self) -> AccountOwner {
|
||||||
|
AccountOwner::This
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pack_type!(SplMint, Mint, AccountOwner::Other(spl_token::id()));
|
||||||
|
pack_type!(SplAccount, Account, AccountOwner::Other(spl_token::id()));
|
|
@ -0,0 +1,194 @@
|
||||||
|
use crate::{
|
||||||
|
accounts::{
|
||||||
|
AuthoritySigner,
|
||||||
|
FromCustodyTokenAccount,
|
||||||
|
FromCustodyTokenAccountDerivationData,
|
||||||
|
MigrationPool,
|
||||||
|
MigrationPoolDerivationData,
|
||||||
|
ShareMint,
|
||||||
|
ShareMintDerivationData,
|
||||||
|
ToCustodyTokenAccount,
|
||||||
|
ToCustodyTokenAccountDerivationData,
|
||||||
|
},
|
||||||
|
instructions,
|
||||||
|
types::PoolData,
|
||||||
|
};
|
||||||
|
use borsh::BorshDeserialize;
|
||||||
|
use solana_program::pubkey::Pubkey;
|
||||||
|
use solitaire::{
|
||||||
|
processors::seeded::Seeded,
|
||||||
|
AccountState,
|
||||||
|
};
|
||||||
|
use std::str::FromStr;
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn add_liquidity(
|
||||||
|
program_id: String,
|
||||||
|
from_mint: String,
|
||||||
|
to_mint: String,
|
||||||
|
liquidity_token_account: String,
|
||||||
|
lp_share_token_account: String,
|
||||||
|
amount: u64,
|
||||||
|
) -> JsValue {
|
||||||
|
let program_id = Pubkey::from_str(program_id.as_str()).unwrap();
|
||||||
|
let from_mint = Pubkey::from_str(from_mint.as_str()).unwrap();
|
||||||
|
let to_mint = Pubkey::from_str(to_mint.as_str()).unwrap();
|
||||||
|
let liquidity_token_account = Pubkey::from_str(liquidity_token_account.as_str()).unwrap();
|
||||||
|
let lp_share_token_account = Pubkey::from_str(lp_share_token_account.as_str()).unwrap();
|
||||||
|
|
||||||
|
let ix = instructions::add_liquidity(
|
||||||
|
program_id,
|
||||||
|
from_mint,
|
||||||
|
to_mint,
|
||||||
|
liquidity_token_account,
|
||||||
|
lp_share_token_account,
|
||||||
|
amount,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
JsValue::from_serde(&ix).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn claim_shares(
|
||||||
|
program_id: String,
|
||||||
|
from_mint: String,
|
||||||
|
to_mint: String,
|
||||||
|
output_token_account: String,
|
||||||
|
lp_share_token_account: String,
|
||||||
|
amount: u64,
|
||||||
|
) -> JsValue {
|
||||||
|
let program_id = Pubkey::from_str(program_id.as_str()).unwrap();
|
||||||
|
let from_mint = Pubkey::from_str(from_mint.as_str()).unwrap();
|
||||||
|
let to_mint = Pubkey::from_str(to_mint.as_str()).unwrap();
|
||||||
|
let output_token_account = Pubkey::from_str(output_token_account.as_str()).unwrap();
|
||||||
|
let lp_share_token_account = Pubkey::from_str(lp_share_token_account.as_str()).unwrap();
|
||||||
|
|
||||||
|
let ix = instructions::claim_shares(
|
||||||
|
program_id,
|
||||||
|
from_mint,
|
||||||
|
to_mint,
|
||||||
|
output_token_account,
|
||||||
|
lp_share_token_account,
|
||||||
|
amount,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
JsValue::from_serde(&ix).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn create_pool(
|
||||||
|
program_id: String,
|
||||||
|
payer: String,
|
||||||
|
from_mint: String,
|
||||||
|
to_mint: String,
|
||||||
|
) -> JsValue {
|
||||||
|
let program_id = Pubkey::from_str(program_id.as_str()).unwrap();
|
||||||
|
let payer = Pubkey::from_str(payer.as_str()).unwrap();
|
||||||
|
let from_mint = Pubkey::from_str(from_mint.as_str()).unwrap();
|
||||||
|
let to_mint = Pubkey::from_str(to_mint.as_str()).unwrap();
|
||||||
|
|
||||||
|
let ix = instructions::create_pool(program_id, payer, from_mint, to_mint).unwrap();
|
||||||
|
|
||||||
|
JsValue::from_serde(&ix).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn migrate_tokens(
|
||||||
|
program_id: String,
|
||||||
|
from_mint: String,
|
||||||
|
to_mint: String,
|
||||||
|
input_token_account: String,
|
||||||
|
output_token_account: String,
|
||||||
|
amount: u64,
|
||||||
|
) -> JsValue {
|
||||||
|
let program_id = Pubkey::from_str(program_id.as_str()).unwrap();
|
||||||
|
let from_mint = Pubkey::from_str(from_mint.as_str()).unwrap();
|
||||||
|
let to_mint = Pubkey::from_str(to_mint.as_str()).unwrap();
|
||||||
|
let input_token_account = Pubkey::from_str(input_token_account.as_str()).unwrap();
|
||||||
|
let output_token_account = Pubkey::from_str(output_token_account.as_str()).unwrap();
|
||||||
|
|
||||||
|
let ix = instructions::migrate_tokens(
|
||||||
|
program_id,
|
||||||
|
from_mint,
|
||||||
|
to_mint,
|
||||||
|
input_token_account,
|
||||||
|
output_token_account,
|
||||||
|
amount,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
JsValue::from_serde(&ix).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn pool_address(program_id: String, from_mint: String, to_mint: String) -> Vec<u8> {
|
||||||
|
let program_id = Pubkey::from_str(program_id.as_str()).unwrap();
|
||||||
|
let from_mint_key = Pubkey::from_str(from_mint.as_str()).unwrap();
|
||||||
|
let to_mint_key = Pubkey::from_str(to_mint.as_str()).unwrap();
|
||||||
|
|
||||||
|
let pool_addr = MigrationPool::<'_, { AccountState::Initialized }>::key(
|
||||||
|
&MigrationPoolDerivationData {
|
||||||
|
from: from_mint_key,
|
||||||
|
to: to_mint_key,
|
||||||
|
},
|
||||||
|
&program_id,
|
||||||
|
);
|
||||||
|
|
||||||
|
pool_addr.to_bytes().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn authority_address(program_id: String) -> Vec<u8> {
|
||||||
|
let program_id = Pubkey::from_str(program_id.as_str()).unwrap();
|
||||||
|
|
||||||
|
let authority_addr = AuthoritySigner::key(None, &program_id);
|
||||||
|
|
||||||
|
authority_addr.to_bytes().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn share_mint_address(program_id: String, pool: String) -> Vec<u8> {
|
||||||
|
let program_id = Pubkey::from_str(program_id.as_str()).unwrap();
|
||||||
|
let pool_key = Pubkey::from_str(pool.as_str()).unwrap();
|
||||||
|
|
||||||
|
let share_mint_addr = ShareMint::<'_, { AccountState::Initialized }>::key(
|
||||||
|
&ShareMintDerivationData { pool: pool_key },
|
||||||
|
&program_id,
|
||||||
|
);
|
||||||
|
|
||||||
|
share_mint_addr.to_bytes().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn from_custody_address(program_id: String, pool: String) -> Vec<u8> {
|
||||||
|
let program_id = Pubkey::from_str(program_id.as_str()).unwrap();
|
||||||
|
let pool_key = Pubkey::from_str(pool.as_str()).unwrap();
|
||||||
|
|
||||||
|
let from_custody_addr = FromCustodyTokenAccount::<'_, { AccountState::Initialized }>::key(
|
||||||
|
&FromCustodyTokenAccountDerivationData { pool: pool_key },
|
||||||
|
&program_id,
|
||||||
|
);
|
||||||
|
|
||||||
|
from_custody_addr.to_bytes().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn to_custody_address(program_id: String, pool: String) -> Vec<u8> {
|
||||||
|
let program_id = Pubkey::from_str(program_id.as_str()).unwrap();
|
||||||
|
let pool_key = Pubkey::from_str(pool.as_str()).unwrap();
|
||||||
|
|
||||||
|
let to_custody_addr = ToCustodyTokenAccount::<'_, { AccountState::Initialized }>::key(
|
||||||
|
&ToCustodyTokenAccountDerivationData { pool: pool_key },
|
||||||
|
&program_id,
|
||||||
|
);
|
||||||
|
|
||||||
|
to_custody_addr.to_bytes().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn parse_pool(data: Vec<u8>) -> JsValue {
|
||||||
|
JsValue::from_serde(&PoolData::try_from_slice(data.as_slice()).unwrap()).unwrap()
|
||||||
|
}
|
Loading…
Reference in New Issue