Skip to content

Commit

Permalink
Merge branch 'develop' into feature/FRONT-362-refactor-vue-example
Browse files Browse the repository at this point in the history
  • Loading branch information
Tkachez committed Jan 30, 2025
2 parents 261470e + 6b4ebb5 commit 6b1b42d
Show file tree
Hide file tree
Showing 8 changed files with 634 additions and 4 deletions.
33 changes: 31 additions & 2 deletions packages/core/src/mint-transfer.mainnet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
authAccountAddress,
collateralPoolAddress,
neonBalanceProgramAddress,
neonBalanceProgramAddressV2, Provider,
neonBalanceProgramAddressV2,
Provider,
toBytesInt32,
TransactionResult
} from './utils';
Expand Down Expand Up @@ -93,7 +94,35 @@ export async function neonTransferMintTransactionMainnet<W extends Provider, TxR
return transaction;
}


/**
* Creates a mainnet-compatible execution instruction from raw transaction data for Neon EVM.
*
* This function generates a `TransactionInstruction` for executing a Neon EVM transaction
* within the Solana blockchain on **mainnet**. It derives necessary accounts, encodes transaction data,
* and constructs the instruction with the appropriate keys.
*
* @param {PublicKey} solanaWallet - The public key of the Solana wallet initiating the transaction.
* @param {string} neonWallet - The Ethereum-style Neon wallet address in hex format.
* @param {PublicKey} neonEvmProgram - The public key of the Neon EVM program.
* @param {string} neonRawTransaction - The raw Neon transaction in hex format.
* @param {AccountMeta[]} neonKeys - The list of required account metadata.
* @param {number} chainId - The chain ID of the target blockchain.
* @param {number} [neonPoolCount=NEON_TREASURY_POOL_COUNT] - The number of Neon treasury pools (optional, defaults to `NEON_TREASURY_POOL_COUNT`).
* @returns {TransactionInstruction} A Solana `TransactionInstruction` for executing the Neon transaction on **mainnet**.
*
* @example
* ```typescript
* const instruction = createExecFromDataInstructionV2Mainnet(
* userWallet,
* "0x1234567890abcdef1234567890abcdef12345678",
* neonProgram,
* "0xabcdef...",
* accountKeys,
* 245022926
* );
* transaction.add(instruction);
* ```
*/
export function createExecFromDataInstructionV2Mainnet(solanaWallet: PublicKey, neonWallet: string, neonEvmProgram: PublicKey, neonRawTransaction: string, neonKeys: AccountMeta[], chainId: number, neonPoolCount = NEON_TREASURY_POOL_COUNT): TransactionInstruction {
const count = Number(neonPoolCount ?? NEON_TREASURY_POOL_COUNT);
const treasuryPoolIndex = Math.floor(Math.random() * count) % count;
Expand Down
278 changes: 277 additions & 1 deletion packages/core/src/mint-transfer.ts

Large diffs are not rendered by default.

47 changes: 47 additions & 0 deletions packages/core/src/neon-transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,36 @@ export async function solanaNEONTransferTransaction({
return transaction;
}

/**
* Creates a Solana transaction instruction to deposit tokens into a Neon EVM balance.
*
* This function generates a `TransactionInstruction` that facilitates the deposit of SPL tokens
* into a Neon EVM balance.
*
* @param {NeonDepositToBalanceInstructionParams} params - The parameters required for the deposit transaction.
* @param {number} params.chainId - The chain ID of the target blockchain.
* @param {PublicKey} params.solanaWallet - The public key of the Solana wallet initiating the transaction.
* @param {PublicKey} params.tokenAddress - The public key of the source token account.
* @param {string} params.neonWallet - The Ethereum-style Neon wallet address in hex format.
* @param {PublicKey} params.neonEvmProgram - The public key of the Neon EVM program.
* @param {PublicKey} params.tokenMint - The public key of the SPL token mint.
* @param {PublicKey} [params.serviceWallet] - The optional service wallet used for operational transactions.
* @returns {TransactionInstruction} A Solana `TransactionInstruction` for depositing tokens into the Neon EVM balance.
*
* @example
* ```typescript
* const instruction = createNeonDepositToBalanceInstruction({
* chainId: 245022926,
* solanaWallet: userWallet,
* tokenAddress: userTokenAccount,
* neonWallet: "0x1234567890abcdef1234567890abcdef12345678",
* neonEvmProgram: neonProgram,
* tokenMint: tokenMintAddress,
* serviceWallet: serviceWalletAddress
* });
* transaction.add(instruction);
* ```
*/
export function createNeonDepositToBalanceInstruction({
chainId,
solanaWallet,
Expand Down Expand Up @@ -132,6 +162,23 @@ export function createNeonDepositToBalanceInstruction({
return new TransactionInstruction({ programId: neonEvmProgram, keys, data });
}

/**
* Not used
*
* Creates a Solana transaction instruction to deposit tokens into a Neon EVM account.
*
* This function generates a `TransactionInstruction` that facilitates the deposit of SPL tokens
* into a Neon EVM-compatible account.
*
* @param {PublicKey} solanaWallet - The public key of the Solana wallet initiating the deposit.
* @param {PublicKey} neonPDAWallet - The public key of the Neon PDA wallet.
* @param {PublicKey} depositWallet - The public key of the deposit wallet.
* @param {string} neonWallet - The Ethereum-style Neon wallet address in hex format.
* @param {PublicKey} neonEvmProgram - The public key of the Neon EVM program.
* @param {PublicKey} neonTokenMint - The public key of the SPL token mint.
* @param {PublicKey} [serviceWallet] - The optional service wallet used for operational transactions.
* @returns {TransactionInstruction} A Solana `TransactionInstruction` for depositing tokens into the Neon EVM account.
*/
export function createNeonDepositInstruction(solanaWallet: PublicKey, neonPDAWallet: PublicKey, depositWallet: PublicKey, neonWallet: string, neonEvmProgram: PublicKey, neonTokenMint: PublicKey, serviceWallet?: PublicKey): TransactionInstruction {
const solanaAssociatedTokenAddress = getAssociatedTokenAddressSync(neonTokenMint, solanaWallet);
const poolKey = getAssociatedTokenAddressSync(neonTokenMint, depositWallet, true);
Expand Down
78 changes: 77 additions & 1 deletion packages/core/src/utils/addresses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@ import { AccountHex, SPLToken } from '../models';
import { randRange, toBytesInt32, toU256BE } from './amount';
import { isValidHex } from './hex';

/**
* Derives a valid program address, that fall off the ed25519 curve,
* for a given Neon wallet (Ethereum-style address) and Neon EVM program.
*
* @param {string} etherKey - The Ethereum-style wallet address in hex format.
* @param {PublicKey} neonEvmProgram - The public key of the Neon EVM program.
* @returns {[PublicKey, number]} A tuple containing the derived public key and a nonce.
*
* @example
* ```typescript
* const [walletPDA] = neonWalletProgramAddress(userEtherAddress, neonEvmProgram);
* ```
*/
export function neonWalletProgramAddress(etherKey: string, neonEvmProgram: PublicKey): [PublicKey, number] {
const keyBuffer = Buffer.from(isValidHex(etherKey) ? etherKey.replace(/^0x/i, '') : etherKey, 'hex');
const seed = [new Uint8Array([AccountHex.SeedVersion]), new Uint8Array(keyBuffer)];
Expand Down Expand Up @@ -30,7 +43,19 @@ export function neonBalanceProgramAddress(etherKey: string, neonEvmProgram: Publ
return PublicKey.findProgramAddressSync(seed, neonEvmProgram);
}

//Only for the Solana -> NEON SPL transfer
/**
* Computes the program address for a NEON token balance.
* Used for SPL tokens transfer from Solana to NeonEVM.
*
* This function generates a program address based on the provided Ethereum address, operator address, the NEON EVM program, and chain ID.
* It is used to identify the NEON token balance associated with the provided address on the given chain.
*
* @param etherKey - The Ethereum address, provided as a hexadecimal string. This should be the address for which the NEON balance is queried.
* @param operatorKey - The payer address as a `PublicKey` = Solana wallet.
* @param neonEvmProgram - The NEON EVM program address as a `PublicKey`.
* @param chainId - The ID of the blockchain network where the NEON token is being used.
* @returns A tuple containing the derived program `PublicKey` and a bump seed number used in the derivation process.
*/
export function neonBalanceProgramAddressV2(etherKey: string, operatorKey: PublicKey, neonEvmProgram: PublicKey, chainId: number): [PublicKey, number] {
const keyBuffer = Buffer.from(isValidHex(etherKey) ? etherKey.replace(/^0x/i, '') : etherKey, 'hex');
const chainIdBytes = toU256BE(BigInt(chainId)); //chain_id as u256be
Expand All @@ -42,6 +67,19 @@ export function neonBalanceProgramAddressV2(etherKey: string, operatorKey: Publi
return PublicKey.findProgramAddressSync(seed, neonEvmProgram);
}

/**
* Generates an authenticated account address for a given Neon wallet, Neon EVM program, and SPL token.
*
* @param {string} neonWallet - The Neon wallet address in hex format.
* @param {PublicKey} neonEvmProgram - The public key of the Neon EVM program.
* @param {SPLToken} splToken - The SPL token object containing the token address.
* @returns {[PublicKey, number]} A tuple containing the derived public key and a nonce.
*
* @example
* ```typescript
* const [delegatePDA] = authAccountAddress(emulateSigner.address, neonEvmProgram, splToken);
* ```
*/
export function authAccountAddress(neonWallet: string, neonEvmProgram: PublicKey, splToken: SPLToken): [PublicKey, number] {
const neonAccountAddressBytes = Buffer.concat([Buffer.alloc(12), Buffer.from(isValidHex(neonWallet) ? neonWallet.replace(/^0x/i, '') : neonWallet, 'hex')]);
const neonContractAddressBytes = Buffer.from(isValidHex(splToken.address) ? splToken.address.replace(/^0x/i, '') : splToken.address, 'hex');
Expand All @@ -53,16 +91,54 @@ export function authAccountAddress(neonWallet: string, neonEvmProgram: PublicKey
return PublicKey.findProgramAddressSync(seed, neonEvmProgram);
}

/**
* Derives the program address for a collateral pool associated with a Neon wallet PDA.
*
* @param {PublicKey} neonWalletPDA - The public key of the Neon wallet PDA.
* @param {number} collateralPoolIndex - The index of the collateral pool.
* @returns {[PublicKey, number]} A tuple containing the derived public key and a nonce.
*
* @example
* ```typescript
* const [poolAddress] = collateralPoolAddress(walletPDA, 0);
* ```
*/
export function collateralPoolAddress(neonWalletPDA: PublicKey, collateralPoolIndex: number): [PublicKey, number] {
const a = Buffer.from('treasury_pool', 'utf8');
const b = Buffer.from(toBytesInt32(collateralPoolIndex));
return PublicKey.findProgramAddressSync([a, b], neonWalletPDA);
}

/**
* Derives the authority pool program address for a given program ID.
*
* @param {PublicKey} programId - The public key of the program.
* @returns {[PublicKey, number]} A tuple containing the derived public key and a nonce.
*
* @example
* ```typescript
* const [authorityAddress] = authorityPoolAddress(myProgramId);
* ```
*/
export function authorityPoolAddress(programId: PublicKey): [PublicKey, number] {
return PublicKey.findProgramAddressSync([new Uint8Array(Buffer.from('Deposit', 'utf-8'))], programId);
}

/**
* Generates a unique holder account address using a seeded derivation method.
*
* @param {PublicKey} neonEvmProgram - The public key of the Neon EVM program.
* @param {PublicKey} solanaWallet - The public key of the Solana wallet.
* @returns {Promise<[PublicKey, string]>} A promise that resolves to a tuple containing:
* - The derived public key of the holder account.
* - The seed used for derivation.
*
* @example
* ```typescript
* const [holderAddress, seed] = await holderAccountData(neonEvmProgram, solanaWallet);
* console.log(`Holder Address: ${holderAddress.toBase58()}, Seed: ${seed}`);
* ```
*/
export async function holderAccountData(neonEvmProgram: PublicKey, solanaWallet: PublicKey): Promise<[PublicKey, string]> {
const seed = randRange(0, 1000000).toString();
const holder = await PublicKey.createWithSeed(solanaWallet, seed, neonEvmProgram);
Expand Down
26 changes: 26 additions & 0 deletions packages/core/src/utils/amount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ export function toBigInt(amount: Amount): bigint {
return BigInt(data.toString());
}

/**
* Converts a given number into a 64-bit little-endian representation as a `Uint8Array`.
*
* @param {number} num - The number to be converted to 64-bit little-endian format.
* @returns {Uint8Array} A `Uint8Array` representing the 64-bit little-endian encoded value.
*
* @example
* ```typescript
* const littleEndianBytes = numberTo64BitLittleEndian(123456789);
* console.log(littleEndianBytes);
* ```
*/
export function numberTo64BitLittleEndian(num: number): Uint8Array {
const buffer = new ArrayBuffer(8); // 64 bits = 8 bytes
const view = new DataView(buffer);
Expand All @@ -39,6 +51,20 @@ export function numberTo64BitLittleEndian(num: number): Uint8Array {
return new Uint8Array(buffer);
}

/**
* Converts a `bigint` number into a 256-bit big-endian (`U256BE`) representation as a `Uint8Array`.
*
* @param {bigint} bigIntNumber - The `bigint` number to be converted to a 256-bit big-endian format.
* @throws {Error} If the number is out of range for a 256-bit unsigned integer.
* @returns {Uint8Array} A `Uint8Array` representing the 256-bit big-endian encoded value.
*
* @example
* ```typescript
* const bigIntValue = BigInt('123456789012345678901234567890');
* const u256Bytes = toU256BE(bigIntValue);
* console.log(u256Bytes);
* ```
*/
export function toU256BE(bigIntNumber: bigint) {
if (bigIntNumber < BigInt(0) || bigIntNumber > BigInt('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF')) {
throw new Error('Number out of range for U256BE');
Expand Down
38 changes: 38 additions & 0 deletions packages/ethers/src/mint-transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,44 @@ export async function createMintNeonTransactionEthers({
return transaction;
}

/**
* Creates a Solana transaction to wrap SOL into wSOL and transfer it to Neon EVM.
*
* This function performs the following operations:
* 1. Wraps **SOL into wSOL** by creating an associated token account (if necessary),
* transferring SOL, and syncing the native balance.
* 2. **Generates a Neon transaction** to transfer **0.1 wSOL** from Solana to Neon.
* 3. **Creates and signs a transaction** using an Ethers wallet for Neon EVM.
* 4. **Adds all necessary instructions** to the Solana transaction and returns it.
*
* @param {MintTransferParams<Wallet>} params - The parameters required for the transaction.
* @param {Connection} params.connection - The Solana blockchain connection.
* @param {ProxyApi} params.proxyApi - The API interface for interacting with the proxy.
* @param {PublicKey} params.neonEvmProgram - The public key of the Neon EVM program.
* @param {PublicKey} params.solanaWallet - The Solana wallet public key initiating the transfer.
* @param {string} params.neonWallet - The Ethereum-style Neon wallet address.
* @param {Wallet} params.walletSigner - The Ethers.js wallet used for signing Neon transactions - private key for a signer based on the Neon and Solana wallet addresses.
* @param {SPLToken} params.splToken - The SPL token details for wSOL.
* @param {Amount} params.amount - The amount of wSOL to transfer (expected to be **0.1 wSOL**).
* @param {number} params.chainId - The chain ID of the target blockchain.
* @param {number} [params.neonHeapFrame=NEON_HEAP_FRAME] - The heap frame size for Neon transaction execution.
* @returns {Promise<Transaction>} A Solana `Transaction` that wraps SOL to wSOL and transfers it to Neon.
*
* @example
* ```typescript
* const transaction = await createWrapAndTransferSOLTransaction({
* connection,
* proxyApi,
* neonEvmProgram,
* solanaWallet: userWallet,
* neonWallet: "0xNeonWalletAddress",
* walletSigner: ethersSigner,
* splToken: wSolToken,
* amount: "0.1",
* chainId: 245022926
* });
* ```
*/
export async function createWrapAndTransferSOLTransaction(params: MintTransferParams<Wallet>): Promise<Transaction> {
const { connection, proxyApi, neonEvmProgram, solanaWallet, neonWallet, walletSigner, splToken, amount, chainId, neonHeapFrame = NEON_HEAP_FRAME } = params;
const instructions: TransactionInstruction[] = [];
Expand Down
44 changes: 44 additions & 0 deletions packages/ethers/src/utils/contracts.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,58 @@
import { erc20Abi, neonWrapper2Abi, neonWrapperAbi } from '@neonevm/token-transfer-core';
import { Interface } from 'ethers';

/**
* Returns an Ethereum `Interface` instance for interacting with an ERC-20 token contract.
*
* This function creates an `Interface` using the standard ERC-20 ABI, enabling interactions
* with ERC-20 compliant tokens.
*
* @returns {Interface} An Ethers.js `Interface` instance for the ERC-20 contract.
*
* @example
* ```typescript
* const erc20Interface = erc20ForSPLContract();
* erc20Interface.encodeFunctionData('transferSolana', [associatedToken.toBuffer(), fullAmount]);
* ```
*/
export function erc20ForSPLContract(): Interface {
return new Interface(erc20Abi);
}

/**
* Returns an Ethereum `Interface` instance for interacting with the Neon wrapper contract.
*
* This function initializes an `Interface` using the Neon wrapper contract ABI,
* enabling interactions with the Neon token contract.
*
* @returns {Interface} An Ethers.js `Interface` instance for the Neon wrapper contract.
*
* @example
* ```typescript
* const neonWrapper = neonWrapperContract();
* neonWrapper.encodeFunctionData('withdraw', [solanaWallet.toBuffer()]);
* ```
*/
export function neonWrapperContract(): Interface {
return new Interface(neonWrapperAbi);
}

/**
* Returns an Ethereum `Interface` instance for interacting with the wrapped Neon contract.
* Used for withdraw wNEON from the NeonEVM to Solana.
*
* This function initializes an `Interface` using the wrapped Neon contract ABI,
* allowing interactions with the wrapped Neon token contract.
*
*
* @returns {Interface} An Ethers.js `Interface` instance for the wrapped Neon contract.
*
* @example
* ```typescript
* const neonWrapperV2 = neonWrapper2Contract();
* neonWrapperV2.encodeFunctionData('withdraw', [parseUnits(amount.toString(), token.decimals)]);
* ```
*/
export function neonWrapper2Contract(): Interface {
return new Interface(neonWrapper2Abi);
}
Loading

0 comments on commit 6b1b42d

Please sign in to comment.