@smartinvoicexyz/utils
Version:
Unified source for utility functions used across the Smart Invoice protocol.
215 lines (214 loc) • 7.66 kB
JavaScript
import _ from 'lodash';
import { isAddress } from 'viem';
import * as Yup from 'yup';
import { sevenDaysFromDate } from './date';
import { isKnownResolver, isValidURL } from './helpers';
export const escrowDetailsSchema = (chainId) => Yup.object().shape({
client: Yup.string()
.required('Client address is required')
.test({
name: 'clientIsAddress',
test: (v, { createError }) => {
if (!!v && isAddress(v))
return true;
return createError({
path: 'client',
message: 'Client must be a valid address',
});
},
})
.when('provider', (p, localSchema) => {
if (!p)
return localSchema;
return localSchema.test({
name: 'clientNotProvider',
test: (v, { createError }) => {
if (_.toLower(v) !== _.toLower(_.first(p)))
return true;
return createError({
path: 'client',
message: 'Client cannot be same as provider',
});
},
});
}),
clientReceiver: Yup.string()
.optional()
.test({
name: 'clientReceiverIsAddress',
test: (v, { createError }) => {
if (!v || isAddress(v))
return true;
return createError({
path: 'clientReceiver',
message: 'Client receiver must be a valid address',
});
},
message: 'Client receiver must be a valid address',
}),
provider: Yup.string()
.required()
.test({
name: 'providerIsAddress',
test: (v, { createError }) => {
if (!!v && isAddress(v))
return true;
return createError({
path: 'provider',
message: 'Provider must be a valid address',
});
},
}),
providerReceiver: Yup.string()
.optional()
.test({
name: 'providerReceiverIsAddress',
test: (v, { createError }) => {
if (!v || isAddress(v))
return true;
return createError({
path: 'providerReceiver',
message: 'Provider receiver must be a valid address',
});
},
message: 'Provider receiver must be a valid address',
}),
resolverType: Yup.string()
.required()
.oneOf(['kleros', 'custom', 'lexdao', 'smart-invoice']),
resolverAddress: Yup.string().when('resolverType', (r, localSchema) => {
if (_.first(r) !== 'custom')
return localSchema;
return localSchema
.required('Custom resolver address is required')
.test((value) => isAddress(value));
}),
klerosCourt: Yup.number().when('resolverType', (r, localSchema) => {
if (_.first(r) !== 'kleros')
return localSchema;
return localSchema.required('Kleros court is required').oneOf([1, 2, 3]);
}),
isResolverTermsChecked: Yup.boolean().when('resolverType', (r, localSchema) => {
if (!isKnownResolver(_.first(r), chainId))
return localSchema;
return localSchema.oneOf([true], "Must accept resolver's terms of service");
}),
});
export const instantPaymentSchema = Yup.object().shape({
client: Yup.string()
.required('Client address is required')
.test({
name: 'clientIsAddress',
test: (v, { createError }) => {
if (!!v && isAddress(v))
return true;
return createError({
path: 'client',
message: 'Client must be a valid address',
});
},
}),
provider: Yup.string()
.required('Provider address is required')
.test({
name: 'providerIsAddress',
test: (v, { createError }) => {
if (!!v && isAddress(v))
return true;
return createError({
path: 'provider',
message: 'Provider must be a valid address',
});
},
}),
token: Yup.string(),
paymentDue: Yup.number(),
deadline: Yup.date(),
lateFee: Yup.string(),
lateFeeTimeInterval: Yup.string(),
});
export const addMilestonesSchema = Yup.object().shape({
milestones: Yup.array()
.min(1, 'At least one milestone is required!')
.of(Yup.object().shape({
value: Yup.string().required('Milestone Amount is required'),
title: Yup.string().optional(),
description: Yup.string().optional(),
})),
document: Yup.string().test({
name: 'documentIsURL',
test: (v, { createError }) => {
if (!v || isValidURL(v))
return true;
return createError({
path: 'document',
message: 'Project document must be a valid URL',
});
},
}),
});
export const resolveFundsSchema = Yup.object().shape({
description: Yup.string().required('Project description is required'),
document: Yup.string().test({
name: 'documentIsURL',
test: (v, { createError }) => {
if (!v || isValidURL(v))
return true;
return createError({
path: 'document',
message: 'Project document must be a valid URL',
});
},
}),
clientAward: Yup.number().required('Client award is required'),
providerAward: Yup.number().required('Provider award is required'),
resolverAward: Yup.number().required('Resolver award is required'),
});
export const lockFundsSchema = Yup.object().shape({
description: Yup.string().required('Project description is required'),
document: Yup.string().test({
name: 'documentIsURL',
test: (v, { createError }) => {
if (!v || isValidURL(v))
return true;
return createError({
path: 'document',
message: 'Project document must be a valid URL',
});
},
}),
});
export const escrowPaymentsSchema = Yup.object().shape({
milestones: Yup.array()
.min(1, 'At least one milestone is required!')
.of(Yup.object().shape({
value: Yup.string().required('Milestone Amount is required'),
title: Yup.string().optional(),
description: Yup.string().optional(),
})),
token: Yup.string().required('Token is required'),
});
export const projectDetailsSchema = Yup.object().shape({
title: Yup.string().required('Project title is required'),
description: Yup.string().required('Project description is required'),
document: Yup.string().test({
name: 'documentIsURL',
test: (v, { createError }) => {
if (!v || isValidURL(v))
return true;
return createError({
path: 'document',
message: 'Project document must be a valid URL',
});
},
}),
startDate: Yup.date().required('Start Date is required'),
endDate: Yup.date()
.required('End Date is required')
.min(Yup.ref('startDate'), 'End Date must be after Start Date'),
// ideally could dynamically choose these. Setting a default covers this largely
deadline: Yup.date().min(Yup.ref('endDate'), 'Deadline must be after End Date'),
safetyValveDate: Yup.date().when(['endDate'], (endDate, schema) => {
return schema.min(sevenDaysFromDate(endDate.toString()), 'Safety Valve Date must be at least 7 days after End Date');
}),
});