Skip to content

Commit 16773ae

Browse files
committed
Merge branch 'ar-audit-staging' into kurtis/fix-m-mint-create
2 parents e43ee78 + 9aa7510 commit 16773ae

File tree

7 files changed

+144
-107
lines changed

7 files changed

+144
-107
lines changed

programs/earn/src/instructions/admin/initialize.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::{
2020
constants::{ANCHOR_DISCRIMINATOR_SIZE, PORTAL_PROGRAM},
2121
errors::EarnError,
2222
state::{EarnGlobal, GLOBAL_SEED, TOKEN_AUTHORITY_SEED},
23-
utils::{conversion::update_multiplier, token::thaw_token_account},
23+
utils::{conversion::{update_multiplier, index_to_multiplier}, token::thaw_token_account},
2424
};
2525

2626
cfg_if::cfg_if!(
@@ -177,20 +177,20 @@ impl Initialize<'_> {
177177

178178
// Set the multiplier on the m_mint to the current index and timestamp on the old earn program
179179
update_multiplier(
180-
&mut ctx.accounts.m_mint, // mint
181-
&ctx.accounts.global_account.to_account_info(), // authority
182-
&[&[GLOBAL_SEED, &[ctx.bumps.global_account]]], // authority seeds
183-
&ctx.accounts.token_program, // token program
184-
ctx.accounts.old_global_account.index, // index
185-
ctx.accounts.old_global_account.timestamp as i64, // timestamp
180+
&mut ctx.accounts.m_mint, // mint
181+
&ctx.accounts.global_account.to_account_info(), // authority
182+
&[&[GLOBAL_SEED, &[ctx.bumps.global_account]]], // authority seeds
183+
&ctx.accounts.token_program, // token program
184+
index_to_multiplier(ctx.accounts.old_global_account.index)?, // index
185+
ctx.accounts.old_global_account.timestamp as i64, // timestamp
186186
)?;
187187
} else {
188188
update_multiplier(
189189
&mut ctx.accounts.m_mint, // mint
190190
&ctx.accounts.global_account.to_account_info(), // authority
191191
&[&[GLOBAL_SEED, &[ctx.bumps.global_account]]], // authority seeds
192192
&ctx.accounts.token_program, // token program
193-
_current_index, // index
193+
index_to_multiplier(_current_index)?, // index
194194
Clock::get()?.unix_timestamp, // timestamp
195195
)?;
196196
}

programs/earn/src/instructions/portal/propagate_index.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ use anchor_spl::token_interface::{Mint, Token2022};
44

55
// local dependencies
66
use crate::{
7-
constants::INDEX_SCALE_F64,
87
errors::EarnError,
98
state::{EarnGlobal, GLOBAL_SEED},
10-
utils::conversion::{get_scaled_ui_config, update_multiplier},
9+
utils::conversion::{get_scaled_ui_config, update_multiplier, index_to_multiplier},
1110
};
1211

