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
4 changes: 4 additions & 0 deletions packages/svm/programs/settler/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ pub const DEPLOYER_KEY: &str = env!(
);

pub const CHAIN_ID: u32 = 507424;

pub const DISCRIMINATOR_LEN: usize = 8;

pub const VEC_SIZE_LEN: usize = 4;
6 changes: 6 additions & 0 deletions packages/svm/programs/settler/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ pub enum SettlerError {
#[msg("Incorrect recipient token account: mint or authority do not match expected")]
IncorrectRecipientTokenAccount,

#[msg("Incorrect fee payer token account: mint or authority do not match expected")]
IncorrectFeePayerTokenAccount,

#[msg("Incorrect user token account: mint or authority do not match expected")]
IncorrectUserTokenAccount,

Expand All @@ -125,6 +128,9 @@ pub enum SettlerError {
#[msg("Incorrect token program account provided")]
IncorrectTokenProgram,

#[msg("Incorrect user delegate")]
IncorrectUserDelegate,

#[msg("Math Error")]
MathError,
}
25 changes: 11 additions & 14 deletions packages/svm/programs/settler/src/instructions/create_intent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@ use crate::{
},
errors::SettlerError,
state::Intent,
types::{IntentEvent, OpType, TokenFee},
types::{Operation, TokenFee},
};

#[derive(Accounts)]
// TODO: can we optimize this deser? we just need the three Vec<T> for their length
#[instruction(intent_hash: [u8; 32], data: Vec<u8>, max_fees: Vec<TokenFee>, events: Vec<IntentEvent>, min_validations: u16)]
#[instruction(intent_hash: [u8; 32], operations: Vec<Operation>, max_fees: Vec<TokenFee>, min_validations: u16)]
pub struct CreateIntent<'info> {
#[account(mut)]
pub solver: Signer<'info>,
Expand All @@ -30,10 +29,12 @@ pub struct CreateIntent<'info> {
seeds = [b"intent", intent_hash.as_ref()],
bump,
payer = solver,
space = Intent::total_size(data.len(), max_fees.len(), &events, min_validations.max(controller_settings.min_validations))?
space = Intent::total_size(
max_fees.len(),
&operations,
min_validations.max(controller_settings.min_validations)
)?
)]
// TODO: change to AccountLoader?
// TODO: init within the handler body to save compute?
pub intent: Box<Account<'info, Intent>>,

#[account(
Expand All @@ -56,12 +57,10 @@ pub struct CreateIntent<'info> {
pub fn create_intent(
ctx: Context<CreateIntent>,
intent_hash: [u8; 32],
data: Vec<u8>,
operations: Vec<Operation>,
max_fees: Vec<TokenFee>,
events: Vec<IntentEvent>,
min_validations: u16,
op: OpType,
user: Pubkey,
fee_payer: Pubkey,
nonce: [u8; 32],
deadline: u64,
is_final: bool,
Expand All @@ -75,18 +74,16 @@ pub fn create_intent(
let intent = &mut ctx.accounts.intent;
let controller_min_validations = ctx.accounts.controller_settings.min_validations;

intent.op = op;
intent.user = user;
intent.fee_payer = fee_payer;
intent.creator = ctx.accounts.solver.key();
intent.hash = intent_hash;
intent.nonce = nonce;
intent.deadline = deadline;
intent.min_validations = min_validations.max(controller_min_validations);
intent.is_final = is_final;
intent.data = data;
intent.max_fees = max_fees;
intent.events = events;
intent.validators = vec![];
intent.operations = operations;
intent.bump = ctx.bumps.intent;

Ok(())
Expand Down
38 changes: 23 additions & 15 deletions packages/svm/programs/settler/src/instructions/execute_proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
controller::{self, accounts::EntityRegistry, types::EntityType},
errors::SettlerError,
state::{FulfilledIntent, Intent, Proposal},
types::IntentEvent,
types::OperationEvent,
utils::{handle_intent_execution, pay_solver_fees},
};

Expand Down Expand Up @@ -55,12 +55,27 @@ pub struct ExecuteProposal<'info> {
)]
pub fulfilled_intent: Box<Account<'info, FulfilledIntent>>,

#[account(seeds = [b"delegate", intent.user.key().as_ref()], bump)]
pub delegate: SystemAccount<'info>,
#[account(seeds = [b"delegate", intent.fee_payer.key().as_ref()], bump)]
pub fee_payer_delegate: SystemAccount<'info>,

pub system_program: Program<'info, System>,
}

