Skip to content

Commit

Permalink
Merge pull request #172 from convergence-rfq/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
pindaroso authored Nov 7, 2023
2 parents 8f050f0 + 505fc18 commit 61014b4
Show file tree
Hide file tree
Showing 16 changed files with 254 additions and 58 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
**Note:** Version 0 of Semantic Versioning is handled differently from version 1 and above.
The minor version will be incremented upon a breaking change and the patch version will be incremented for features.

## [2.2.14] - 2023-10-31

### Features

- response: added response expiration timestamp field to Response state and validation to check response expiration. See PR ([#170](https://github.com/convergence-rfq/convergence-program-library/pull/170)) for full details.

## [2.2.13] - 2023-10-04

### Fixes
Expand Down
4 changes: 2 additions & 2 deletions psyoptions-american-instrument/js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@convergence-rfq/psyoptions-american-instrument",
"version": "2.2.13",
"version": "2.2.14",
"license": "MIT",
"publishConfig": {
"access": "public",
Expand Down Expand Up @@ -31,4 +31,4 @@
"typescript": "^4.8.4",
"rimraf": "^4.1.2"
}
}
}
4 changes: 2 additions & 2 deletions psyoptions-european-instrument/js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@convergence-rfq/psyoptions-european-instrument",
"version": "2.2.13",
"version": "2.2.14",
"license": "MIT",
"publishConfig": {
"access": "public",
Expand Down Expand Up @@ -31,4 +31,4 @@
"typescript": "^4.8.4",
"rimraf": "^4.1.2"
}
}
}
4 changes: 2 additions & 2 deletions rfq/js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@convergence-rfq/rfq",
"version": "2.2.13",
"version": "2.2.14",
"license": "MIT",
"publishConfig": {
"access": "public",
Expand Down Expand Up @@ -31,4 +31,4 @@
"typescript": "^4.8.4",
"rimraf": "^4.1.2"
}
}
}
2 changes: 2 additions & 0 deletions rfq/program/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ pub enum ProtocolError {
NotARiskEngine,
#[msg("Recent timestamp is too different from on-chain time")]
InvalidRecentTimestamp,
#[msg("Expiration timestamp is invalid")]
InvalidExpirationTimestamp,
#[msg("An Rfq without legs is not supported")]
EmptyLegsNotSupported,
#[msg("Legs size does not match specified expected leg size")]
Expand Down
17 changes: 16 additions & 1 deletion rfq/program/src/instructions/rfq/respond_to_rfq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,21 @@ fn validate(
ctx: &Context<RespondToRfqAccounts>,
bid: Option<Quote>,
ask: Option<Quote>,
expiration_timestamp: i64,
) -> Result<()> {
let RespondToRfqAccounts { maker, rfq, .. } = &ctx.accounts;
//checks for expiration timestamp
let current_timestamp = Clock::get()?.unix_timestamp;
let rfq_expiration_timestamp = rfq.creation_timestamp + rfq.active_window as i64;
require!(
expiration_timestamp > current_timestamp,
ProtocolError::InvalidExpirationTimestamp
);

require!(
expiration_timestamp <= rfq_expiration_timestamp,
ProtocolError::InvalidExpirationTimestamp
);

require!(maker.key() != rfq.taker, ProtocolError::TakerCanNotRespond);

Expand Down Expand Up @@ -112,8 +125,9 @@ pub fn respond_to_rfq_instruction<'info>(
bid: Option<Quote>,
ask: Option<Quote>,
_pda_distinguisher: u16,
expiration_timestamp: i64,
) -> Result<()> {
validate(&ctx, bid, ask)?;
validate(&ctx, bid, ask, expiration_timestamp)?;

let RespondToRfqAccounts {
maker,
Expand All @@ -140,6 +154,7 @@ pub fn respond_to_rfq_instruction<'info>(
leg_preparations_initialized_by: vec![],
bid,
ask,
expiration_timestamp,
});
response.exit(ctx.program_id)?;

Expand Down
3 changes: 2 additions & 1 deletion rfq/program/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,9 @@ pub mod rfq {
bid: Option<Quote>,
ask: Option<Quote>,
pda_distinguisher: u16, // allows creation of the same response multiple times specifying a different distinguisher
expiration_timestamp: i64,
) -> Result<()> {
respond_to_rfq_instruction(ctx, bid, ask, pda_distinguisher)
respond_to_rfq_instruction(ctx, bid, ask, pda_distinguisher, expiration_timestamp)
}

pub fn confirm_response<'info>(
Expand Down
7 changes: 6 additions & 1 deletion rfq/program/src/state/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub struct Response {
pub rfq: Pubkey,

pub creation_timestamp: i64,
pub expiration_timestamp: i64,
pub maker_collateral_locked: u64,
pub taker_collateral_locked: u64,
pub state: StoredResponseState,
Expand Down Expand Up @@ -43,7 +44,7 @@ impl Response {

pub fn get_state(&self, rfq: &Rfq) -> Result<ResponseState> {
let current_time = Clock::get()?.unix_timestamp;
let active_window_ended = rfq.active_window_ended(current_time);
let active_window_ended = self.active_window_ended(current_time);
let settle_window_ended = rfq.settle_window_ended(current_time);
let state = match self.state {
StoredResponseState::Active => {
Expand Down Expand Up @@ -81,6 +82,10 @@ impl Response {
Ok(state)
}

pub fn active_window_ended(&self, current_time: i64) -> bool {
current_time >= self.expiration_timestamp
}

pub fn get_asset_amount_to_transfer(
&self,
rfq: &Rfq,
Expand Down
4 changes: 2 additions & 2 deletions risk-engine/js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@convergence-rfq/risk-engine",
"version": "2.2.13",
"version": "2.2.14",
"license": "MIT",
"publishConfig": {
"access": "public",
Expand Down Expand Up @@ -31,4 +31,4 @@
"typescript": "^4.8.4",
"rimraf": "^4.1.2"
}
}
}
4 changes: 2 additions & 2 deletions spot-instrument/js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@convergence-rfq/spot-instrument",
"version": "2.2.13",
"version": "2.2.14",
"license": "MIT",
"publishConfig": {
"access": "public",
Expand Down Expand Up @@ -31,4 +31,4 @@
"typescript": "^4.8.4",
"rimraf": "^4.1.2"
}
}
}
2 changes: 2 additions & 0 deletions tests/integration/psyoptionsAmerican.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ describe("Psyoptions American instrument integration tests", async () => {
// response with agreeing to buy 5 options for 45$
const response = await rfq.respond({
bid: Quote.getStandard(toAbsolutePrice(withTokenDecimals(45)), toLegMultiplier(5)),
expirationTimestamp: Date.now() / 1000 + 1,
});

// taker confirms to sell 2 options
Expand Down Expand Up @@ -249,6 +250,7 @@ describe("Psyoptions American instrument integration tests", async () => {
// response with agreeing to buy 5 options for 45$
const response = await rfq.respond({
bid: Quote.getStandard(toAbsolutePrice(withTokenDecimals(45)), toLegMultiplier(5)),
expirationTimestamp: Date.now() / 1000 + 1,
});

// taker confirms to sell 2 options
Expand Down
22 changes: 18 additions & 4 deletions tests/integration/psyoptionsEuropean.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ describe("Psyoptions European instrument integration tests", () => {
ask: Quote.getStandard(toAbsolutePrice(withTokenDecimals(500)), toLegMultiplier(2)),
});
// taker confirms to buy 1 option
await response.confirm({ side: QuoteSide.Ask, legMultiplierBps: toLegMultiplier(1) });
await response.confirm({
side: QuoteSide.Ask,
legMultiplierBps: toLegMultiplier(1),
});

await response.prepareSettlement(AuthoritySide.Taker);

Expand All @@ -70,7 +73,11 @@ describe("Psyoptions European instrument integration tests", () => {
// taker should receive 1 option, maker should receive 500$ and lose 1 bitcoin as option collateral
await response.settle(maker, [taker]);
await tokenMeasurer.expectChange([
{ token: options.callMint, user: taker, delta: new BN(1).mul(CONTRACT_DECIMALS_BN) },
{
token: options.callMint,
user: taker,
delta: new BN(1).mul(CONTRACT_DECIMALS_BN),
},
{ token: "quote", user: taker, delta: withTokenDecimals(-500) },
{ token: "quote", user: maker, delta: withTokenDecimals(500) },
{ token: "asset", user: maker, delta: withTokenDecimals(-1) },
Expand Down Expand Up @@ -98,9 +105,13 @@ describe("Psyoptions European instrument integration tests", () => {
// response with agreeing to buy 5 options for 450$
const response = await rfq.respond({
bid: Quote.getStandard(toAbsolutePrice(withTokenDecimals(450)), toLegMultiplier(5)),
expirationTimestamp: Date.now() / 1000 + 1,
});
// taker confirms to sell 2 options
await response.confirm({ side: QuoteSide.Bid, legMultiplierBps: toLegMultiplier(2) });
await response.confirm({
side: QuoteSide.Bid,
legMultiplierBps: toLegMultiplier(2),
});

await options.mintOptions(context.taker, new BN(2), OptionType.PUT);

Expand Down Expand Up @@ -169,7 +180,10 @@ describe("Psyoptions European instrument integration tests", () => {
bid: Quote.getStandard(toAbsolutePrice(withTokenDecimals(450)), toLegMultiplier(5)),
ask: Quote.getStandard(toAbsolutePrice(withTokenDecimals(500)), toLegMultiplier(2)),
});
await response.confirm({ side: QuoteSide.Ask, legMultiplierBps: toLegMultiplier(1) });
await response.confirm({
side: QuoteSide.Ask,
legMultiplierBps: toLegMultiplier(1),
});

// mint options
await Promise.all(options.map(async (option) => option.mintOptions(context.maker, new BN(2), OptionType.CALL)));
Expand Down
Loading

0 comments on commit 61014b4

Please sign in to comment.