1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
//! JobOffer-related structs.
extern crate alloc;
use crate::bid_escrow::job::PickBidRequest;
use crate::bid_escrow::types::JobOfferId;
use crate::configuration::Configuration;
use crate::rules::validation::bid_escrow::{
CanJobOfferBeCancelled, CanProgressJobOffer, HasPermissionsToCancelJobOffer, IsDosFeeEnough,
};
use crate::rules::validation::IsUserKyced;
use crate::rules::RulesBuilder;
use alloc::rc::Rc;
use odra::types::{Address, Balance, BlockTime};
use odra::OdraType;
/// Serializable JobOffer status representation.
#[derive(OdraType, PartialEq)]
pub enum JobOfferStatus {
/// Created, Bidders can place bids.
Created,
/// Bid selected, a Worker works on it.
InProgress,
/// Offer canceled, is no longer valid.
Cancelled,
}
/// Auction state representation.
#[derive(PartialEq)]
pub enum AuctionState {
/// Unknown state.
None,
/// Internal Auction - only VAs' can bid.
Internal,
/// Public Auction - nonVAs' can bid.
Public,
}
/// Data required to post a job offer.
pub struct PostJobOfferRequest {
/// New offer id.
pub job_offer_id: JobOfferId,
/// The offer creator.
pub job_poster: Address,
/// Is the creator passed the KYC process.
pub job_poster_kyced: bool,
/// Max amount the Job Poster can pay for the Job.
pub max_budget: Balance,
/// The time the Job should be completed.
pub expected_timeframe: BlockTime,
/// CSPR amount attached to Post Job query.
pub dos_fee: Balance,
/// The time since the offer is available for Bidders.
pub start_time: BlockTime,
/// Job configuration.
pub configuration: Rc<Configuration>,
}
/// Data required to cancel a job offer.
pub struct CancelJobOfferRequest {
/// The request caller.
pub caller: Address,
/// The request creation time.
pub block_time: BlockTime,
}
/// Writeable/readable representation of a `Job Offer`.
#[derive(OdraType)]
pub struct JobOffer {
/// Offer id.
pub job_offer_id: JobOfferId,
/// The offer creator.
pub job_poster: Address,
/// Max amount the Job Poster can pay for the Job.
pub max_budget: Balance,
/// The time the Job should be completed.
pub expected_timeframe: BlockTime,
/// CSPR amount attached to the offer.
pub dos_fee: Balance,
/// The current job offer status.
pub status: JobOfferStatus,
/// The time since the offer is available for Bidders.
pub start_time: BlockTime,
/// Job configuration.
pub configuration: Configuration,
}
impl JobOffer {
/// Conditionally creates a new instance of JobOffer.
///
/// Runs validation:
/// * [`IsUserKyced`]
/// * [`IsDosFeeEnough`]
/// Stops contract execution if any validation fails.
pub fn new(request: PostJobOfferRequest) -> JobOffer {
RulesBuilder::new()
.add_validation(IsUserKyced::create(request.job_poster_kyced))
.add_validation(IsDosFeeEnough::create(
request.configuration.clone(),
request.dos_fee,
))
.build()
.validate_generic_validations();
JobOffer {
job_offer_id: request.job_offer_id,
job_poster: request.job_poster,
max_budget: request.max_budget,
expected_timeframe: request.expected_timeframe,
dos_fee: request.dos_fee,
status: JobOfferStatus::Created,
start_time: request.start_time,
configuration: (*request.configuration).clone(),
}
}
/// Conditionally changes the status to [InProgress](JobOfferStatus::InProgress).
///
/// Runs validation:
/// * [`CanProgressJobOffer`]
///
/// Stops contract execution if the validation fails.
pub fn in_progress(&mut self, request: &PickBidRequest) {
RulesBuilder::new()
.add_validation(CanProgressJobOffer::create(request.caller, self.job_poster))
.build()
.validate_generic_validations();
self.status = JobOfferStatus::InProgress;
}
/// Conditionally changes the status to [Cancelled](JobOfferStatus::Cancelled).
///
/// Runs validation:
/// * [`HasPermissionsToCancelJobOffer`]
/// * [`CanJobOfferBeCancelled`]
///
/// Stops contract execution if any validation fails.
pub fn cancel(&mut self, request: &CancelJobOfferRequest) {
RulesBuilder::new()
.add_validation(HasPermissionsToCancelJobOffer::create(
request.caller,
self.job_poster,
))
.add_validation(CanJobOfferBeCancelled::create(
self.auction_state(request.block_time),
))
.build()
.validate_generic_validations();
self.status = JobOfferStatus::Cancelled;
}
/// Gets the auction state in a given time.
pub fn auction_state(&self, block_time: BlockTime) -> AuctionState {
let public_auction_start_time =
self.start_time + self.configuration.internal_auction_time();
let public_auction_end_time =
public_auction_start_time + self.configuration.public_auction_time();
if block_time >= self.start_time && block_time < public_auction_start_time {
AuctionState::Internal
} else if block_time >= public_auction_start_time && block_time < public_auction_end_time {
AuctionState::Public
} else {
AuctionState::None
}
}
/// Gets a reference to the job configuration.
pub fn configuration(&self) -> &Configuration {
&self.configuration
}
pub fn slash(&mut self) {
self.status = JobOfferStatus::Cancelled;
}
}