Skip to content

Commit

Permalink
Merge pull request #98 from cardinal-labs/payment-manager
Browse files Browse the repository at this point in the history
Payment manager
  • Loading branch information
jpbogle authored Mar 12, 2022
2 parents 1751c93 + f8c47af commit 77414ce
Show file tree
Hide file tree
Showing 15 changed files with 200 additions and 39 deletions.
2 changes: 2 additions & 0 deletions programs/cardinal-paid-claim-approver/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use anchor_lang::prelude::*;
pub enum ErrorCode {
#[msg("Token account not owned by the claim approver")]
InvalidPaymentTokenAccount,
#[msg("Token account incorrect mint")]
InvalidPaymentManagerTokenAccount,
#[msg("Token account not owned by the payer")]
InvalidPayerTokenAccount,
#[msg("Invalid token manager for this claim approver")]
Expand Down
17 changes: 15 additions & 2 deletions programs/cardinal-paid-claim-approver/src/instructions/pay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use {
crate::{state::*, errors::ErrorCode},
anchor_lang::{prelude::*},
anchor_spl::{token::{self, Token, TokenAccount, Transfer}},
cardinal_token_manager::{program::CardinalTokenManager, state::TokenManager, utils::assert_payment_token_account},
cardinal_token_manager::{program::CardinalTokenManager, state::{TokenManager, PROVIDER_FEE, RECIPIENT_FEE, FEE_SCALE, assert_payment_manager}, utils::assert_payment_token_account},
};

#[derive(Accounts)]
Expand All @@ -12,6 +12,8 @@ pub struct PayCtx<'info> {

#[account(mut, constraint = payment_token_account.mint == claim_approver.payment_mint @ ErrorCode::InvalidPaymentTokenAccount)]
payment_token_account: Box<Account<'info, TokenAccount>>,
#[account(mut, constraint = payment_manager_token_account.mint == claim_approver.payment_mint && assert_payment_manager(&payment_manager_token_account.owner) @ ErrorCode::InvalidPaymentManagerTokenAccount)]
payment_manager_token_account: Box<Account<'info, TokenAccount>>,

#[account(mut)]
claim_approver: Box<Account<'info, PaidClaimApprover>>,
Expand All @@ -38,14 +40,25 @@ pub fn handler(ctx: Context<PayCtx>) -> Result<()> {
let remaining_accs = &mut ctx.remaining_accounts.iter();
assert_payment_token_account(&ctx.accounts.payment_token_account, &ctx.accounts.token_manager, remaining_accs)?;

let provider_fee = ctx.accounts.claim_approver.payment_amount * (PROVIDER_FEE / FEE_SCALE);
let recipient_fee = ctx.accounts.claim_approver.payment_amount * (RECIPIENT_FEE / FEE_SCALE);
let cpi_accounts = Transfer {
from: ctx.accounts.payer_token_account.to_account_info(),
to: ctx.accounts.payment_manager_token_account.to_account_info(),
authority: ctx.accounts.payer.to_account_info(),
};
let cpi_program = ctx.accounts.token_program.to_account_info();
let cpi_context = CpiContext::new(cpi_program, cpi_accounts);
token::transfer(cpi_context, provider_fee + recipient_fee)?;

let cpi_accounts = Transfer {
from: ctx.accounts.payer_token_account.to_account_info(),
to: ctx.accounts.payment_token_account.to_account_info(),
authority: ctx.accounts.payer.to_account_info(),
};
let cpi_program = ctx.accounts.token_program.to_account_info();
let cpi_context = CpiContext::new(cpi_program, cpi_accounts);
token::transfer(cpi_context, ctx.accounts.claim_approver.payment_amount)?;
token::transfer(cpi_context, ctx.accounts.claim_approver.payment_amount - recipient_fee)?;

let token_manager_key = ctx.accounts.token_manager.key();
let claim_approver_seeds = &[PAID_CLAIM_APPROVER_SEED.as_bytes(), token_manager_key.as_ref(), &[ctx.accounts.claim_approver.bump]];
Expand Down
4 changes: 3 additions & 1 deletion programs/cardinal-time-invalidator/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,7 @@ pub enum ErrorCode {
#[msg("Invalid payment mint on time invalidator")]
InvalidPaymentMint,
#[msg("Invalid extension partial duration not allowed")]
InvalidExtensionAmount
InvalidExtensionAmount,
#[msg("Token account incorrect mint")]
InvalidPaymentManagerTokenAccount,
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use {
crate::{errors::ErrorCode, state::*},
anchor_lang::prelude::*,
anchor_spl::token::{self, Token, TokenAccount, Transfer},
cardinal_token_manager::{state::{TokenManager, TokenManagerState}, utils::assert_payment_token_account},
cardinal_token_manager::{state::{TokenManager, TokenManagerState, PROVIDER_FEE, RECIPIENT_FEE, FEE_SCALE, assert_payment_manager}, utils::assert_payment_token_account},
};

#[derive(Accounts)]
Expand All @@ -15,6 +15,8 @@ pub struct ExtendExpirationCtx<'info> {

#[account(mut, constraint = payment_token_account.mint == time_invalidator.extension_payment_mint.unwrap() @ ErrorCode::InvalidPaymentTokenAccount)]
payment_token_account: Box<Account<'info, TokenAccount>>,
#[account(mut, constraint = payment_manager_token_account.mint == time_invalidator.extension_payment_mint.unwrap() && assert_payment_manager(&payment_manager_token_account.owner) @ ErrorCode::InvalidPaymentManagerTokenAccount)]
payment_manager_token_account: Box<Account<'info, TokenAccount>>,

#[account(mut)]
payer: Signer<'info>,
Expand Down Expand Up @@ -59,6 +61,17 @@ pub fn handler(ctx: Context<ExtendExpirationCtx>, payment_amount: u64) -> Result
return Err(error!(ErrorCode::InvalidExtendExpiration));
}

let provider_fee = time_invalidator.extension_payment_amount.unwrap() * (PROVIDER_FEE / FEE_SCALE);
let recipient_fee = time_invalidator.extension_payment_amount.unwrap() * (RECIPIENT_FEE / FEE_SCALE);
let cpi_accounts = Transfer {
from: ctx.accounts.payer_token_account.to_account_info(),
to: ctx.accounts.payment_manager_token_account.to_account_info(),
authority: ctx.accounts.payer.to_account_info(),
};
let cpi_program = ctx.accounts.token_program.to_account_info();
let cpi_context = CpiContext::new(cpi_program, cpi_accounts);
token::transfer(cpi_context, provider_fee + recipient_fee)?;

let cpi_accounts = Transfer {
from: ctx.accounts.payer_token_account.to_account_info(),
to: ctx.accounts.payment_token_account.to_account_info(),
Expand All @@ -67,7 +80,7 @@ pub fn handler(ctx: Context<ExtendExpirationCtx>, payment_amount: u64) -> Result

let cpi_program = ctx.accounts.token_program.to_account_info();
let cpi_context = CpiContext::new(cpi_program, cpi_accounts);
token::transfer(cpi_context, payment_amount)?;
token::transfer(cpi_context, payment_amount - recipient_fee)?;

time_invalidator.expiration = new_expiration;
return Ok(());
Expand Down
11 changes: 11 additions & 0 deletions programs/cardinal-token-manager/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use anchor_lang::prelude::*;
use std::str::FromStr;

#[derive(Clone, Debug, PartialEq, AnchorSerialize, AnchorDeserialize)]
#[repr(u8)]
Expand Down Expand Up @@ -97,3 +98,13 @@ pub struct TranferReceipt {
pub token_manager: Pubkey,
pub target: Pubkey
}

pub const FEE_SCALE: u64 = 10000;
pub const PROVIDER_FEE: u64 = 0;
pub const RECIPIENT_FEE: u64 = 0;
pub fn assert_payment_manager(key: &Pubkey) -> bool {
let allowed_payment_managers = [
Pubkey::from_str("crdk1Mw5WzoVNgz8RgHJXzHdwSrJvp4UcGirvtJzB6U").unwrap(),
];
return allowed_payment_managers.contains(key)
}
2 changes: 2 additions & 0 deletions programs/cardinal-use-invalidator/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,6 @@ pub enum ErrorCode {
MaxUsagesReached,
#[msg("Extension must be a multiple of extension payment")]
InvalidExtensionAmount,
#[msg("Token account incorrect mint")]
InvalidPaymentManagerTokenAccount,
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use {
crate::{errors::ErrorCode, state::*},
anchor_lang::prelude::*,
anchor_spl::token::{self, Token, TokenAccount, Transfer},
cardinal_token_manager::{state::{TokenManager, TokenManagerState}, utils::assert_payment_token_account},
cardinal_token_manager::{state::{TokenManager, TokenManagerState, PROVIDER_FEE, RECIPIENT_FEE, FEE_SCALE, assert_payment_manager}, utils::assert_payment_token_account},
};

#[derive(Accounts)]
Expand All @@ -15,7 +15,9 @@ use {

#[account(mut, constraint = payment_token_account.mint == use_invalidator.extension_payment_mint.unwrap() @ ErrorCode::InvalidPaymentTokenAccount)]
payment_token_account: Box<Account<'info, TokenAccount>>,

#[account(mut, constraint = payment_manager_token_account.mint == use_invalidator.extension_payment_mint.unwrap() && assert_payment_manager(&payment_manager_token_account.owner) @ ErrorCode::InvalidPaymentManagerTokenAccount)]
payment_manager_token_account: Box<Account<'info, TokenAccount>>,

#[account(mut)]
payer: Signer<'info>,
#[account(mut, constraint =
Expand Down Expand Up @@ -51,6 +53,17 @@ use {
return Err(error!(ErrorCode::MaxUsagesReached));
}

let provider_fee = use_invalidator.extension_payment_amount.unwrap() * (PROVIDER_FEE / FEE_SCALE);
let recipient_fee = use_invalidator.extension_payment_amount.unwrap() * (RECIPIENT_FEE / FEE_SCALE);
let cpi_accounts = Transfer {
from: ctx.accounts.payer_token_account.to_account_info(),
to: ctx.accounts.payment_manager_token_account.to_account_info(),
authority: ctx.accounts.payer.to_account_info(),
};
let cpi_program = ctx.accounts.token_program.to_account_info();
let cpi_context = CpiContext::new(cpi_program, cpi_accounts);
token::transfer(cpi_context, provider_fee + recipient_fee)?;

let cpi_accounts = Transfer {
from: ctx.accounts.payer_token_account.to_account_info(),
to: ctx.accounts.payment_token_account.to_account_info(),
Expand All @@ -59,7 +72,7 @@ use {

let cpi_program = ctx.accounts.token_program.to_account_info();
let cpi_context = CpiContext::new(cpi_program, cpi_accounts);
token::transfer(cpi_context, payment_amount)?;
token::transfer(cpi_context, payment_amount - recipient_fee)?;

use_invalidator.total_usages = new_total_usages;
return Ok(());
Expand Down
28 changes: 24 additions & 4 deletions src/idl/cardinal_paid_claim_approver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ export type CardinalPaidClaimApprover = {
isMut: true;
isSigner: false;
},
{
name: "paymentManagerTokenAccount";
isMut: true;
isSigner: false;
},
{
name: "claimApprover";
isMut: true;
Expand Down Expand Up @@ -149,16 +154,21 @@ export type CardinalPaidClaimApprover = {
},
{
code: 6001;
name: "InvalidPaymentManagerTokenAccount";
msg: "Token account incorrect mint";
},
{
code: 6002;
name: "InvalidPayerTokenAccount";
msg: "Token account not owned by the payer";
},
{
code: 6002;
code: 6003;
name: "InvalidTokenManager";
msg: "Invalid token manager for this claim approver";
},
{
code: 6003;
code: 6004;
name: "InvalidIssuer";
msg: "Invalid issuer";
}
Expand Down Expand Up @@ -222,6 +232,11 @@ export const IDL: CardinalPaidClaimApprover = {
isMut: true,
isSigner: false,
},
{
name: "paymentManagerTokenAccount",
isMut: true,
isSigner: false,
},
{
name: "claimApprover",
isMut: true,
Expand Down Expand Up @@ -316,16 +331,21 @@ export const IDL: CardinalPaidClaimApprover = {
},
{
code: 6001,
name: "InvalidPaymentManagerTokenAccount",
msg: "Token account incorrect mint",
},
{
code: 6002,
name: "InvalidPayerTokenAccount",
msg: "Token account not owned by the payer",
},
{
code: 6002,
code: 6003,
name: "InvalidTokenManager",
msg: "Invalid token manager for this claim approver",
},
{
code: 6003,
code: 6004,
name: "InvalidIssuer",
msg: "Invalid issuer",
},
Expand Down
20 changes: 20 additions & 0 deletions src/idl/cardinal_time_invalidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ export type CardinalTimeInvalidator = {
isMut: true;
isSigner: false;
},
{
name: "paymentManagerTokenAccount";
isMut: true;
isSigner: false;
},
{
name: "payer";
isMut: true;
Expand Down Expand Up @@ -332,6 +337,11 @@ export type CardinalTimeInvalidator = {
code: 6010;
name: "InvalidExtensionAmount";
msg: "Invalid extension partial duration not allowed";
},
{
code: 6011;
name: "InvalidPaymentManagerTokenAccount";
msg: "Token account incorrect mint";
}
];
};
Expand Down Expand Up @@ -412,6 +422,11 @@ export const IDL: CardinalTimeInvalidator = {
isMut: true,
isSigner: false,
},
{
name: "paymentManagerTokenAccount",
isMut: true,
isSigner: false,
},
{
name: "payer",
isMut: true,
Expand Down Expand Up @@ -671,5 +686,10 @@ export const IDL: CardinalTimeInvalidator = {
name: "InvalidExtensionAmount",
msg: "Invalid extension partial duration not allowed",
},
{
code: 6011,
name: "InvalidPaymentManagerTokenAccount",
msg: "Token account incorrect mint",
},
],
};
20 changes: 20 additions & 0 deletions src/idl/cardinal_use_invalidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ export type CardinalUseInvalidator = {
isMut: true;
isSigner: false;
},
{
name: "paymentManagerTokenAccount";
isMut: true;
isSigner: false;
},
{
name: "payer";
isMut: true;
Expand Down Expand Up @@ -329,6 +334,11 @@ export type CardinalUseInvalidator = {
code: 6008;
name: "InvalidExtensionAmount";
msg: "Extension must be a multiple of extension payment";
},
{
code: 6009;
name: "InvalidPaymentManagerTokenAccount";
msg: "Token account incorrect mint";
}
];
};
Expand Down Expand Up @@ -424,6 +434,11 @@ export const IDL: CardinalUseInvalidator = {
isMut: true,
isSigner: false,
},
{
name: "paymentManagerTokenAccount",
isMut: true,
isSigner: false,
},
{
name: "payer",
isMut: true,
Expand Down Expand Up @@ -665,5 +680,10 @@ export const IDL: CardinalUseInvalidator = {
name: "InvalidExtensionAmount",
msg: "Extension must be a multiple of extension payment",
},
{
code: 6009,
name: "InvalidPaymentManagerTokenAccount",
msg: "Token account incorrect mint",
},
],
};
9 changes: 7 additions & 2 deletions src/programs/claimApprover/instruction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export const pay = async (
wallet: Wallet,
tokenManagerId: PublicKey,
payerTokenAccountId: PublicKey,
paymentAccounts: [PublicKey, AccountMeta[]]
paymentAccounts: [PublicKey, PublicKey, AccountMeta[]]
): Promise<TransactionInstruction> => {
const provider = new Provider(connection, wallet, {});

Expand All @@ -74,14 +74,19 @@ export const pay = async (
);

const [claimApproverId] = await findClaimApproverAddress(tokenManagerId);
const [paymentTokenAccountId, remainingAccounts] = paymentAccounts;
const [
paymentTokenAccountId,
paymentManagerTokenAccountId,
remainingAccounts,
] = paymentAccounts;
return claimApproverProgram.instruction.pay({
accounts: {
tokenManager: tokenManagerId,
paymentTokenAccount: paymentTokenAccountId,
claimApprover: claimApproverId,
payer: wallet.publicKey,
payerTokenAccount: payerTokenAccountId,
paymentManagerTokenAccount: paymentManagerTokenAccountId,
claimReceipt: claimReceiptId,
cardinalTokenManager: TOKEN_MANAGER_ADDRESS,
tokenProgram: TOKEN_PROGRAM_ID,
Expand Down
Loading

0 comments on commit 77414ce

Please sign in to comment.