1312
#[derive(Accounts)]
@@ -40,10 +39,10 @@ impl PropagateIndex<'_> {
4039
) -> Result<()> {
4140
let scaled_ui_config = get_scaled_ui_config(&ctx.accounts.m_mint)?;
4241
let current_multiplier: f64 = scaled_ui_config.new_multiplier.into();
43-
let current_index = (INDEX_SCALE_F64 * current_multiplier).trunc() as u64;
42+
let new_multiplier = index_to_multiplier(new_index)?;
4443

45-
// Check if the new index is greater than or equal to the previously seen index.
46-
if new_index >= current_index {
44+
// Check if the new multiplier is greater than or equal to the previously seen multiplier.
45+
if new_multiplier >= current_multiplier {
4746
// If so, update the merkle root if it is non-zero.
4847
// We don't necessarily need the second check if we know updates only come
4948
// from mainnet. However, it provides some protection against staleness
@@ -52,16 +51,16 @@ impl PropagateIndex<'_> {
5251
ctx.accounts.global_account.earner_merkle_root = earner_merkle_root;
5352
}
5453

55-
// If the new index is strictly greater than the current one, update the multiplier.
56-
if new_index > current_index {
54+
// If the new multiplier is strictly greater than the current one, update the multiplier.
55+
if new_multiplier > current_multiplier {
5756
let timestamp = Clock::get()?.unix_timestamp;
5857

5958
update_multiplier(
6059
&mut ctx.accounts.m_mint,
6160
&ctx.accounts.global_account.to_account_info(),
6261
&[&[GLOBAL_SEED, &[ctx.accounts.global_account.bump]]],
6362
&ctx.accounts.token_program,
64-
new_index,
63+
new_multiplier,
6564
timestamp,
6665
)?;
6766

programs/earn/src/utils/conversion.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,9 @@ pub fn update_multiplier<'info>(
1414
authority: &AccountInfo<'info>,
1515
authority_seeds: &[&[&[u8]]],
1616
token_program: &Program<'info, Token2022>,
17-
index: u64,
17+
multiplier: f64,
1818
timestamp: i64,
1919
) -> Result<()> {
20-
let multiplier = (index as f64) / INDEX_SCALE_F64;
21-
2220
// Only update multiplier if the new multiplier is greater than the current multiplier
2321
// Indices in the M protocol are monotonically increasing, but we may receive a stale update
2422
// from another chain.
@@ -137,6 +135,23 @@ pub fn principal_to_amount_up(principal: u64, multiplier: f64) -> Result<u64> {
137135
Ok(amount)
138136
}
139137

138+
pub fn multiplier_to_index(multiplier: f64) -> Result<u64> {
139+
let index: f64 = (INDEX_SCALE_F64 * multiplier).trunc();
140+
141+
if index < 0.0 {
142+
err!(EarnError::MathUnderflow)
143+
} else if index > u64::MAX as f64 {
144+
err!(EarnError::MathOverflow)
145+
} else {
146+
// Convert the f64 index to u64
147+
Ok(index as u64)
148+
}
149+
}
150+
151+
pub fn index_to_multiplier(index: u64) -> Result<f64> {
152+
Ok(index as f64 / INDEX_SCALE_F64)
153+
}
154+
140155
pub fn get_mint_extensions<'info>(
141156
mint: &InterfaceAccount<'info, Mint>,
142157
) -> Result<Vec<spl_token_2022::extension::ExtensionType>> {

programs/portal/src/instructions/admin.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use anchor_lang::prelude::*;
2-
use anchor_spl::{token_2022::spl_token_2022::instruction::AuthorityType, token_interface};
2+
use anchor_spl::{
3+
token_2022::{spl_token_2022::instruction::AuthorityType, Token2022},
4+
token_interface,
5+
};
36

47
use crate::{
58
config::Config,
@@ -9,6 +12,7 @@ use crate::{
912
pending_token_authority::PendingTokenAuthority,
1013
queue::{inbox::InboxRateLimit, outbox::OutboxRateLimit, rate_limit::RateLimitState},
1114
registered_transceiver::RegisteredTransceiver,
15+
TOKEN_AUTHORITY_SEED,
1216
};
1317

1418
// * Transfer ownership
@@ -625,3 +629,38 @@ pub fn set_threshold(ctx: Context<SetThreshold>, threshold: u8) -> Result<()> {
625629
ctx.accounts.config.threshold = threshold;
626630
Ok(())
627631
}
632+
633+
// * Set Mint
634+
#[derive(Accounts)]
635+
pub struct SetMint<'info> {
636+
pub owner: Signer<'info>,
637+
638+
#[account(
639+
mut,
640+
has_one = owner,
641+
constraint = config.paused @ NTTError::NotPaused,
642+
)]
643+
pub config: Account<'info, Config>,
644+
645+
pub mint: InterfaceAccount<'info, token_interface::Mint>,
646+
647+
/// CHECK: This account is validated by its seeds
648+
#[account(
649+
seeds = [TOKEN_AUTHORITY_SEED],
650+
bump,
651+
)]
652+
pub token_authority: UncheckedAccount<'info>,
653+
654+
#[account(
655+
associated_token::mint = mint,
656+
associated_token::authority = token_authority,
657+
associated_token::token_program = Token2022::id(),
658+
)]
659+
pub custody: InterfaceAccount<'info, token_interface::TokenAccount>,
660+
}
661+
662+
pub fn set_mint(ctx: Context<SetMint>) -> Result<()> {
663+
ctx.accounts.config.mint = ctx.accounts.mint.key();
664+
ctx.accounts.config.custody = ctx.accounts.custody.key();
665+
Ok(())
666+
}

programs/portal/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ pub mod portal {
160160
instructions::claim_token_authority(ctx)
161161
}
162162

163+
pub fn set_mint(ctx: Context<SetMint>) -> Result<()> {
164+
instructions::set_mint(ctx)
165+
}
166+
163167
pub fn set_paused(ctx: Context<SetPaused>, pause: bool) -> Result<()> {
164168
instructions::set_paused(ctx, pause)
165169
}

services/cli/main.ts

