Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions packages/wasm-solana/js/intentBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,11 @@ export function buildFromIntent(
): BuildFromIntentResult {
const result = IntentNamespace.build_from_intent(intent, params) as WasmBuildResult;

// Generated keypair signing happens in Rust (build_from_intent signs
// before returning). Signatures survive the wasm-bindgen boundary
// because WasmTransaction is a heap-allocated Rust object that JS
// holds a handle to — no serialization round-trip.

return {
transaction: Transaction.fromWasm(result.transaction),
generatedKeypairs: result.generatedKeypairs,
Expand Down
9 changes: 9 additions & 0 deletions packages/wasm-solana/js/keypair.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@ export class Keypair {
return this._wasm.to_base58();
}

/**
* Sign a message with this keypair
* @param message - The message bytes to sign
* @returns The 64-byte Ed25519 signature
*/
sign(message: Uint8Array): Uint8Array {
return this._wasm.sign(message);
}

/**
* Get the underlying WASM instance (internal use only)
* @internal
Expand Down
12 changes: 12 additions & 0 deletions packages/wasm-solana/js/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,18 @@ export class Transaction {
return idx ?? null;
}

/**
* Sign this transaction with a base58-encoded Ed25519 secret key.
*
* Derives the public key from the secret, signs the transaction message,
* and places the signature at the correct signer index.
*
* @param secretKeyBase58 - The Ed25519 secret key (32-byte seed) as base58
*/
signWithSecretKey(secretKeyBase58: string): void {
Copy link
Contributor

Choose a reason for hiding this comment

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

@copilot explain how public keys are typed in wasm-utxo

this._wasm.sign_with_secret_key(secretKeyBase58);
}

/**
* Get the underlying WASM instance (internal use only)
* @internal
Expand Down
17 changes: 11 additions & 6 deletions packages/wasm-solana/src/instructions/decode.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Instruction decoding using official Solana interface crates.

use super::types::*;
use crate::intent::AuthorizeType;
use solana_compute_budget_interface::ComputeBudgetInstruction;
use solana_stake_interface::instruction::StakeInstruction;
use solana_system_interface::instruction::SystemInstruction;
Expand Down Expand Up @@ -155,8 +156,10 @@ fn decode_stake_instruction(ctx: InstructionContext) -> ParsedInstruction {
// Accounts: [0] stake, [1] clock, [2] authority, [3] optional custodian
if ctx.accounts.len() >= 3 {
let auth_type = match stake_authorize {
solana_stake_interface::state::StakeAuthorize::Staker => "Staker",
solana_stake_interface::state::StakeAuthorize::Withdrawer => "Withdrawer",
solana_stake_interface::state::StakeAuthorize::Staker => AuthorizeType::Staker,
solana_stake_interface::state::StakeAuthorize::Withdrawer => {
AuthorizeType::Withdrawer
}
};
let custodian = if ctx.accounts.len() >= 4 {
Some(ctx.accounts[3].clone())
Expand All @@ -167,7 +170,7 @@ fn decode_stake_instruction(ctx: InstructionContext) -> ParsedInstruction {
staking_address: ctx.accounts[0].clone(),
old_authorize_address: ctx.accounts[2].clone(),
new_authorize_address: new_authority.to_string(),
authorize_type: auth_type.to_string(),
authorize_type: auth_type,
custodian_address: custodian,
})
} else {
Expand All @@ -178,8 +181,10 @@ fn decode_stake_instruction(ctx: InstructionContext) -> ParsedInstruction {
// Accounts: [0] stake, [1] clock, [2] authority, [3] new_authority (signer), [4] optional custodian
if ctx.accounts.len() >= 4 {
let auth_type = match stake_authorize {
solana_stake_interface::state::StakeAuthorize::Staker => "Staker",
solana_stake_interface::state::StakeAuthorize::Withdrawer => "Withdrawer",
solana_stake_interface::state::StakeAuthorize::Staker => AuthorizeType::Staker,
solana_stake_interface::state::StakeAuthorize::Withdrawer => {
AuthorizeType::Withdrawer
}
};
let custodian = if ctx.accounts.len() >= 5 {
Some(ctx.accounts[4].clone())
Expand All @@ -190,7 +195,7 @@ fn decode_stake_instruction(ctx: InstructionContext) -> ParsedInstruction {
staking_address: ctx.accounts[0].clone(),
old_authorize_address: ctx.accounts[2].clone(),
new_authorize_address: ctx.accounts[3].clone(),
authorize_type: auth_type.to_string(),
authorize_type: auth_type,
custodian_address: custodian,
})
} else {
Expand Down
37 changes: 37 additions & 0 deletions packages/wasm-solana/src/instructions/try_into_js_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,43 @@ use base64::prelude::*;
use wasm_bindgen::JsValue;

use super::types::*;
use crate::intent::{AuthorizeType, KeypairPurpose, StakingType};

// =============================================================================
// Enum → JS string conversions
// =============================================================================

impl TryIntoJsValue for StakingType {
fn try_to_js_value(&self) -> Result<JsValue, JsConversionError> {
let s = match self {
StakingType::Native => "NATIVE",
StakingType::Jito => "JITO",
StakingType::Marinade => "MARINADE",
Comment on lines +21 to +23
Copy link
Contributor

Choose a reason for hiding this comment

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

uppercase here and regular case for the others? I'm guessing this is due to some external interface

};
Ok(JsValue::from_str(s))
}
}

impl TryIntoJsValue for AuthorizeType {
fn try_to_js_value(&self) -> Result<JsValue, JsConversionError> {
let s = match self {
AuthorizeType::Staker => "Staker",
AuthorizeType::Withdrawer => "Withdrawer",
};
Ok(JsValue::from_str(s))
}
}

impl TryIntoJsValue for KeypairPurpose {
fn try_to_js_value(&self) -> Result<JsValue, JsConversionError> {
let s = match self {
KeypairPurpose::StakeAccount => "stakeAccount",
KeypairPurpose::UnstakeAccount => "unstakeAccount",
KeypairPurpose::TransferAuthority => "transferAuthority",
};
Ok(JsValue::from_str(s))
}
}

// =============================================================================
// System Program Params
Expand Down
4 changes: 2 additions & 2 deletions packages/wasm-solana/src/instructions/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ pub struct StakingActivateParams {
pub staking_address: String,
pub amount: u64,
pub validator: String,
pub staking_type: String, // "NATIVE", "JITO", "MARINADE"
pub staking_type: crate::intent::StakingType,
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -152,7 +152,7 @@ pub struct StakingAuthorizeParams {
pub staking_address: String,
pub old_authorize_address: String,
pub new_authorize_address: String,
pub authorize_type: String, // "Staker" or "Withdrawer"
pub authorize_type: crate::intent::AuthorizeType,
pub custodian_address: Option<String>,
}

Expand Down
Loading