Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
],
"dependencies": {
"@dappio-wonderland/gateway-idls": "^0.2.6",
"@dappio-wonderland/navigator": "^0.2.11",
"@dappio-wonderland/navigator": "^0.2.20",
"@jup-ag/core": "1.0.0-beta.26",
"@project-serum/anchor": "^0.24.2",
"@project-serum/borsh": "^0.2.5",
Expand Down
34 changes: 34 additions & 0 deletions src/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
nftFinance,
katana,
friktion,
lido,
} from "@dappio-wonderland/navigator";
import {
ActionType,
Expand Down Expand Up @@ -63,6 +64,7 @@ import { ProtocolFrancium } from "./protocols/francium";
import { ProtocolKatana } from "./protocols/katana";
import { ProtocolTulip } from "./protocols/tulip";
import { ProtocolFriktion } from "./protocols/friktion";
import { ProtocolLido } from "./protocols/lido";

export class GatewayBuilder {
public params: GatewayParams;
Expand Down Expand Up @@ -109,6 +111,7 @@ export class GatewayBuilder {
// Extra Metadata
poolDirection: PoolDirection.Obverse,
swapMinOutAmount: new anchor.BN(0),
validatorIndex: 0,
};

this._metadata = {
Expand Down Expand Up @@ -1188,6 +1191,19 @@ export class GatewayBuilder {
);

break;
case SupportedProtocols.Lido:
this._metadata.vault = await lido.infos.getVault(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So in order to support validatorIndex in GatewayState:

  1. Add validatorIndex as an optional field in DepositParams
  2. Add validatorIndex field (metadata section) in GatewayParams (this is a work-around)
  3. Update gatewayParams: this.params.validatorIndex = depositParams.validatorIndex

this._provider.connection,
depositParams.vaultId
);
protocol = new ProtocolLido(
this._provider.connection,
this._program,
await this.getGatewayStateKey(),
this.params
);

break;
default:
throw new Error("Unsupported Protocol");
}
Expand Down Expand Up @@ -1297,6 +1313,24 @@ export class GatewayBuilder {

break;

case SupportedProtocols.Lido:
// NOTE: This is a temporary work-around, and will be removed once multiple indexes are supported in `gateway-programs`
const vault = await lido.infos.getVault(
this._provider.connection,
withdrawParams.vaultId
);
this._metadata.vault = vault;
this.params.validatorIndex = (new lido.VaultInfoWrapper(vault as lido.VaultInfo)).getHeaviestValidatorIndex();

protocol = new ProtocolLido(
this._provider.connection,
this._program,
await this.getGatewayStateKey(),
this.params
);

break;

default:
throw new Error("Unsupported Protocol");
}
Expand Down
58 changes: 16 additions & 42 deletions src/ids.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,34 @@ import { PublicKey } from "@solana/web3.js";

// Program IDs

export const GATEWAY_PROGRAM_ID = new PublicKey(
"GATEp6AEtXtwHABNWHKH9qeh3uJDZtZJ7YBNYzHsX3FS"
);
export const GATEWAY_PROGRAM_ID = new PublicKey("GATEp6AEtXtwHABNWHKH9qeh3uJDZtZJ7YBNYzHsX3FS");

export const RAYDIUM_ADAPTER_PROGRAM_ID = new PublicKey(
"ADPT1q4xG8F9m64cQyjqGe11cCXQq6vL4beY5hJavhQ5"
);
export const RAYDIUM_ADAPTER_PROGRAM_ID = new PublicKey("ADPT1q4xG8F9m64cQyjqGe11cCXQq6vL4beY5hJavhQ5");

export const SABER_ADAPTER_PROGRAM_ID = new PublicKey(
"ADPT4GbWTs9DXxo91YGBjNntYwLpXxn4gEbxfnUPfQoB"
);
export const SABER_ADAPTER_PROGRAM_ID = new PublicKey("ADPT4GbWTs9DXxo91YGBjNntYwLpXxn4gEbxfnUPfQoB");

export const TULIP_ADAPTER_PROGRAM_ID = new PublicKey(
"ADPT9nhC1asRcEB13FKymLTatqWGCuZHDznGgnakWKxW"
);
export const TULIP_ADAPTER_PROGRAM_ID = new PublicKey("ADPT9nhC1asRcEB13FKymLTatqWGCuZHDznGgnakWKxW");

export const SOLEND_ADAPTER_PROGRAM_ID = new PublicKey(
"ADPTCXAFfJFVqcw73B4PWRZQjMNo7Q3Yj4g7p4zTiZnQ"
);
export const SOLEND_ADAPTER_PROGRAM_ID = new PublicKey("ADPTCXAFfJFVqcw73B4PWRZQjMNo7Q3Yj4g7p4zTiZnQ");

export const NFT_FINANCE_ADAPTER_PROGRAM_ID = new PublicKey(
"ADPTyBr92sBCE1hdYBRvXbMpF4hKs17xyDjFPxopcsrh"
);
export const NFT_FINANCE_ADAPTER_PROGRAM_ID = new PublicKey("ADPTyBr92sBCE1hdYBRvXbMpF4hKs17xyDjFPxopcsrh");

export const SERUM_PROGRAM_ID = new PublicKey(
"9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin"
);
export const SERUM_PROGRAM_ID = new PublicKey("9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin");

export const NATIVE_SOL = new PublicKey("11111111111111111111111111111111");

export const WSOL = new PublicKey(
"So11111111111111111111111111111111111111112"
);
export const WSOL = new PublicKey("So11111111111111111111111111111111111111112");

export const LARIX_ADAPTER_PROGRAM_ID = new PublicKey(
"ADPTLQQ1Bwgybb2qge7QKSW7woDrhEjcLWG642qP2X4"
);
export const LARIX_ADAPTER_PROGRAM_ID = new PublicKey("ADPTLQQ1Bwgybb2qge7QKSW7woDrhEjcLWG642qP2X4");

export const LIFINITY_ADAPTER_PROGRAM_ID = new PublicKey(
"ADPTF4WmNPebELw6UvnSVBdL7BAqs5ceg9tyrHsQfrJK"
);
export const LIFINITY_ADAPTER_PROGRAM_ID = new PublicKey("ADPTF4WmNPebELw6UvnSVBdL7BAqs5ceg9tyrHsQfrJK");

export const ORCA_ADAPTER_PROGRAM_ID = new PublicKey(
"ADPTTyNqameXftbqsxwXhbs7v7XP8E82YMaUStPgjmU5"
);
export const ORCA_ADAPTER_PROGRAM_ID = new PublicKey("ADPTTyNqameXftbqsxwXhbs7v7XP8E82YMaUStPgjmU5");

export const KATANA_ADAPTER_PROGRAM_ID = new PublicKey(
"ADPTwDKJTizC3V8gZXDxt5uLjJv4pBnh1nTTf9dZJnS2"
);
export const KATANA_ADAPTER_PROGRAM_ID = new PublicKey("ADPTwDKJTizC3V8gZXDxt5uLjJv4pBnh1nTTf9dZJnS2");

export const FRANCIUM_ADAPTER_PROGRAM_ID = new PublicKey(
"ADPTax5HwQ2ZWVLmceCek8UrqMhwCy5q3SHwi8W71Kv2"
);
export const FRANCIUM_ADAPTER_PROGRAM_ID = new PublicKey("ADPTax5HwQ2ZWVLmceCek8UrqMhwCy5q3SHwi8W71Kv2");

export const FRIKTION_ADAPTER_PROGRAM_ID = new PublicKey(
"ADPTzbsaBdXA3FqXoPHjaTjPfh9kadxxFKxonZihP1Ji"
);
export const FRIKTION_ADAPTER_PROGRAM_ID = new PublicKey("ADPTzbsaBdXA3FqXoPHjaTjPfh9kadxxFKxonZihP1Ji");

export const LIDO_ADAPTER_PROGRAM_ID = new PublicKey("ADPTPxbHbEBo9A8E53P2PZnmw3ZYJuwc8ArQQkbJtqhx");
148 changes: 148 additions & 0 deletions src/protocols/lido.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import * as anchor from "@project-serum/anchor";
import { TOKEN_PROGRAM_ID, getAssociatedTokenAddress } from "@solana/spl-token-v2";
import { DepositParams, GatewayParams, IProtocolVault, PAYLOAD_SIZE, WithdrawParams } from "../types";
import { Gateway } from "@dappio-wonderland/gateway-idls";
import { IVaultInfo, lido } from "@dappio-wonderland/navigator";
import { struct, nu64, u8, u32 } from "buffer-layout";
import { getActivityIndex, sigHash, createATAWithoutCheckIx, getGatewayAuthority } from "../utils";
import { LIDO_ADAPTER_PROGRAM_ID } from "../ids";

export class ProtocolLido implements IProtocolVault {
constructor(
private _connection: anchor.web3.Connection,
private _gatewayProgram: anchor.Program<Gateway>,
private _gatewayStateKey: anchor.web3.PublicKey,
private _gatewayParams: GatewayParams
) {}
async deposit(
params: DepositParams,
vault: IVaultInfo,
userKey: anchor.web3.PublicKey
): Promise<{ txs: anchor.web3.Transaction[]; input: Buffer }> {
// Handle payload input here
const inputLayout = struct([nu64("amount")]);
let payload = Buffer.alloc(PAYLOAD_SIZE);
inputLayout.encode(
{
amount: new anchor.BN(params.depositAmount),
},
payload
);

// Handle transaction here

let preInstructions = [] as anchor.web3.TransactionInstruction[];

const bufferArray = [lido.LIDO_ADDRESS.toBuffer(), Buffer.from("reserve_account")];
const [reserveAccount] = anchor.web3.PublicKey.findProgramAddressSync(bufferArray, lido.LIDO_PROGRAM_ID);
const bufferArrayMint = [lido.LIDO_ADDRESS.toBuffer(), Buffer.from("mint_authority")];
const [mintAuthority] = anchor.web3.PublicKey.findProgramAddressSync(bufferArrayMint, lido.LIDO_PROGRAM_ID);

const recipientStSolAddress = await getAssociatedTokenAddress(vault.shareMint, userKey);

preInstructions.push(await createATAWithoutCheckIx(userKey, vault.shareMint));

const remainingAccounts = [
{ pubkey: lido.LIDO_ADDRESS, isSigner: false, isWritable: true }, // 0
{ pubkey: userKey, isSigner: true, isWritable: true }, // 1 wallet.publicKey
{ pubkey: recipientStSolAddress, isSigner: false, isWritable: true }, // 2
{ pubkey: vault.shareMint, isSigner: false, isWritable: true }, // 3
{ pubkey: reserveAccount, isSigner: false, isWritable: true }, // 4
{ pubkey: mintAuthority, isSigner: false, isWritable: false }, // 5
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, // 6
{ pubkey: anchor.web3.SystemProgram.programId, isSigner: false, isWritable: false }, // 7
];
const txDeposit = await this._gatewayProgram.methods
.deposit()
.accounts({
gatewayState: this._gatewayStateKey,
adapterProgramId: LIDO_ADAPTER_PROGRAM_ID,
baseProgramId: lido.LIDO_PROGRAM_ID,
activityIndex: await getActivityIndex(userKey),
gatewayAuthority: getGatewayAuthority(),
})
.preInstructions(preInstructions)
.remainingAccounts(remainingAccounts)
.transaction();

return { txs: [txDeposit], input: payload };
}

async withdraw(
params: WithdrawParams,
vault: IVaultInfo,
userKey: anchor.web3.PublicKey
): Promise<{ txs: anchor.web3.Transaction[]; input: Buffer }> {
// Handle payload input here
const inputLayout = struct([nu64("amount"), u32("validatorIndex")]);
let payload = Buffer.alloc(PAYLOAD_SIZE);

const vaultInfo = vault as lido.VaultInfo;
const vaultInfoWrapper = new lido.VaultInfoWrapper(vaultInfo);

const heaviestValidatorIndex = vaultInfoWrapper.getHeaviestValidatorIndex();

const heaviestValidator = vaultInfo.validators!.entries[heaviestValidatorIndex];

inputLayout.encode(
{
amount: new anchor.BN(params.withdrawAmount),
// Set validator index.
validatorIndex: heaviestValidatorIndex,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validatorIndex should be retrieved from params?

},
payload
);

// Account to temporarily hold stSOL in
const receivingAccount = anchor.web3.Keypair.generate();

const senderStSolAddress = await getAssociatedTokenAddress(vault.shareMint, userKey);

const bufferArrayStake = [lido.LIDO_ADDRESS.toBuffer(), Buffer.from("stake_authority")];
const [stakeAuthority] = anchor.web3.PublicKey.findProgramAddressSync(bufferArrayStake, lido.LIDO_PROGRAM_ID);

const validatorStakeSeeds = [
lido.LIDO_ADDRESS.toBuffer(),
heaviestValidator.pubkey.toBuffer(),
Buffer.from("validator_stake_account"),
Buffer.from(heaviestValidator.entry.stakeSeeds.begin.toArray("le", 8)),
];

const [validatorStakeAccount] = anchor.web3.PublicKey.findProgramAddressSync(
validatorStakeSeeds,
lido.LIDO_PROGRAM_ID
);

// Set up accounts
const remainingAccounts = [
{ pubkey: lido.LIDO_ADDRESS, isSigner: false, isWritable: true }, // 1
{ pubkey: userKey, isSigner: true, isWritable: false }, // 2
{ pubkey: senderStSolAddress, isSigner: false, isWritable: true }, // 3
{ pubkey: vault.shareMint, isSigner: false, isWritable: true }, // 4
{ pubkey: heaviestValidator.pubkey, isSigner: false, isWritable: false }, // 5
{ pubkey: validatorStakeAccount, isSigner: false, isWritable: true }, // 6
{ pubkey: receivingAccount.publicKey, isSigner: true, isWritable: true }, // 7
{ pubkey: stakeAuthority, isSigner: false, isWritable: false }, // 8
{ pubkey: vaultInfo.validatorList, isSigner: false, isWritable: true }, // 9
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, // 10
{ pubkey: anchor.web3.SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false }, // 11
{ pubkey: anchor.web3.SystemProgram.programId, isSigner: false, isWritable: false }, // 12
{ pubkey: anchor.web3.StakeProgram.programId, isSigner: false, isWritable: false }, // 13
];

// Handle transaction here
const txWithdraw = await this._gatewayProgram.methods
.withdraw()
.accounts({
gatewayState: this._gatewayStateKey,
adapterProgramId: LIDO_ADAPTER_PROGRAM_ID,
baseProgramId: lido.LIDO_PROGRAM_ID,
activityIndex: await getActivityIndex(userKey),
gatewayAuthority: getGatewayAuthority(),
})
.remainingAccounts(remainingAccounts)
.transaction();

return { txs: [txWithdraw], input: payload };
}
}
5 changes: 5 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ export enum SupportedProtocols {
Francium = 9,
Friktion = 10,
Katana = 11,
Lido = 12,
}

export interface RouteInfoExtend extends RouteInfo {
Expand Down Expand Up @@ -458,6 +459,10 @@ export type GatewayParams = TypeDef<
{
name: "poolDirection";
type: "u8";
},
{
name: "validatorIndex";
type: "u32";
}
];
};
Expand Down
Loading