////////////////////////////////////////////////////////
// REMAINING ACCOUNTS //
// //
// [token_program, token_2022_program] //
// //
// for operation in intent.operations: //
// [user_delegate(operation.user)] //
// //
// for transfer in operation.transfers: //
// [token_mint, recipient, recipient_ta, user_ta] //
// //
// for each fee in proposal.fees / intent.max_fees: //
// [fee_token_mint, solver_ta, fee_payer_ta] //
////////////////////////////////////////////////////////

pub fn execute_proposal<'info>(
ctx: Context<'_, '_, '_, 'info, ExecuteProposal<'info>>,
) -> Result<()> {
Expand All @@ -85,33 +100,26 @@ pub fn execute_proposal<'info>(
handle_intent_execution(
intent,
proposal,
&ctx.accounts.delegate.clone(),
&mut remaining_accounts_iter,
token_program,
token_2022_program,
ctx.bumps.delegate,
ctx.program_id,
)?;

intent.events.iter().for_each(|event| {
emit!(IntentEventEvent {
event: event.clone()
})
});

pay_solver_fees(
&mut remaining_accounts_iter,
intent,
proposal,
token_program,
token_2022_program,
&ctx.accounts.delegate.clone(),
ctx.bumps.delegate,
&ctx.accounts.fee_payer_delegate.clone(),
ctx.bumps.fee_payer_delegate,
)?;

Ok(())
}

#[event]
pub struct IntentEventEvent {
event: IntentEvent,
pub struct OperationEventEvent {
pub event: OperationEvent,
}
21 changes: 10 additions & 11 deletions packages/svm/programs/settler/src/instructions/extend_intent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ use anchor_lang::prelude::*;
use crate::{
errors::SettlerError,
state::Intent,
types::{IntentEvent, TokenFee},
types::{Operation, TokenFee},
};

#[derive(Accounts)]
#[instruction(more_data: Option<Vec<u8>>, more_max_fees: Option<Vec<TokenFee>>, more_events: Option<Vec<IntentEvent>>)]
#[instruction(more_max_fees: Option<Vec<TokenFee>>, more_operations: Option<Vec<Operation>>)]
pub struct ExtendIntent<'info> {
#[account(mut)]
pub creator: Signer<'info>,
Expand All @@ -18,7 +18,11 @@ pub struct ExtendIntent<'info> {
constraint = !intent.is_final @ SettlerError::IntentIsFinal,
constraint = intent.deadline > Clock::get()?.unix_timestamp as u64 @ SettlerError::IntentIsExpired,
realloc =
Intent::extended_size(intent.to_account_info().data_len(), &more_data, &more_max_fees, &more_events)?,
Intent::extended_size(
intent.to_account_info().data_len(),
&more_max_fees,
&more_operations
)?,
realloc::payer = creator,
realloc::zero = true
)]
Expand All @@ -29,23 +33,18 @@ pub struct ExtendIntent<'info> {