Lines changed: 25 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ import {
5050
} from '../../sdk/src';
5151
import { createInitializeConfidentialTransferMintInstruction } from './confidential-transfers';
5252
import { Program, BN } from '@coral-xyz/anchor';
53-
import { anchorProvider, keysFromEnv, NttManager } from './utils';
53+
import { anchorProvider, keysFromEnv, NttManager, updatePortalMint } from './utils';
5454
import { MerkleTree } from '../../sdk/src/merkle';
5555
import { bs58 } from '@coral-xyz/anchor/dist/cjs/utils/bytes';
5656
import { sha256 } from '@noble/hashes/sha2';
@@ -84,7 +84,7 @@ async function main() {
8484
.command('print-addresses')
8585
.description('Print the addresses of all the relevant programs and accounts')
8686
.action(() => {
87-
const [mMint, wmMint, multisig] = keysFromEnv(['M_MINT_KEYPAIR', 'WM_MINT_KEYPAIR', 'M_MINT_MULTISIG_KEYPAIR']);
87+
const [mMint, wmMint] = keysFromEnv(['M_MINT_KEYPAIR', 'WM_MINT_KEYPAIR']);
8888
const [portalTokenAuthPda] = PublicKey.findProgramAddressSync([Buffer.from('token_authority')], PROGRAMS.portal);
8989
const [earnTokenAuthPda] = PublicKey.findProgramAddressSync([Buffer.from('token_authority')], PROGRAMS.earn);
9090
const [portalEmitter] = PublicKey.findProgramAddressSync([Buffer.from('emitter')], PROGRAMS.portal);
@@ -100,7 +100,6 @@ async function main() {
100100
'Earn Program': PROGRAMS.earn,
101101
'Swap Program': PROGRAMS.swap,
102102
'M Mint': mMint.publicKey,
103-
'M Mint Multisig': multisig.publicKey,
104103
'Portal Token Authority': portalTokenAuthPda,
105104
'Earn Token Authority': earnTokenAuthPda,
106105
'wM Mint': wmMint.publicKey,
@@ -367,92 +366,14 @@ async function main() {
367366

368367
program.command('update-portal-mint').action(async () => {
369368
const [payer, mint] = keysFromEnv(['PAYER_KEYPAIR', 'M_MINT_KEYPAIR']);
370-
const admin = process.env.SQUADS_VAULT ? new PublicKey(process.env.SQUADS_VAULT) : payer.publicKey;
371369
const { ntt } = NttManager(connection, payer, mint.publicKey);
372370

373-
const tx = new Transaction().add(
374-
new TransactionInstruction({
375-
programId: PROGRAMS.portal,
376-
keys: [
377-
{
378-
pubkey: admin,
379-
isSigner: true,
380-
isWritable: false,
381-
},
382-
{
383-
pubkey: ntt.pdas.configAccount(),
384-
isSigner: false,
385-
isWritable: true,
386-
},
387-
{
388-
pubkey: mint.publicKey,
389-
isSigner: false,
390-
isWritable: false,
391-
},
392-
],
393-
data: Buffer.concat([Buffer.from(sha256('global:set_mint').subarray(0, 8))]),
394-
}),
395-
);
396-
397-
tx.feePayer = admin;
398-
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
399-
371+
let owner = payer.publicKey;
400372
if (process.env.SQUADS_VAULT) {
401-
const b = tx.serialize({ verifySignatures: false });
402-
console.log('Transaction:', {
403-
b64: b.toString('base64'),
404-
b58: bs58.encode(b),
405-
});
406-
} else {
407-
const sig = await connection.sendTransaction(tx, [payer]);
408-
console.log(`Updated mint: ${sig}`);
373+
owner = new PublicKey(process.env.SQUADS_VAULT);
409374
}
410-
});
411-
412-
program.command('initialize-portal-resolver').action(async () => {
413-
const [payer, mint] = keysFromEnv(['PAYER_KEYPAIR', 'M_MINT_KEYPAIR']);
414-
const admin = process.env.SQUADS_VAULT ? new PublicKey(process.env.SQUADS_VAULT) : payer.publicKey;
415-
const { ntt } = NttManager(connection, payer, mint.publicKey);
416-
const swapLUT = new PublicKey('9JLRqBqkznKiSoNfotA4ywSRdnWb2fE76SiFrAfkaRCD');
417-
418-
const tx = new Transaction().add(
419-
new TransactionInstruction({
420-
programId: PROGRAMS.portal,
421-
keys: [
422-
{
423-
pubkey: admin,
424-
isSigner: true,
425-
isWritable: true,
426-
},
427-
{
428-
pubkey: ntt.pdas.configAccount(),
429-
isSigner: false,
430-
isWritable: true,
431-
},
432-
{
433-
pubkey: PublicKey.findProgramAddressSync(
434-
[Buffer.from('executor-account-resolver:result')],
435-
PROGRAMS.portal,
436-
)[0],
437-
isSigner: false,
438-
isWritable: true,
439-
},
440-
{
441-
pubkey: SystemProgram.programId,
442-
isSigner: false,
443-
isWritable: false,
444-
},
445-
],
446-
data: Buffer.concat([
447-
Buffer.from(sha256('global:initialize_resolver_accounts').subarray(0, 8)),
448-
Buffer.from([1]),
449-
swapLUT.toBuffer(),
450-
]),
451-
}),
452-
);
453375

454-
tx.feePayer = admin;
455-
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
376+
const tx = new Transaction().add(updatePortalMint(owner, ntt.pdas.configAccount(), mint.publicKey));
456377

457378
if (process.env.SQUADS_VAULT) {
458379
const b = tx.serialize({ verifySignatures: false });
@@ -462,7 +383,7 @@ async function main() {
462383
});
463384
} else {
464385
const sig = await connection.sendTransaction(tx, [payer]);
465-
console.log(`Initialized resolver: ${sig}`);
386+
console.log(`Paused: ${sig}`);
466387
}
467388
});
468389

@@ -588,6 +509,25 @@ async function main() {
588509
}
589510
});
590511

512+
program.command('pause-bridging').action(async () => {
513+
const [payer, mint] = keysFromEnv(['PAYER_KEYPAIR', 'M_MINT_KEYPAIR']);
514+
const { ntt, sender } = NttManager(connection, payer, mint.publicKey);
515+
516+
const pauseTxn = (await ntt.pause(sender).next()).value as SolanaUnsignedTransaction<'Mainnet', 'Solana'>;
517+
const tx = pauseTxn.transaction.transaction as Transaction;
518+
519+
if (process.env.SQUADS_VAULT) {
520+
const b = tx.serialize({ verifySignatures: false });
521+
console.log('Transaction:', {
522+
b64: b.toString('base64'),
523+
b58: bs58.encode(b),
524+
});
525+
} else {
526+
const sig = await connection.sendTransaction(tx, [payer]);
527+
console.log(`Paused: ${sig}`);
528+
}
529+
});
530+
591531
program
592532
.command('pause-bridging')
593533
.option('-u, --unpause', 'Unpause if already paused')

services/cli/utils.ts

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { Keypair, Connection, PublicKey } from '@solana/web3.js';
1+
import { Keypair, Connection, PublicKey, TransactionInstruction } from '@solana/web3.js';
22
import { SolanaNtt } from '@wormhole-foundation/sdk-solana-ntt';
33
import { SolanaPlatform, SolanaSendSigner } from '@wormhole-foundation/sdk-solana';
4-
import { AccountAddress, Wormhole } from '@wormhole-foundation/sdk';
4+
import { AccountAddress, sha256, Wormhole } from '@wormhole-foundation/sdk';
55
import { AnchorProvider, Wallet } from '@coral-xyz/anchor';
6+
import { getAssociatedTokenAddressSync, TOKEN_2022_PROGRAM_ID } from '@solana/spl-token';
67

78
const PORTAL = new PublicKey('mzp1q2j5Hr1QuLC3KFBCAUz5aUckT6qyuZKZ3WJnMmY');
89

@@ -45,3 +46,42 @@ export function anchorProvider(connection: Connection, owner: Keypair) {
4546
skipPreflight: false,
4647
});
4748
}
49+
50+
export function updatePortalMint(owner: PublicKey, config: PublicKey, mMint: PublicKey): TransactionInstruction {
51+
return new TransactionInstruction({
52+
programId: PORTAL,
53+
keys: [
54+
{
55+
pubkey: owner,
56+
isSigner: true,
57+
isWritable: false,
58+
},
59+
{
60+
pubkey: config,
61+
isSigner: false,
62+
isWritable: true,
63+
},
64+
{
65+
pubkey: mMint,
66+
isSigner: false,
67+
isWritable: false,
68+
},
69+
{
70+
pubkey: PublicKey.findProgramAddressSync([Buffer.from('token_authority')], PORTAL)[0],
71+
isSigner: false,
72+
isWritable: false,
73+
},
74+
{
75+
pubkey: getAssociatedTokenAddressSync(
76+
mMint,
77+
PublicKey.findProgramAddressSync([Buffer.from('token_authority')], PORTAL)[0],
78+
true,
79+
TOKEN_2022_PROGRAM_ID,
80+
),
81+
isSigner: false,
82+
isWritable: false,
83+
},
84+
],
85+
data: Buffer.concat([Buffer.from(sha256('global:set_mint').subarray(0, 8))]),
86+
});
87+
}

0 commit comments

Comments
 (0)