pub fn extend_intent(
ctx: Context<ExtendIntent>,
more_data: Option<Vec<u8>>,
more_max_fees: Option<Vec<TokenFee>>,
more_events: Option<Vec<IntentEvent>>,
more_operations: Option<Vec<Operation>>,
finalize: bool,
) -> Result<()> {
let intent = &mut ctx.accounts.intent;

if let Some(_more_data) = more_data {
intent.data.extend_from_slice(&_more_data);
}

if let Some(_more_max_fees) = more_max_fees {
intent.max_fees.extend_from_slice(&_more_max_fees);
}

if let Some(_more_events) = more_events {
intent.events.extend_from_slice(&_more_events);
if let Some(_more_operations) = more_operations {
intent.operations.extend_from_slice(&_more_operations);
}

if finalize {
Expand Down
17 changes: 6 additions & 11 deletions packages/svm/programs/settler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,25 +45,21 @@ pub mod settler {
pub fn create_intent(
ctx: Context<CreateIntent>,
intent_hash: [u8; 32],
data: Vec<u8>,
operations: Vec<Operation>,
max_fees: Vec<TokenFee>,
events: Vec<IntentEvent>,
min_validations: u16,
op: OpType,
user: Pubkey,
fee_payer: Pubkey,
nonce: [u8; 32],
deadline: u64,
is_final: bool,
) -> Result<()> {
instructions::create_intent(
ctx,
intent_hash,
data,
operations,
max_fees,
events,
min_validations,
op,
user,
fee_payer,
nonce,
deadline,
is_final,
Expand All @@ -88,12 +84,11 @@ pub mod settler {

pub fn extend_intent(
ctx: Context<ExtendIntent>,
more_data: Option<Vec<u8>>,
more_max_fees: Option<Vec<TokenFee>>,
more_events: Option<Vec<IntentEvent>>,
more_operations: Option<Vec<Operation>>,
finalize: bool,
) -> Result<()> {
instructions::extend_intent(ctx, more_data, more_max_fees, more_events, finalize)
instructions::extend_intent(ctx, more_max_fees, more_operations, finalize)
}

pub fn initialize(ctx: Context<Initialize>, domain: Eip712Domain) -> Result<()> {
Expand Down
59 changes: 24 additions & 35 deletions packages/svm/programs/settler/src/state/intent.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
use anchor_lang::prelude::*;

use crate::{
types::{IntentEvent, OpType, TokenFee},
constants::{DISCRIMINATOR_LEN, VEC_SIZE_LEN},
types::{Operation, TokenFee},
utils::{add, mul, sub},
};

#[account]
pub struct Intent {
pub op: OpType,
pub user: Pubkey,
pub fee_payer: Pubkey,
pub creator: Pubkey,
pub hash: [u8; 32],
pub nonce: [u8; 32],
pub deadline: u64,
pub min_validations: u16,
pub is_final: bool,
pub validators: Vec<[u8; 20]>, // TODO: how to store more efficiently?
pub data: Vec<u8>,
pub max_fees: Vec<TokenFee>,
pub events: Vec<IntentEvent>,
pub operations: Vec<Operation>,
pub bump: u8,
}

impl Intent {
/// Doesn't take into account size of variable fields
pub const BASE_LEN: usize =
1 + // op
32 + // user
32 + // fee_payer
32 + // creator
32 + // hash
32 + // nonce
Expand All @@ -39,59 +37,50 @@ impl Intent {
pub const VALIDATOR_ADDRESS_SIZE: usize = 20;

pub fn total_size(
data_len: usize,
max_fees_len: usize,
events: &[IntentEvent],
operations: &[Operation],
min_validations: u16,
) -> Result<usize> {
let size = add(8, Intent::BASE_LEN)?;
let size = add(size, Intent::data_size(data_len)?)?;
let size = add(size, Intent::max_fees_size(max_fees_len)?)?;
let size = add(size, Intent::events_size(events)?)?;
let size = add(DISCRIMINATOR_LEN, Intent::BASE_LEN)?;
let size = add(size, Intent::validators_size(min_validations)?)?;
let size = add(size, Intent::max_fees_size(max_fees_len)?)?;
let size = add(size, Intent::operations_size(operations)?)?;
Ok(size)
}

pub fn data_size(len: usize) -> Result<usize> {
add(4, len)
pub fn validators_size(min_validations: u16) -> Result<usize> {
add(
VEC_SIZE_LEN,
mul(min_validations as usize, Self::VALIDATOR_ADDRESS_SIZE)?,
)
}

pub fn max_fees_size(len: usize) -> Result<usize> {
add(4, mul(TokenFee::INIT_SPACE, len)?)
add(VEC_SIZE_LEN, mul(TokenFee::INIT_SPACE, len)?)
}

pub fn events_size(events: &[IntentEvent]) -> Result<usize> {
let sum = events
.iter()
.try_fold(0usize, |acc, e| add(acc, e.size()))?;
add(4, sum)
}

pub fn validators_size(min_validations: u16) -> Result<usize> {
pub fn operations_size(operations: &[Operation]) -> Result<usize> {
add(
4,
mul(min_validations as usize, Self::VALIDATOR_ADDRESS_SIZE)?,
VEC_SIZE_LEN,
operations
.iter()
.try_fold(0usize, |acc, op| add(acc, op.total_size()?))?,
)
}

pub fn extended_size(
size: usize,
more_data: &Option<Vec<u8>>,
more_max_fees: &Option<Vec<TokenFee>>,
more_events: &Option<Vec<IntentEvent>>,
more_operations: &Option<Vec<Operation>>,
) -> Result<usize> {
let mut size = size;

if let Some(v) = more_data {
size = add(size, sub(Intent::data_size(v.len())?, 4)?)?;
}

if let Some(v) = more_max_fees {
size = add(size, sub(Intent::max_fees_size(v.len())?, 4)?)?;
size = add(size, sub(Intent::max_fees_size(v.len())?, VEC_SIZE_LEN)?)?;
}

if let Some(v) = more_events {
size = add(size, sub(Intent::events_size(v)?, 4)?)?;
if let Some(v) = more_operations {
size = add(size, sub(Intent::operations_size(v)?, VEC_SIZE_LEN)?)?;
}

Ok(size)
Expand Down
Loading
Loading