@carrot-foundation/schemas 0.1.37 → 0.1.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1037 -383
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1826 -1276
- package/dist/index.d.ts +1826 -1276
- package/dist/index.js +1017 -384
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/schemas/ipfs/collection/collection.schema.json +3 -2
- package/schemas/ipfs/credit/credit.schema.json +3 -2
- package/schemas/ipfs/credit-purchase-receipt/credit-purchase-receipt.schema.json +103 -99
- package/schemas/ipfs/credit-retirement-receipt/credit-retirement-receipt.example.json +280 -0
- package/schemas/ipfs/credit-retirement-receipt/credit-retirement-receipt.schema.json +1704 -0
- package/schemas/ipfs/gas-id/gas-id.schema.json +3 -2
- package/schemas/ipfs/mass-id/mass-id.schema.json +3 -2
- package/schemas/ipfs/mass-id-audit/mass-id-audit.schema.json +3 -2
- package/schemas/ipfs/methodology/methodology.schema.json +3 -2
- package/schemas/ipfs/recycled-id/recycled-id.schema.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -292,6 +292,7 @@ var RecordSchemaTypeSchema = zod.z.enum([
|
|
|
292
292
|
"RecycledID",
|
|
293
293
|
"GasID",
|
|
294
294
|
"CreditPurchaseReceipt",
|
|
295
|
+
"CreditRetirementReceipt",
|
|
295
296
|
"Methodology",
|
|
296
297
|
"Credit",
|
|
297
298
|
"Collection"
|
|
@@ -308,6 +309,11 @@ var TokenSymbolSchema = NonEmptyStringSchema.max(10).regex(
|
|
|
308
309
|
description: "Symbol representing a token or cryptocurrency",
|
|
309
310
|
examples: ["MASS", "REC", "GAS"]
|
|
310
311
|
});
|
|
312
|
+
var CreditTokenSymbolSchema = TokenSymbolSchema.meta({
|
|
313
|
+
title: "Credit Token Symbol",
|
|
314
|
+
description: "Symbol of the credit token (e.g., C-CARB, C-BIOW)",
|
|
315
|
+
examples: ["C-CARB", "C-BIOW"]
|
|
316
|
+
});
|
|
311
317
|
var RecordRelationshipTypeSchema = zod.z.enum([
|
|
312
318
|
"collection",
|
|
313
319
|
"credit",
|
|
@@ -316,6 +322,7 @@ var RecordRelationshipTypeSchema = zod.z.enum([
|
|
|
316
322
|
"mass-id-audit",
|
|
317
323
|
"methodology",
|
|
318
324
|
"credit-purchase-receipt",
|
|
325
|
+
"credit-retirement-receipt",
|
|
319
326
|
"recycled-id"
|
|
320
327
|
]).meta({
|
|
321
328
|
title: "Relationship Type",
|
|
@@ -733,7 +740,8 @@ var NftSchemaTypeSchema = RecordSchemaTypeSchema.extract([
|
|
|
733
740
|
"MassID",
|
|
734
741
|
"RecycledID",
|
|
735
742
|
"GasID",
|
|
736
|
-
"CreditPurchaseReceipt"
|
|
743
|
+
"CreditPurchaseReceipt",
|
|
744
|
+
"CreditRetirementReceipt"
|
|
737
745
|
]).meta({
|
|
738
746
|
title: "NFT Schema Type",
|
|
739
747
|
description: "Type of schema for NFT records"
|
|
@@ -910,7 +918,7 @@ function buildSchemaUrl(schemaPath) {
|
|
|
910
918
|
return `${getSchemaBaseUrl()}/${cleanPath}`;
|
|
911
919
|
}
|
|
912
920
|
function getSchemaVersionOrDefault() {
|
|
913
|
-
return "0.1.
|
|
921
|
+
return "0.1.39";
|
|
914
922
|
}
|
|
915
923
|
var MethodologyAttributeSchema = NftAttributeSchema.safeExtend({
|
|
916
924
|
trait_type: zod.z.literal("Methodology"),
|
|
@@ -1085,6 +1093,331 @@ var AuditRuleExecutionResultsSchema = zod.z.array(AuditRuleExecutionResultSchema
|
|
|
1085
1093
|
title: "Audit Rule Execution Results",
|
|
1086
1094
|
description: "Detailed results of each audit rule execution"
|
|
1087
1095
|
});
|
|
1096
|
+
var EPSILON = 1e-9;
|
|
1097
|
+
function nearlyEqual(a, b, epsilon = EPSILON) {
|
|
1098
|
+
return Math.abs(a - b) <= epsilon;
|
|
1099
|
+
}
|
|
1100
|
+
var SummaryBaseSchema = zod.z.strictObject({
|
|
1101
|
+
total_certificates: PositiveIntegerSchema.meta({
|
|
1102
|
+
title: "Total Certificates",
|
|
1103
|
+
description: "Total number of certificates represented in the receipt"
|
|
1104
|
+
}),
|
|
1105
|
+
credit_symbols: uniqueArrayItems(
|
|
1106
|
+
CreditTokenSymbolSchema,
|
|
1107
|
+
"Credit symbols must be unique"
|
|
1108
|
+
).min(1).meta({
|
|
1109
|
+
title: "Credit Symbols",
|
|
1110
|
+
description: "Array of credit token symbols represented in the receipt"
|
|
1111
|
+
}),
|
|
1112
|
+
certificate_types: uniqueArrayItems(
|
|
1113
|
+
RecordSchemaTypeSchema.extract(["GasID", "RecycledID"]),
|
|
1114
|
+
"Certificate types must be unique"
|
|
1115
|
+
).min(1).meta({
|
|
1116
|
+
title: "Certificate Types",
|
|
1117
|
+
description: "Array of certificate types represented in the receipt"
|
|
1118
|
+
}),
|
|
1119
|
+
collection_slugs: uniqueArrayItems(
|
|
1120
|
+
CollectionSlugSchema,
|
|
1121
|
+
"Collection slugs must be unique"
|
|
1122
|
+
).min(1).meta({
|
|
1123
|
+
title: "Collection Slugs",
|
|
1124
|
+
description: "Array of collection slugs represented in the receipt"
|
|
1125
|
+
})
|
|
1126
|
+
});
|
|
1127
|
+
var CreditPurchaseReceiptSummarySchema = SummaryBaseSchema.extend({
|
|
1128
|
+
total_usdc_amount: NonNegativeFloatSchema.meta({
|
|
1129
|
+
title: "Total USDC Amount",
|
|
1130
|
+
description: "Total amount paid in USDC for the purchase"
|
|
1131
|
+
}),
|
|
1132
|
+
total_credits: CreditAmountSchema.meta({
|
|
1133
|
+
title: "Total Credits",
|
|
1134
|
+
description: "Total amount of credits purchased"
|
|
1135
|
+
}),
|
|
1136
|
+
purchase_date: IsoDateSchema.meta({
|
|
1137
|
+
title: "Purchase Date",
|
|
1138
|
+
description: "Date when the purchase was made (YYYY-MM-DD)"
|
|
1139
|
+
})
|
|
1140
|
+
}).meta({
|
|
1141
|
+
title: "Credit Purchase Receipt Summary",
|
|
1142
|
+
description: "Summary totals for the credit purchase including amounts and collections represented"
|
|
1143
|
+
});
|
|
1144
|
+
var CreditRetirementReceiptSummarySchema = SummaryBaseSchema.extend({
|
|
1145
|
+
total_retirement_amount: CreditAmountSchema.meta({
|
|
1146
|
+
title: "Total Retirement Amount",
|
|
1147
|
+
description: "Total amount of credits retired"
|
|
1148
|
+
}),
|
|
1149
|
+
retirement_date: IsoDateSchema.meta({
|
|
1150
|
+
title: "Retirement Date",
|
|
1151
|
+
description: "Date when the retirement occurred (YYYY-MM-DD)"
|
|
1152
|
+
})
|
|
1153
|
+
}).meta({
|
|
1154
|
+
title: "Credit Retirement Receipt Summary",
|
|
1155
|
+
description: "Summary totals for the credit retirement including amounts and collections represented"
|
|
1156
|
+
});
|
|
1157
|
+
var ReceiptIdentitySchema = zod.z.strictObject({
|
|
1158
|
+
name: ParticipantNameSchema.meta({
|
|
1159
|
+
title: "Identity Name",
|
|
1160
|
+
description: "Display name for the participant",
|
|
1161
|
+
examples: ["EcoTech Solutions Inc.", "Climate Action Corp"]
|
|
1162
|
+
}),
|
|
1163
|
+
external_id: ExternalIdSchema.meta({
|
|
1164
|
+
title: "Identity External ID",
|
|
1165
|
+
description: "External identifier for the participant"
|
|
1166
|
+
}),
|
|
1167
|
+
external_url: ExternalUrlSchema.meta({
|
|
1168
|
+
title: "Identity External URL",
|
|
1169
|
+
description: "External URL for the participant profile"
|
|
1170
|
+
})
|
|
1171
|
+
}).meta({
|
|
1172
|
+
title: "Identity",
|
|
1173
|
+
description: "Participant identity information"
|
|
1174
|
+
});
|
|
1175
|
+
var MassIdReferenceWithContractSchema = MassIDReferenceSchema.safeExtend({
|
|
1176
|
+
smart_contract: SmartContractSchema
|
|
1177
|
+
}).meta({
|
|
1178
|
+
title: "MassID Reference with Smart Contract",
|
|
1179
|
+
description: "Reference to a MassID record including smart contract details"
|
|
1180
|
+
});
|
|
1181
|
+
function createReceiptCollectionSchema(params) {
|
|
1182
|
+
const { amountKey, amountMeta, meta } = params;
|
|
1183
|
+
return zod.z.strictObject({
|
|
1184
|
+
slug: CollectionSlugSchema,
|
|
1185
|
+
external_id: ExternalIdSchema.meta({
|
|
1186
|
+
title: "Collection External ID",
|
|
1187
|
+
description: "External identifier for the collection"
|
|
1188
|
+
}),
|
|
1189
|
+
name: CollectionNameSchema,
|
|
1190
|
+
external_url: ExternalUrlSchema.meta({
|
|
1191
|
+
title: "Collection External URL",
|
|
1192
|
+
description: "External URL for the collection"
|
|
1193
|
+
}),
|
|
1194
|
+
uri: IpfsUriSchema.meta({
|
|
1195
|
+
title: "Collection URI",
|
|
1196
|
+
description: "IPFS URI for the collection metadata"
|
|
1197
|
+
}),
|
|
1198
|
+
[amountKey]: CreditAmountSchema.meta(amountMeta)
|
|
1199
|
+
}).meta(meta);
|
|
1200
|
+
}
|
|
1201
|
+
function createReceiptCreditSchema(params) {
|
|
1202
|
+
const { amountKey, amountMeta, meta, retirementAmountMeta } = params;
|
|
1203
|
+
const creditShape = {
|
|
1204
|
+
slug: SlugSchema.meta({
|
|
1205
|
+
title: "Credit Slug",
|
|
1206
|
+
description: "URL-friendly identifier for the credit"
|
|
1207
|
+
}),
|
|
1208
|
+
symbol: CreditTokenSymbolSchema.meta({
|
|
1209
|
+
title: "Credit Token Symbol",
|
|
1210
|
+
description: "Symbol of the credit token",
|
|
1211
|
+
examples: ["CARBON", "ORGANIC", "C-CARB", "C-BIOW"]
|
|
1212
|
+
}),
|
|
1213
|
+
external_id: ExternalIdSchema.meta({
|
|
1214
|
+
title: "Credit External ID",
|
|
1215
|
+
description: "External identifier for the credit"
|
|
1216
|
+
}),
|
|
1217
|
+
external_url: ExternalUrlSchema.meta({
|
|
1218
|
+
title: "Credit External URL",
|
|
1219
|
+
description: "External URL for the credit"
|
|
1220
|
+
}),
|
|
1221
|
+
uri: IpfsUriSchema.meta({
|
|
1222
|
+
title: "Credit URI",
|
|
1223
|
+
description: "IPFS URI for the credit details"
|
|
1224
|
+
}),
|
|
1225
|
+
smart_contract: SmartContractSchema,
|
|
1226
|
+
[amountKey]: CreditAmountSchema.meta(amountMeta)
|
|
1227
|
+
};
|
|
1228
|
+
if (retirementAmountMeta) {
|
|
1229
|
+
creditShape.retirement_amount = CreditAmountSchema.optional().meta(retirementAmountMeta);
|
|
1230
|
+
}
|
|
1231
|
+
return zod.z.strictObject(creditShape).meta(meta);
|
|
1232
|
+
}
|
|
1233
|
+
var certificateBaseShape = {
|
|
1234
|
+
token_id: TokenIdSchema.meta({
|
|
1235
|
+
title: "Certificate Token ID",
|
|
1236
|
+
description: "Token ID of the certificate"
|
|
1237
|
+
}),
|
|
1238
|
+
type: RecordSchemaTypeSchema.extract(["GasID", "RecycledID"]).meta({
|
|
1239
|
+
title: "Certificate Type",
|
|
1240
|
+
description: "Type of certificate (e.g., GasID, RecycledID)"
|
|
1241
|
+
}),
|
|
1242
|
+
external_id: ExternalIdSchema.meta({
|
|
1243
|
+
title: "Certificate External ID",
|
|
1244
|
+
description: "External identifier for the certificate"
|
|
1245
|
+
}),
|
|
1246
|
+
external_url: ExternalUrlSchema.meta({
|
|
1247
|
+
title: "Certificate External URL",
|
|
1248
|
+
description: "External URL for the certificate"
|
|
1249
|
+
}),
|
|
1250
|
+
uri: IpfsUriSchema.meta({
|
|
1251
|
+
title: "Certificate URI",
|
|
1252
|
+
description: "IPFS URI for the certificate metadata"
|
|
1253
|
+
}),
|
|
1254
|
+
smart_contract: SmartContractSchema,
|
|
1255
|
+
collection_slug: CollectionSlugSchema.meta({
|
|
1256
|
+
title: "Collection Slug",
|
|
1257
|
+
description: "Slug of the collection this certificate belongs to"
|
|
1258
|
+
}),
|
|
1259
|
+
total_amount: CreditAmountSchema.meta({
|
|
1260
|
+
title: "Certificate Total Amount",
|
|
1261
|
+
description: "Total credits available in this certificate"
|
|
1262
|
+
}),
|
|
1263
|
+
mass_id: MassIdReferenceWithContractSchema
|
|
1264
|
+
};
|
|
1265
|
+
function createReceiptCertificateSchema(params) {
|
|
1266
|
+
return zod.z.strictObject({
|
|
1267
|
+
...certificateBaseShape,
|
|
1268
|
+
...params.additionalShape
|
|
1269
|
+
}).meta(params.meta);
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
// src/shared/receipt/receipt.validation.ts
|
|
1273
|
+
function buildMessage(message, value) {
|
|
1274
|
+
return typeof message === "function" ? message(value) : message;
|
|
1275
|
+
}
|
|
1276
|
+
function createAttributeMap(attributes) {
|
|
1277
|
+
return new Map(
|
|
1278
|
+
attributes.map((attribute) => [attribute.trait_type, attribute])
|
|
1279
|
+
);
|
|
1280
|
+
}
|
|
1281
|
+
function validateSummaryListMatchesData(params) {
|
|
1282
|
+
const { ctx, summaryValues, dataValues, summaryPath } = params;
|
|
1283
|
+
const summarySet = new Set(summaryValues);
|
|
1284
|
+
const dataSet = new Set(dataValues);
|
|
1285
|
+
summarySet.forEach((value) => {
|
|
1286
|
+
if (!dataSet.has(value)) {
|
|
1287
|
+
ctx.addIssue({
|
|
1288
|
+
code: "custom",
|
|
1289
|
+
message: buildMessage(params.missingFromDataMessage, value),
|
|
1290
|
+
path: summaryPath
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1293
|
+
});
|
|
1294
|
+
dataSet.forEach((value) => {
|
|
1295
|
+
if (!summarySet.has(value)) {
|
|
1296
|
+
ctx.addIssue({
|
|
1297
|
+
code: "custom",
|
|
1298
|
+
message: buildMessage(params.missingFromSummaryMessage, value),
|
|
1299
|
+
path: summaryPath
|
|
1300
|
+
});
|
|
1301
|
+
}
|
|
1302
|
+
});
|
|
1303
|
+
}
|
|
1304
|
+
function validateTotalMatches(params) {
|
|
1305
|
+
const { ctx, actualTotal, expectedTotal, path, message } = params;
|
|
1306
|
+
if (!nearlyEqual(actualTotal, expectedTotal)) {
|
|
1307
|
+
ctx.addIssue({
|
|
1308
|
+
code: "custom",
|
|
1309
|
+
message,
|
|
1310
|
+
path
|
|
1311
|
+
});
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
function validateCountMatches(params) {
|
|
1315
|
+
const { ctx, actualCount, expectedCount, path, message } = params;
|
|
1316
|
+
if (actualCount !== expectedCount) {
|
|
1317
|
+
ctx.addIssue({
|
|
1318
|
+
code: "custom",
|
|
1319
|
+
message,
|
|
1320
|
+
path
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
function validateAttributeValue(params) {
|
|
1325
|
+
const {
|
|
1326
|
+
ctx,
|
|
1327
|
+
attributeByTraitType,
|
|
1328
|
+
traitType,
|
|
1329
|
+
expectedValue,
|
|
1330
|
+
missingMessage,
|
|
1331
|
+
mismatchMessage,
|
|
1332
|
+
path = ["attributes"]
|
|
1333
|
+
} = params;
|
|
1334
|
+
const attribute = attributeByTraitType.get(traitType);
|
|
1335
|
+
if (!attribute) {
|
|
1336
|
+
ctx.addIssue({
|
|
1337
|
+
code: "custom",
|
|
1338
|
+
message: missingMessage,
|
|
1339
|
+
path
|
|
1340
|
+
});
|
|
1341
|
+
return;
|
|
1342
|
+
}
|
|
1343
|
+
if (attribute.value !== expectedValue) {
|
|
1344
|
+
ctx.addIssue({
|
|
1345
|
+
code: "custom",
|
|
1346
|
+
message: mismatchMessage,
|
|
1347
|
+
path
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
function validateDateAttribute(params) {
|
|
1352
|
+
const {
|
|
1353
|
+
ctx,
|
|
1354
|
+
attributeByTraitType,
|
|
1355
|
+
traitType,
|
|
1356
|
+
dateValue,
|
|
1357
|
+
missingMessage,
|
|
1358
|
+
invalidDateMessage,
|
|
1359
|
+
mismatchMessage,
|
|
1360
|
+
attributePath = ["attributes"],
|
|
1361
|
+
datePath
|
|
1362
|
+
} = params;
|
|
1363
|
+
const attribute = attributeByTraitType.get(traitType);
|
|
1364
|
+
if (!attribute) {
|
|
1365
|
+
ctx.addIssue({
|
|
1366
|
+
code: "custom",
|
|
1367
|
+
message: missingMessage,
|
|
1368
|
+
path: attributePath
|
|
1369
|
+
});
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
const dateMs = Date.parse(`${dateValue}T00:00:00.000Z`);
|
|
1373
|
+
if (Number.isNaN(dateMs)) {
|
|
1374
|
+
ctx.addIssue({
|
|
1375
|
+
code: "custom",
|
|
1376
|
+
message: invalidDateMessage,
|
|
1377
|
+
path: datePath ?? attributePath
|
|
1378
|
+
});
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
if (attribute.value !== dateMs) {
|
|
1382
|
+
ctx.addIssue({
|
|
1383
|
+
code: "custom",
|
|
1384
|
+
message: mismatchMessage,
|
|
1385
|
+
path: attributePath
|
|
1386
|
+
});
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
function validateAttributesForItems(params) {
|
|
1390
|
+
const {
|
|
1391
|
+
ctx,
|
|
1392
|
+
attributeByTraitType,
|
|
1393
|
+
items,
|
|
1394
|
+
traitSelector,
|
|
1395
|
+
valueSelector,
|
|
1396
|
+
missingMessage,
|
|
1397
|
+
mismatchMessage,
|
|
1398
|
+
path = ["attributes"]
|
|
1399
|
+
} = params;
|
|
1400
|
+
items.forEach((item) => {
|
|
1401
|
+
const traitType = traitSelector(item);
|
|
1402
|
+
const expectedValue = valueSelector(item);
|
|
1403
|
+
const attribute = attributeByTraitType.get(traitType);
|
|
1404
|
+
if (!attribute) {
|
|
1405
|
+
ctx.addIssue({
|
|
1406
|
+
code: "custom",
|
|
1407
|
+
message: missingMessage(traitType),
|
|
1408
|
+
path
|
|
1409
|
+
});
|
|
1410
|
+
return;
|
|
1411
|
+
}
|
|
1412
|
+
if (attribute.value !== expectedValue) {
|
|
1413
|
+
ctx.addIssue({
|
|
1414
|
+
code: "custom",
|
|
1415
|
+
message: mismatchMessage(traitType),
|
|
1416
|
+
path
|
|
1417
|
+
});
|
|
1418
|
+
}
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1088
1421
|
|
|
1089
1422
|
// src/mass-id/mass-id.attributes.ts
|
|
1090
1423
|
var MassIDAttributeWasteTypeSchema = NftAttributeSchema.safeExtend({
|
|
@@ -1905,66 +2238,7 @@ var CreditPurchaseReceiptAttributesSchema = uniqueBy(
|
|
|
1905
2238
|
title: "Credit Purchase Receipt NFT Attribute Array",
|
|
1906
2239
|
description: "Attributes for credit purchase receipts including per-credit breakdowns, totals, receiver, purchase date, and per-collection amounts. Attributes must have unique trait types."
|
|
1907
2240
|
});
|
|
1908
|
-
var
|
|
1909
|
-
total_usdc_amount: NonNegativeFloatSchema.meta({
|
|
1910
|
-
title: "Total USDC Amount",
|
|
1911
|
-
description: "Total amount paid in USDC for the purchase"
|
|
1912
|
-
}),
|
|
1913
|
-
total_credits: CreditAmountSchema.meta({
|
|
1914
|
-
title: "Total Credits",
|
|
1915
|
-
description: "Total amount of credits purchased"
|
|
1916
|
-
}),
|
|
1917
|
-
total_certificates: PositiveIntegerSchema.meta({
|
|
1918
|
-
title: "Total Certificates",
|
|
1919
|
-
description: "Total number of certificates purchased"
|
|
1920
|
-
}),
|
|
1921
|
-
purchase_date: IsoDateSchema.meta({
|
|
1922
|
-
title: "Purchase Date",
|
|
1923
|
-
description: "Date when the purchase was made (YYYY-MM-DD)"
|
|
1924
|
-
}),
|
|
1925
|
-
credit_symbols: uniqueArrayItems(
|
|
1926
|
-
TokenSymbolSchema,
|
|
1927
|
-
"Credit symbols must be unique"
|
|
1928
|
-
).min(1).meta({
|
|
1929
|
-
title: "Credit Symbols",
|
|
1930
|
-
description: "Array of credit token symbols included in the purchase"
|
|
1931
|
-
}),
|
|
1932
|
-
certificate_types: uniqueArrayItems(
|
|
1933
|
-
RecordSchemaTypeSchema.extract(["GasID", "RecycledID"]),
|
|
1934
|
-
"Certificate types must be unique"
|
|
1935
|
-
).min(1).meta({
|
|
1936
|
-
title: "Certificate Types",
|
|
1937
|
-
description: "Array of certificate types included in the purchase"
|
|
1938
|
-
}),
|
|
1939
|
-
collection_slugs: uniqueArrayItems(
|
|
1940
|
-
CollectionSlugSchema,
|
|
1941
|
-
"Collection slugs must be unique"
|
|
1942
|
-
).min(1).meta({
|
|
1943
|
-
title: "Collection Slugs",
|
|
1944
|
-
description: "Array of collection slugs represented in the purchase"
|
|
1945
|
-
})
|
|
1946
|
-
}).meta({
|
|
1947
|
-
title: "Credit Purchase Receipt Summary",
|
|
1948
|
-
description: "Summary totals for the credit purchase including amounts and collections represented"
|
|
1949
|
-
});
|
|
1950
|
-
var CreditPurchaseReceiptIdentitySchema = zod.z.strictObject({
|
|
1951
|
-
name: ParticipantNameSchema.meta({
|
|
1952
|
-
title: "Identity Name",
|
|
1953
|
-
description: "Display name for the participant",
|
|
1954
|
-
examples: ["EcoTech Solutions Inc."]
|
|
1955
|
-
}),
|
|
1956
|
-
external_id: ExternalIdSchema.meta({
|
|
1957
|
-
title: "Identity External ID",
|
|
1958
|
-
description: "External identifier for the participant"
|
|
1959
|
-
}),
|
|
1960
|
-
external_url: ExternalUrlSchema.meta({
|
|
1961
|
-
title: "Identity External URL",
|
|
1962
|
-
description: "External URL for the participant profile"
|
|
1963
|
-
})
|
|
1964
|
-
}).meta({
|
|
1965
|
-
title: "Identity",
|
|
1966
|
-
description: "Participant identity information"
|
|
1967
|
-
});
|
|
2241
|
+
var CreditPurchaseReceiptIdentitySchema = ReceiptIdentitySchema;
|
|
1968
2242
|
var CreditPurchaseReceiptReceiverSchema = zod.z.strictObject({
|
|
1969
2243
|
wallet_address: EthereumAddressSchema.meta({
|
|
1970
2244
|
title: "Receiver Wallet Address",
|
|
@@ -1996,123 +2270,52 @@ var CreditPurchaseReceiptPartiesSchema = zod.z.strictObject({
|
|
|
1996
2270
|
title: "Parties",
|
|
1997
2271
|
description: "Parties involved in the purchase including payer, receiver, and optional buyer"
|
|
1998
2272
|
});
|
|
1999
|
-
var CreditPurchaseReceiptCollectionSchema =
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
title: "Collection External ID",
|
|
2003
|
-
description: "External identifier for the collection"
|
|
2004
|
-
}),
|
|
2005
|
-
name: CollectionNameSchema,
|
|
2006
|
-
external_url: ExternalUrlSchema.meta({
|
|
2007
|
-
title: "Collection External URL",
|
|
2008
|
-
description: "External URL for the collection"
|
|
2009
|
-
}),
|
|
2010
|
-
uri: IpfsUriSchema.meta({
|
|
2011
|
-
title: "Collection URI",
|
|
2012
|
-
description: "IPFS URI for the collection metadata"
|
|
2013
|
-
}),
|
|
2014
|
-
credit_amount: CreditAmountSchema.meta({
|
|
2273
|
+
var CreditPurchaseReceiptCollectionSchema = createReceiptCollectionSchema({
|
|
2274
|
+
amountKey: "credit_amount",
|
|
2275
|
+
amountMeta: {
|
|
2015
2276
|
title: "Collection Credit Amount",
|
|
2016
2277
|
description: "Total credits purchased from this collection"
|
|
2017
|
-
}
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2278
|
+
},
|
|
2279
|
+
meta: {
|
|
2280
|
+
title: "Collection",
|
|
2281
|
+
description: "Collection included in the purchase"
|
|
2282
|
+
}
|
|
2021
2283
|
});
|
|
2022
|
-
var CreditPurchaseReceiptCreditSchema =
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
description: "URL-friendly identifier for the credit"
|
|
2026
|
-
}),
|
|
2027
|
-
symbol: TokenSymbolSchema.meta({
|
|
2028
|
-
title: "Credit Token Symbol",
|
|
2029
|
-
description: "Symbol of the credit token",
|
|
2030
|
-
examples: ["C-CARB", "C-BIOW"]
|
|
2031
|
-
}),
|
|
2032
|
-
external_id: ExternalIdSchema.meta({
|
|
2033
|
-
title: "Credit External ID",
|
|
2034
|
-
description: "External identifier for the credit"
|
|
2035
|
-
}),
|
|
2036
|
-
external_url: ExternalUrlSchema.meta({
|
|
2037
|
-
title: "Credit External URL",
|
|
2038
|
-
description: "External URL for the credit"
|
|
2039
|
-
}),
|
|
2040
|
-
uri: IpfsUriSchema.meta({
|
|
2041
|
-
title: "Credit URI",
|
|
2042
|
-
description: "IPFS URI for the credit details"
|
|
2043
|
-
}),
|
|
2044
|
-
smart_contract: SmartContractSchema,
|
|
2045
|
-
purchase_amount: CreditAmountSchema.meta({
|
|
2284
|
+
var CreditPurchaseReceiptCreditSchema = createReceiptCreditSchema({
|
|
2285
|
+
amountKey: "purchase_amount",
|
|
2286
|
+
amountMeta: {
|
|
2046
2287
|
title: "Credit Purchase Amount",
|
|
2047
2288
|
description: "Total credits purchased for this credit type"
|
|
2048
|
-
}
|
|
2049
|
-
|
|
2289
|
+
},
|
|
2290
|
+
retirementAmountMeta: {
|
|
2050
2291
|
title: "Credit Retirement Amount",
|
|
2051
2292
|
description: "Credits retired immediately for this credit type during purchase"
|
|
2052
|
-
}
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2293
|
+
},
|
|
2294
|
+
meta: {
|
|
2295
|
+
title: "Credit",
|
|
2296
|
+
description: "Credit token included in the purchase"
|
|
2297
|
+
}
|
|
2056
2298
|
});
|
|
2057
|
-
var
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
}),
|
|
2078
|
-
external_id: ExternalIdSchema.meta({
|
|
2079
|
-
title: "Certificate External ID",
|
|
2080
|
-
description: "External identifier for the certificate"
|
|
2081
|
-
}),
|
|
2082
|
-
external_url: ExternalUrlSchema.meta({
|
|
2083
|
-
title: "Certificate External URL",
|
|
2084
|
-
description: "External URL for the certificate"
|
|
2085
|
-
}),
|
|
2086
|
-
uri: IpfsUriSchema.meta({
|
|
2087
|
-
title: "Certificate URI",
|
|
2088
|
-
description: "IPFS URI for the certificate metadata"
|
|
2089
|
-
}),
|
|
2090
|
-
smart_contract: SmartContractSchema,
|
|
2091
|
-
collection_slug: CollectionSlugSchema.meta({
|
|
2092
|
-
title: "Collection Slug",
|
|
2093
|
-
description: "Slug of the collection this certificate belongs to"
|
|
2094
|
-
}),
|
|
2095
|
-
total_amount: CreditAmountSchema.meta({
|
|
2096
|
-
title: "Certificate Total Amount",
|
|
2097
|
-
description: "Total credits available in this certificate"
|
|
2098
|
-
}),
|
|
2099
|
-
purchased_amount: CreditAmountSchema.meta({
|
|
2100
|
-
title: "Certificate Purchased Amount",
|
|
2101
|
-
description: "Credits purchased from this certificate"
|
|
2102
|
-
}),
|
|
2103
|
-
retired_amount: CreditAmountSchema.meta({
|
|
2104
|
-
title: "Certificate Retired Amount",
|
|
2105
|
-
description: "Credits retired from this certificate during the purchase (0 if none)"
|
|
2106
|
-
}),
|
|
2107
|
-
credit_slug: SlugSchema.meta({
|
|
2108
|
-
title: "Credit Slug",
|
|
2109
|
-
description: "Slug of the credit type for this certificate",
|
|
2110
|
-
examples: ["carbon", "organic"]
|
|
2111
|
-
}),
|
|
2112
|
-
mass_id: MassIDReferenceWithContractSchema
|
|
2113
|
-
}).meta({
|
|
2114
|
-
title: "Certificate",
|
|
2115
|
-
description: "Certificate associated with the purchase"
|
|
2299
|
+
var CreditPurchaseReceiptCertificateSchema = createReceiptCertificateSchema({
|
|
2300
|
+
additionalShape: {
|
|
2301
|
+
purchased_amount: CreditAmountSchema.meta({
|
|
2302
|
+
title: "Certificate Purchased Amount",
|
|
2303
|
+
description: "Credits purchased from this certificate"
|
|
2304
|
+
}),
|
|
2305
|
+
retired_amount: CreditAmountSchema.meta({
|
|
2306
|
+
title: "Certificate Retired Amount",
|
|
2307
|
+
description: "Credits retired from this certificate during the purchase (0 if none)"
|
|
2308
|
+
}),
|
|
2309
|
+
credit_slug: SlugSchema.meta({
|
|
2310
|
+
title: "Credit Slug",
|
|
2311
|
+
description: "Slug of the credit type for this certificate",
|
|
2312
|
+
examples: ["carbon", "organic"]
|
|
2313
|
+
})
|
|
2314
|
+
},
|
|
2315
|
+
meta: {
|
|
2316
|
+
title: "Certificate",
|
|
2317
|
+
description: "Certificate associated with the purchase"
|
|
2318
|
+
}
|
|
2116
2319
|
});
|
|
2117
2320
|
var CreditPurchaseReceiptParticipantRewardSchema = zod.z.strictObject({
|
|
2118
2321
|
id_hash: Sha256HashSchema.meta({
|
|
@@ -2170,10 +2373,6 @@ var CreditPurchaseReceiptRetirementSchema = zod.z.strictObject({
|
|
|
2170
2373
|
title: "Retirement",
|
|
2171
2374
|
description: "Immediate retirement details performed as part of purchase"
|
|
2172
2375
|
});
|
|
2173
|
-
var EPSILON = 1e-9;
|
|
2174
|
-
function nearlyEqual(a, b) {
|
|
2175
|
-
return Math.abs(a - b) <= EPSILON;
|
|
2176
|
-
}
|
|
2177
2376
|
var CreditPurchaseReceiptDataSchema = zod.z.strictObject({
|
|
2178
2377
|
summary: CreditPurchaseReceiptSummarySchema,
|
|
2179
2378
|
parties: CreditPurchaseReceiptPartiesSchema,
|
|
@@ -2214,7 +2413,8 @@ var CreditPurchaseReceiptDataSchema = zod.z.strictObject({
|
|
|
2214
2413
|
const retirementProvided = Boolean(data.retirement);
|
|
2215
2414
|
const creditsWithRetirement = data.credits.reduce(
|
|
2216
2415
|
(indices, credit, index) => {
|
|
2217
|
-
|
|
2416
|
+
const retirementAmount = Number(credit.retirement_amount ?? 0);
|
|
2417
|
+
if (retirementAmount > 0) {
|
|
2218
2418
|
indices.push(index);
|
|
2219
2419
|
}
|
|
2220
2420
|
return indices;
|
|
@@ -2237,77 +2437,48 @@ var CreditPurchaseReceiptDataSchema = zod.z.strictObject({
|
|
|
2237
2437
|
});
|
|
2238
2438
|
});
|
|
2239
2439
|
}
|
|
2440
|
+
validateCountMatches({
|
|
2441
|
+
ctx,
|
|
2442
|
+
actualCount: data.certificates.length,
|
|
2443
|
+
expectedCount: data.summary.total_certificates,
|
|
2444
|
+
path: ["summary", "total_certificates"],
|
|
2445
|
+
message: "summary.total_certificates must equal the number of certificates"
|
|
2446
|
+
});
|
|
2240
2447
|
const collectionSlugs = new Set(
|
|
2241
|
-
data.collections.map((collection) => collection.slug)
|
|
2448
|
+
data.collections.map((collection) => String(collection.slug))
|
|
2449
|
+
);
|
|
2450
|
+
const creditSlugs = new Set(
|
|
2451
|
+
data.credits.map((credit) => String(credit.slug))
|
|
2452
|
+
);
|
|
2453
|
+
const creditSymbols = new Set(
|
|
2454
|
+
data.credits.map((credit) => String(credit.symbol))
|
|
2242
2455
|
);
|
|
2243
|
-
const creditSlugs = new Set(data.credits.map((credit) => credit.slug));
|
|
2244
|
-
const creditSymbols = new Set(data.credits.map((credit) => credit.symbol));
|
|
2245
|
-
const summaryCreditSymbols = new Set(data.summary.credit_symbols);
|
|
2246
|
-
const summaryCollectionSlugs = new Set(data.summary.collection_slugs);
|
|
2247
|
-
const summaryCertificateTypes = new Set(data.summary.certificate_types);
|
|
2248
|
-
if (data.summary.total_certificates !== data.certificates.length) {
|
|
2249
|
-
ctx.addIssue({
|
|
2250
|
-
code: "custom",
|
|
2251
|
-
message: "summary.total_certificates must equal the number of certificates",
|
|
2252
|
-
path: ["summary", "total_certificates"]
|
|
2253
|
-
});
|
|
2254
|
-
}
|
|
2255
|
-
data.summary.credit_symbols.forEach((symbol) => {
|
|
2256
|
-
if (!creditSymbols.has(symbol)) {
|
|
2257
|
-
ctx.addIssue({
|
|
2258
|
-
code: "custom",
|
|
2259
|
-
message: "summary.credit_symbols must reference symbols from credits",
|
|
2260
|
-
path: ["summary", "credit_symbols"]
|
|
2261
|
-
});
|
|
2262
|
-
}
|
|
2263
|
-
});
|
|
2264
|
-
creditSymbols.forEach((symbol) => {
|
|
2265
|
-
if (!summaryCreditSymbols.has(symbol)) {
|
|
2266
|
-
ctx.addIssue({
|
|
2267
|
-
code: "custom",
|
|
2268
|
-
message: "All credit symbols must be listed in summary.credit_symbols",
|
|
2269
|
-
path: ["summary", "credit_symbols"]
|
|
2270
|
-
});
|
|
2271
|
-
}
|
|
2272
|
-
});
|
|
2273
|
-
data.summary.collection_slugs.forEach((slug) => {
|
|
2274
|
-
if (!collectionSlugs.has(slug)) {
|
|
2275
|
-
ctx.addIssue({
|
|
2276
|
-
code: "custom",
|
|
2277
|
-
message: "summary.collection_slugs must reference slugs from collections",
|
|
2278
|
-
path: ["summary", "collection_slugs"]
|
|
2279
|
-
});
|
|
2280
|
-
}
|
|
2281
|
-
});
|
|
2282
|
-
collectionSlugs.forEach((slug) => {
|
|
2283
|
-
if (!summaryCollectionSlugs.has(slug)) {
|
|
2284
|
-
ctx.addIssue({
|
|
2285
|
-
code: "custom",
|
|
2286
|
-
message: "All collection slugs must be listed in summary.collection_slugs",
|
|
2287
|
-
path: ["summary", "collection_slugs"]
|
|
2288
|
-
});
|
|
2289
|
-
}
|
|
2290
|
-
});
|
|
2291
2456
|
const certificateTypes = new Set(
|
|
2292
|
-
data.certificates.map((certificate) => certificate.type)
|
|
2457
|
+
data.certificates.map((certificate) => String(certificate.type))
|
|
2293
2458
|
);
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
}
|
|
2459
|
+
validateSummaryListMatchesData({
|
|
2460
|
+
ctx,
|
|
2461
|
+
summaryValues: data.summary.credit_symbols,
|
|
2462
|
+
dataValues: creditSymbols,
|
|
2463
|
+
summaryPath: ["summary", "credit_symbols"],
|
|
2464
|
+
missingFromDataMessage: "summary.credit_symbols must reference symbols from credits",
|
|
2465
|
+
missingFromSummaryMessage: "All credit symbols must be listed in summary.credit_symbols"
|
|
2302
2466
|
});
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2467
|
+
validateSummaryListMatchesData({
|
|
2468
|
+
ctx,
|
|
2469
|
+
summaryValues: data.summary.collection_slugs,
|
|
2470
|
+
dataValues: collectionSlugs,
|
|
2471
|
+
summaryPath: ["summary", "collection_slugs"],
|
|
2472
|
+
missingFromDataMessage: "summary.collection_slugs must reference slugs from collections",
|
|
2473
|
+
missingFromSummaryMessage: "All collection slugs must be listed in summary.collection_slugs"
|
|
2474
|
+
});
|
|
2475
|
+
validateSummaryListMatchesData({
|
|
2476
|
+
ctx,
|
|
2477
|
+
summaryValues: data.summary.certificate_types,
|
|
2478
|
+
dataValues: certificateTypes,
|
|
2479
|
+
summaryPath: ["summary", "certificate_types"],
|
|
2480
|
+
missingFromDataMessage: "summary.certificate_types must reference types present in certificates",
|
|
2481
|
+
missingFromSummaryMessage: "All certificate types must be listed in summary.certificate_types"
|
|
2311
2482
|
});
|
|
2312
2483
|
const creditPurchaseTotalsBySlug = /* @__PURE__ */ new Map();
|
|
2313
2484
|
const creditRetiredTotalsBySlug = /* @__PURE__ */ new Map();
|
|
@@ -2342,60 +2513,60 @@ var CreditPurchaseReceiptDataSchema = zod.z.strictObject({
|
|
|
2342
2513
|
path: ["certificates", index, "purchased_amount"]
|
|
2343
2514
|
});
|
|
2344
2515
|
}
|
|
2345
|
-
totalCreditsFromCertificates += certificate.purchased_amount;
|
|
2516
|
+
totalCreditsFromCertificates += Number(certificate.purchased_amount);
|
|
2346
2517
|
creditPurchaseTotalsBySlug.set(
|
|
2347
|
-
certificate.credit_slug,
|
|
2348
|
-
(creditPurchaseTotalsBySlug.get(certificate.credit_slug) ?? 0) + certificate.purchased_amount
|
|
2518
|
+
String(certificate.credit_slug),
|
|
2519
|
+
(creditPurchaseTotalsBySlug.get(certificate.credit_slug) ?? 0) + Number(certificate.purchased_amount)
|
|
2349
2520
|
);
|
|
2350
2521
|
creditRetiredTotalsBySlug.set(
|
|
2351
|
-
certificate.credit_slug,
|
|
2352
|
-
(creditRetiredTotalsBySlug.get(certificate.credit_slug) ?? 0) + certificate.retired_amount
|
|
2522
|
+
String(certificate.credit_slug),
|
|
2523
|
+
(creditRetiredTotalsBySlug.get(certificate.credit_slug) ?? 0) + Number(certificate.retired_amount)
|
|
2353
2524
|
);
|
|
2354
2525
|
collectionTotalsBySlug.set(
|
|
2355
|
-
certificate.collection_slug,
|
|
2356
|
-
(collectionTotalsBySlug.get(certificate.collection_slug) ?? 0) + certificate.purchased_amount
|
|
2526
|
+
String(certificate.collection_slug),
|
|
2527
|
+
(collectionTotalsBySlug.get(certificate.collection_slug) ?? 0) + Number(certificate.purchased_amount)
|
|
2357
2528
|
);
|
|
2358
2529
|
});
|
|
2359
2530
|
const totalCreditsFromCollections = data.collections.reduce(
|
|
2360
|
-
(sum, collection) => sum + collection.credit_amount,
|
|
2531
|
+
(sum, collection) => sum + Number(collection.credit_amount),
|
|
2361
2532
|
0
|
|
2362
2533
|
);
|
|
2363
2534
|
const totalCreditsFromCredits = data.credits.reduce(
|
|
2364
|
-
(sum, credit) => sum + credit.purchase_amount,
|
|
2535
|
+
(sum, credit) => sum + Number(credit.purchase_amount),
|
|
2365
2536
|
0
|
|
2366
2537
|
);
|
|
2367
|
-
|
|
2368
|
-
ctx
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
}
|
|
2374
|
-
|
|
2375
|
-
ctx
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
}
|
|
2381
|
-
|
|
2382
|
-
ctx
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
}
|
|
2538
|
+
validateTotalMatches({
|
|
2539
|
+
ctx,
|
|
2540
|
+
actualTotal: totalCreditsFromCertificates,
|
|
2541
|
+
expectedTotal: data.summary.total_credits,
|
|
2542
|
+
path: ["summary", "total_credits"],
|
|
2543
|
+
message: "summary.total_credits must equal sum of certificates.purchased_amount"
|
|
2544
|
+
});
|
|
2545
|
+
validateTotalMatches({
|
|
2546
|
+
ctx,
|
|
2547
|
+
actualTotal: totalCreditsFromCredits,
|
|
2548
|
+
expectedTotal: data.summary.total_credits,
|
|
2549
|
+
path: ["summary", "total_credits"],
|
|
2550
|
+
message: "summary.total_credits must equal sum of credits.purchase_amount"
|
|
2551
|
+
});
|
|
2552
|
+
validateTotalMatches({
|
|
2553
|
+
ctx,
|
|
2554
|
+
actualTotal: totalCreditsFromCollections,
|
|
2555
|
+
expectedTotal: data.summary.total_credits,
|
|
2556
|
+
path: ["summary", "total_credits"],
|
|
2557
|
+
message: "summary.total_credits must equal sum of collections.credit_amount"
|
|
2558
|
+
});
|
|
2388
2559
|
data.credits.forEach((credit, index) => {
|
|
2389
|
-
const purchasedTotal = creditPurchaseTotalsBySlug.get(credit.slug) ?? 0;
|
|
2390
|
-
if (!nearlyEqual(credit.purchase_amount, purchasedTotal)) {
|
|
2560
|
+
const purchasedTotal = creditPurchaseTotalsBySlug.get(String(credit.slug)) ?? 0;
|
|
2561
|
+
if (!nearlyEqual(Number(credit.purchase_amount), purchasedTotal)) {
|
|
2391
2562
|
ctx.addIssue({
|
|
2392
2563
|
code: "custom",
|
|
2393
2564
|
message: "credit.purchase_amount must equal sum of certificate purchased_amount for the credit slug",
|
|
2394
2565
|
path: ["credits", index, "purchase_amount"]
|
|
2395
2566
|
});
|
|
2396
2567
|
}
|
|
2397
|
-
const retiredTotal = creditRetiredTotalsBySlug.get(credit.slug) ?? 0;
|
|
2398
|
-
const retirementAmount = credit.retirement_amount ?? 0;
|
|
2568
|
+
const retiredTotal = creditRetiredTotalsBySlug.get(String(credit.slug)) ?? 0;
|
|
2569
|
+
const retirementAmount = Number(credit.retirement_amount ?? 0);
|
|
2399
2570
|
if (!nearlyEqual(retirementAmount, retiredTotal)) {
|
|
2400
2571
|
ctx.addIssue({
|
|
2401
2572
|
code: "custom",
|
|
@@ -2405,8 +2576,8 @@ var CreditPurchaseReceiptDataSchema = zod.z.strictObject({
|
|
|
2405
2576
|
}
|
|
2406
2577
|
});
|
|
2407
2578
|
data.collections.forEach((collection, index) => {
|
|
2408
|
-
const purchasedTotal = collectionTotalsBySlug.get(collection.slug) ?? 0;
|
|
2409
|
-
if (!nearlyEqual(collection.credit_amount, purchasedTotal)) {
|
|
2579
|
+
const purchasedTotal = collectionTotalsBySlug.get(String(collection.slug)) ?? 0;
|
|
2580
|
+
if (!nearlyEqual(Number(collection.credit_amount), purchasedTotal)) {
|
|
2410
2581
|
ctx.addIssue({
|
|
2411
2582
|
code: "custom",
|
|
2412
2583
|
message: "collection.credit_amount must equal sum of certificate purchased_amount for the collection slug",
|
|
@@ -2415,16 +2586,16 @@ var CreditPurchaseReceiptDataSchema = zod.z.strictObject({
|
|
|
2415
2586
|
}
|
|
2416
2587
|
});
|
|
2417
2588
|
const participantRewardTotal = data.participant_rewards.reduce(
|
|
2418
|
-
(sum, reward) => sum + reward.usdc_amount,
|
|
2589
|
+
(sum, reward) => sum + Number(reward.usdc_amount),
|
|
2419
2590
|
0
|
|
2420
2591
|
);
|
|
2421
|
-
|
|
2422
|
-
ctx
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
}
|
|
2592
|
+
validateTotalMatches({
|
|
2593
|
+
ctx,
|
|
2594
|
+
actualTotal: participantRewardTotal,
|
|
2595
|
+
expectedTotal: data.summary.total_usdc_amount,
|
|
2596
|
+
path: ["summary", "total_usdc_amount"],
|
|
2597
|
+
message: "summary.total_usdc_amount must equal sum of participant_rewards.usdc_amount"
|
|
2598
|
+
});
|
|
2428
2599
|
}).meta({
|
|
2429
2600
|
title: "Credit Purchase Receipt Data",
|
|
2430
2601
|
description: "Complete data structure for a credit purchase receipt"
|
|
@@ -2449,133 +2620,595 @@ var CreditPurchaseReceiptIpfsSchema = NftIpfsSchema.safeExtend({
|
|
|
2449
2620
|
}).superRefine((value, ctx) => {
|
|
2450
2621
|
const attributes = value.attributes;
|
|
2451
2622
|
const data = value.data;
|
|
2452
|
-
const attributeByTraitType =
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
"Total Credits Purchased"
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2623
|
+
const attributeByTraitType = createAttributeMap(attributes);
|
|
2624
|
+
validateAttributeValue({
|
|
2625
|
+
ctx,
|
|
2626
|
+
attributeByTraitType,
|
|
2627
|
+
traitType: "Total Credits Purchased",
|
|
2628
|
+
expectedValue: data.summary.total_credits,
|
|
2629
|
+
missingMessage: 'Attribute "Total Credits Purchased" is required',
|
|
2630
|
+
mismatchMessage: 'Attribute "Total Credits Purchased" must match data.summary.total_credits'
|
|
2631
|
+
});
|
|
2632
|
+
validateAttributeValue({
|
|
2633
|
+
ctx,
|
|
2634
|
+
attributeByTraitType,
|
|
2635
|
+
traitType: "Total USDC Amount",
|
|
2636
|
+
expectedValue: data.summary.total_usdc_amount,
|
|
2637
|
+
missingMessage: 'Attribute "Total USDC Amount" is required',
|
|
2638
|
+
mismatchMessage: 'Attribute "Total USDC Amount" must match data.summary.total_usdc_amount'
|
|
2639
|
+
});
|
|
2640
|
+
validateAttributeValue({
|
|
2641
|
+
ctx,
|
|
2642
|
+
attributeByTraitType,
|
|
2643
|
+
traitType: "Certificates Purchased",
|
|
2644
|
+
expectedValue: data.summary.total_certificates,
|
|
2645
|
+
missingMessage: 'Attribute "Certificates Purchased" is required',
|
|
2646
|
+
mismatchMessage: 'Attribute "Certificates Purchased" must match data.summary.total_certificates'
|
|
2647
|
+
});
|
|
2648
|
+
const receiverName = data.parties.receiver.identity?.name;
|
|
2649
|
+
if (receiverName) {
|
|
2650
|
+
validateAttributeValue({
|
|
2651
|
+
ctx,
|
|
2652
|
+
attributeByTraitType,
|
|
2653
|
+
traitType: "Receiver",
|
|
2654
|
+
expectedValue: String(receiverName),
|
|
2655
|
+
missingMessage: 'Attribute "Receiver" is required when receiver.identity.name is provided',
|
|
2656
|
+
mismatchMessage: 'Attribute "Receiver" must match receiver.identity.name'
|
|
2470
2657
|
});
|
|
2471
2658
|
}
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2659
|
+
validateDateAttribute({
|
|
2660
|
+
ctx,
|
|
2661
|
+
attributeByTraitType,
|
|
2662
|
+
traitType: "Purchase Date",
|
|
2663
|
+
dateValue: data.summary.purchase_date,
|
|
2664
|
+
missingMessage: 'Attribute "Purchase Date" is required',
|
|
2665
|
+
invalidDateMessage: "data.summary.purchase_date must be a valid date string",
|
|
2666
|
+
mismatchMessage: 'Attribute "Purchase Date" must match data.summary.purchase_date as a Unix timestamp in milliseconds',
|
|
2667
|
+
datePath: ["data", "summary", "purchase_date"]
|
|
2668
|
+
});
|
|
2669
|
+
validateAttributesForItems({
|
|
2670
|
+
ctx,
|
|
2671
|
+
attributeByTraitType,
|
|
2672
|
+
items: data.credits,
|
|
2673
|
+
traitSelector: (credit) => String(credit.symbol),
|
|
2674
|
+
valueSelector: (credit) => Number(credit.purchase_amount),
|
|
2675
|
+
missingMessage: (symbol) => `Attribute for credit symbol ${symbol} is required`,
|
|
2676
|
+
mismatchMessage: (symbol) => `Attribute for credit symbol ${symbol} must match credit.purchase_amount`
|
|
2677
|
+
});
|
|
2678
|
+
validateAttributesForItems({
|
|
2679
|
+
ctx,
|
|
2680
|
+
attributeByTraitType,
|
|
2681
|
+
items: data.collections,
|
|
2682
|
+
traitSelector: (collection) => String(collection.name),
|
|
2683
|
+
valueSelector: (collection) => Number(collection.credit_amount),
|
|
2684
|
+
missingMessage: (name) => `Attribute for collection ${name} is required`,
|
|
2685
|
+
mismatchMessage: (name) => `Attribute for collection ${name} must match collection.credit_amount`
|
|
2686
|
+
});
|
|
2687
|
+
}).meta(CreditPurchaseReceiptIpfsSchemaMeta);
|
|
2688
|
+
var CreditRetirementReceiptCreditAttributeSchema = NftAttributeSchema.safeExtend({
|
|
2689
|
+
trait_type: CreditTokenSymbolSchema,
|
|
2690
|
+
value: CreditAmountSchema.meta({
|
|
2691
|
+
title: "Credit Retirement Amount",
|
|
2692
|
+
description: "Amount of credits retired for the token symbol"
|
|
2693
|
+
}),
|
|
2694
|
+
display_type: zod.z.literal("number")
|
|
2695
|
+
}).meta({
|
|
2696
|
+
title: "Credit Attribute",
|
|
2697
|
+
description: "Attribute representing retired amount per credit token symbol"
|
|
2698
|
+
});
|
|
2699
|
+
var CreditRetirementReceiptTotalCreditsAttributeSchema = NftAttributeSchema.safeExtend({
|
|
2700
|
+
trait_type: zod.z.literal("Total Credits Retired"),
|
|
2701
|
+
value: CreditAmountSchema.meta({
|
|
2702
|
+
title: "Total Credits Retired",
|
|
2703
|
+
description: "Total number of credits retired across all tokens"
|
|
2704
|
+
}),
|
|
2705
|
+
display_type: zod.z.literal("number")
|
|
2706
|
+
}).meta({
|
|
2707
|
+
title: "Total Credits Retired Attribute",
|
|
2708
|
+
description: "Aggregate credits retired attribute"
|
|
2709
|
+
});
|
|
2710
|
+
var CreditRetirementReceiptBeneficiaryAttributeSchema = NftAttributeSchema.safeExtend({
|
|
2711
|
+
trait_type: zod.z.literal("Beneficiary"),
|
|
2712
|
+
value: ParticipantNameSchema.meta({
|
|
2713
|
+
title: "Beneficiary",
|
|
2714
|
+
description: "Beneficiary receiving the retirement benefit",
|
|
2715
|
+
examples: ["Climate Action Corp"]
|
|
2716
|
+
})
|
|
2717
|
+
}).meta({
|
|
2718
|
+
title: "Beneficiary Attribute",
|
|
2719
|
+
description: "Attribute containing the beneficiary display name"
|
|
2720
|
+
});
|
|
2721
|
+
var CreditRetirementReceiptCreditHolderAttributeSchema = NftAttributeSchema.safeExtend({
|
|
2722
|
+
trait_type: zod.z.literal("Credit Holder"),
|
|
2723
|
+
value: ParticipantNameSchema.meta({
|
|
2724
|
+
title: "Credit Holder",
|
|
2725
|
+
description: "Entity that surrendered the credits",
|
|
2726
|
+
examples: ["EcoTech Solutions Inc."]
|
|
2727
|
+
})
|
|
2728
|
+
}).meta({
|
|
2729
|
+
title: "Credit Holder Attribute",
|
|
2730
|
+
description: "Attribute containing the credit holder display name"
|
|
2731
|
+
});
|
|
2732
|
+
var CreditRetirementReceiptRetirementDateAttributeSchema = NftAttributeSchema.safeExtend({
|
|
2733
|
+
trait_type: zod.z.literal("Retirement Date"),
|
|
2734
|
+
value: UnixTimestampSchema.meta({
|
|
2735
|
+
title: "Retirement Date",
|
|
2736
|
+
description: "Unix timestamp in milliseconds when the retirement was completed"
|
|
2737
|
+
}),
|
|
2738
|
+
display_type: zod.z.literal("date")
|
|
2739
|
+
}).meta({
|
|
2740
|
+
title: "Retirement Date Attribute",
|
|
2741
|
+
description: "Retirement date attribute using Unix timestamp in milliseconds"
|
|
2742
|
+
});
|
|
2743
|
+
var CreditRetirementReceiptCertificatesAttributeSchema = NftAttributeSchema.safeExtend({
|
|
2744
|
+
trait_type: zod.z.literal("Certificates Retired"),
|
|
2745
|
+
value: PositiveIntegerSchema.meta({
|
|
2746
|
+
title: "Certificates Retired",
|
|
2747
|
+
description: "Total number of certificates retired"
|
|
2748
|
+
}),
|
|
2749
|
+
display_type: zod.z.literal("number")
|
|
2750
|
+
}).meta({
|
|
2751
|
+
title: "Certificates Retired Attribute",
|
|
2752
|
+
description: "Attribute representing how many certificates were retired in total"
|
|
2753
|
+
});
|
|
2754
|
+
var CreditRetirementReceiptCollectionAttributeSchema = NftAttributeSchema.safeExtend({
|
|
2755
|
+
trait_type: CollectionNameSchema,
|
|
2756
|
+
value: CreditAmountSchema.meta({
|
|
2757
|
+
title: "Credits from Collection",
|
|
2758
|
+
description: "Amount of credits retired from the collection"
|
|
2759
|
+
}),
|
|
2760
|
+
display_type: zod.z.literal("number")
|
|
2761
|
+
}).meta({
|
|
2762
|
+
title: "Collection Attribute",
|
|
2763
|
+
description: "Attribute representing the amount of credits retired from a collection"
|
|
2764
|
+
});
|
|
2765
|
+
var CreditRetirementReceiptAttributesSchema = uniqueBy(
|
|
2766
|
+
zod.z.union([
|
|
2767
|
+
CreditRetirementReceiptCreditAttributeSchema,
|
|
2768
|
+
CreditRetirementReceiptTotalCreditsAttributeSchema,
|
|
2769
|
+
CreditRetirementReceiptBeneficiaryAttributeSchema,
|
|
2770
|
+
CreditRetirementReceiptCreditHolderAttributeSchema,
|
|
2771
|
+
CreditRetirementReceiptRetirementDateAttributeSchema,
|
|
2772
|
+
CreditRetirementReceiptCertificatesAttributeSchema,
|
|
2773
|
+
CreditRetirementReceiptCollectionAttributeSchema
|
|
2774
|
+
]),
|
|
2775
|
+
(attribute) => attribute.trait_type,
|
|
2776
|
+
"Attribute trait_type values must be unique"
|
|
2777
|
+
).min(6).meta({
|
|
2778
|
+
title: "Credit Retirement Receipt NFT Attribute Array",
|
|
2779
|
+
description: "Attributes for credit retirement receipts including per-credit breakdowns, totals, beneficiary, credit holder, retirement date, certificate count, and per-collection amounts. Attributes must have unique trait types."
|
|
2780
|
+
});
|
|
2781
|
+
var CreditRetirementReceiptIdentitySchema = ReceiptIdentitySchema;
|
|
2782
|
+
var CreditRetirementReceiptBeneficiarySchema = zod.z.strictObject({
|
|
2783
|
+
beneficiary_id: ExternalIdSchema.meta({
|
|
2784
|
+
title: "Retirement Beneficiary ID",
|
|
2785
|
+
description: "UUID identifying the beneficiary of the retirement (bytes16 normalized to UUID)"
|
|
2786
|
+
}),
|
|
2787
|
+
identity: CreditRetirementReceiptIdentitySchema
|
|
2788
|
+
}).meta({
|
|
2789
|
+
title: "Beneficiary",
|
|
2790
|
+
description: "Beneficiary receiving the retirement benefit"
|
|
2791
|
+
});
|
|
2792
|
+
var CreditRetirementReceiptCreditHolderSchema = zod.z.strictObject({
|
|
2793
|
+
wallet_address: EthereumAddressSchema.meta({
|
|
2794
|
+
title: "Credit Holder Wallet Address",
|
|
2795
|
+
description: "Ethereum address of the credit holder surrendering credits"
|
|
2796
|
+
}),
|
|
2797
|
+
identity: CreditRetirementReceiptIdentitySchema.optional()
|
|
2798
|
+
}).meta({
|
|
2799
|
+
title: "Credit Holder",
|
|
2800
|
+
description: "Credit holder wallet and optional identity information"
|
|
2801
|
+
});
|
|
2802
|
+
var CreditRetirementReceiptCollectionSchema = createReceiptCollectionSchema({
|
|
2803
|
+
amountKey: "amount",
|
|
2804
|
+
amountMeta: {
|
|
2805
|
+
title: "Collection Retirement Amount",
|
|
2806
|
+
description: "Total credits retired from this collection"
|
|
2807
|
+
},
|
|
2808
|
+
meta: {
|
|
2809
|
+
title: "Collection",
|
|
2810
|
+
description: "Collection included in the retirement"
|
|
2485
2811
|
}
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
ctx.addIssue({
|
|
2497
|
-
code: "custom",
|
|
2498
|
-
message: 'Attribute "Certificates Purchased" must match data.summary.total_certificates',
|
|
2499
|
-
path: ["attributes"]
|
|
2500
|
-
});
|
|
2812
|
+
});
|
|
2813
|
+
var CreditRetirementReceiptCreditSchema = createReceiptCreditSchema({
|
|
2814
|
+
amountKey: "amount",
|
|
2815
|
+
amountMeta: {
|
|
2816
|
+
title: "Credit Retirement Amount",
|
|
2817
|
+
description: "Total credits retired for this credit type"
|
|
2818
|
+
},
|
|
2819
|
+
meta: {
|
|
2820
|
+
title: "Credit",
|
|
2821
|
+
description: "Credit token retired in this receipt"
|
|
2501
2822
|
}
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2823
|
+
});
|
|
2824
|
+
var CreditRetirementReceiptCertificateCreditSchema = zod.z.strictObject({
|
|
2825
|
+
credit_symbol: CreditTokenSymbolSchema.meta({
|
|
2826
|
+
title: "Credit Token Symbol",
|
|
2827
|
+
description: "Symbol of the credit token retired from the certificate"
|
|
2828
|
+
}),
|
|
2829
|
+
credit_slug: SlugSchema.meta({
|
|
2830
|
+
title: "Credit Slug",
|
|
2831
|
+
description: "Slug of the credit type retired from the certificate",
|
|
2832
|
+
examples: ["carbon", "organic"]
|
|
2833
|
+
}),
|
|
2834
|
+
amount: CreditAmountSchema.meta({
|
|
2835
|
+
title: "Retired Credit Amount",
|
|
2836
|
+
description: "Credits retired of this type from the certificate"
|
|
2837
|
+
}),
|
|
2838
|
+
external_id: ExternalIdSchema.meta({
|
|
2839
|
+
title: "Retired Credit External ID",
|
|
2840
|
+
description: "External identifier for the retired credit entry"
|
|
2841
|
+
}),
|
|
2842
|
+
external_url: ExternalUrlSchema.meta({
|
|
2843
|
+
title: "Retired Credit External URL",
|
|
2844
|
+
description: "External URL for the retired credit entry"
|
|
2845
|
+
})
|
|
2846
|
+
}).meta({
|
|
2847
|
+
title: "Certificate Credit Retirement",
|
|
2848
|
+
description: "Credit retirement breakdown for a certificate"
|
|
2849
|
+
});
|
|
2850
|
+
var CreditPurchaseReceiptReferenceSchema = zod.z.strictObject({
|
|
2851
|
+
token_id: TokenIdSchema.meta({
|
|
2852
|
+
title: "Purchase Receipt Token ID",
|
|
2853
|
+
description: "Token ID of the credit purchase receipt"
|
|
2854
|
+
}),
|
|
2855
|
+
external_id: ExternalIdSchema.meta({
|
|
2856
|
+
title: "Purchase Receipt External ID",
|
|
2857
|
+
description: "External identifier for the purchase receipt"
|
|
2858
|
+
}),
|
|
2859
|
+
external_url: ExternalUrlSchema.meta({
|
|
2860
|
+
title: "Purchase Receipt External URL",
|
|
2861
|
+
description: "External URL for the purchase receipt"
|
|
2862
|
+
}),
|
|
2863
|
+
uri: IpfsUriSchema.meta({
|
|
2864
|
+
title: "Purchase Receipt URI",
|
|
2865
|
+
description: "IPFS URI for the purchase receipt metadata"
|
|
2866
|
+
}),
|
|
2867
|
+
smart_contract: SmartContractSchema
|
|
2868
|
+
}).meta({
|
|
2869
|
+
title: "Credit Purchase Receipt Reference",
|
|
2870
|
+
description: "Reference to the credit purchase receipt when retirement occurs during purchase"
|
|
2871
|
+
});
|
|
2872
|
+
var CreditRetirementReceiptCertificateSchema = createReceiptCertificateSchema(
|
|
2873
|
+
{
|
|
2874
|
+
additionalShape: {
|
|
2875
|
+
retired_amount: CreditAmountSchema.meta({
|
|
2876
|
+
title: "Certificate Retired Amount",
|
|
2877
|
+
description: "Credits retired from this certificate"
|
|
2878
|
+
}),
|
|
2879
|
+
credits_retired: uniqueBy(
|
|
2880
|
+
CreditRetirementReceiptCertificateCreditSchema,
|
|
2881
|
+
(credit) => credit.credit_symbol,
|
|
2882
|
+
"Credit symbols within credits_retired must be unique"
|
|
2883
|
+
).min(1).meta({
|
|
2884
|
+
title: "Credits Retired",
|
|
2885
|
+
description: "Breakdown of credits retired from this certificate by symbol"
|
|
2886
|
+
})
|
|
2887
|
+
},
|
|
2888
|
+
meta: {
|
|
2889
|
+
title: "Certificate",
|
|
2890
|
+
description: "Certificate associated with the retirement"
|
|
2891
|
+
}
|
|
2515
2892
|
}
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2893
|
+
);
|
|
2894
|
+
var CreditRetirementReceiptDataSchema = zod.z.strictObject({
|
|
2895
|
+
summary: CreditRetirementReceiptSummarySchema,
|
|
2896
|
+
beneficiary: CreditRetirementReceiptBeneficiarySchema,
|
|
2897
|
+
credit_holder: CreditRetirementReceiptCreditHolderSchema,
|
|
2898
|
+
collections: uniqueBy(
|
|
2899
|
+
CreditRetirementReceiptCollectionSchema,
|
|
2900
|
+
(collection) => collection.slug,
|
|
2901
|
+
"Collection slugs must be unique"
|
|
2902
|
+
).min(1).meta({
|
|
2903
|
+
title: "Collections",
|
|
2904
|
+
description: "Collections included in the retirement"
|
|
2905
|
+
}),
|
|
2906
|
+
credits: uniqueBy(
|
|
2907
|
+
CreditRetirementReceiptCreditSchema,
|
|
2908
|
+
(credit) => credit.slug,
|
|
2909
|
+
"Credit slugs must be unique"
|
|
2910
|
+
).min(1).meta({
|
|
2911
|
+
title: "Credits",
|
|
2912
|
+
description: "Credits included in the retirement"
|
|
2913
|
+
}),
|
|
2914
|
+
certificates: uniqueBy(
|
|
2915
|
+
CreditRetirementReceiptCertificateSchema,
|
|
2916
|
+
(certificate) => certificate.token_id,
|
|
2917
|
+
"Certificate token_ids must be unique"
|
|
2918
|
+
).min(1).meta({
|
|
2919
|
+
title: "Certificates",
|
|
2920
|
+
description: "Certificates retired in this receipt"
|
|
2921
|
+
}),
|
|
2922
|
+
purchase_receipt: CreditPurchaseReceiptReferenceSchema.optional()
|
|
2923
|
+
}).superRefine((data, ctx) => {
|
|
2924
|
+
const creditSymbols = new Set(
|
|
2925
|
+
data.credits.map((credit) => String(credit.symbol))
|
|
2926
|
+
);
|
|
2927
|
+
const creditBySlug = new Map(
|
|
2928
|
+
data.credits.map((credit) => [credit.slug, credit])
|
|
2929
|
+
);
|
|
2930
|
+
const collectionSlugs = new Set(
|
|
2931
|
+
data.collections.map((collection) => String(collection.slug))
|
|
2932
|
+
);
|
|
2933
|
+
const certificateTypes = new Set(
|
|
2934
|
+
data.certificates.map((certificate) => String(certificate.type))
|
|
2935
|
+
);
|
|
2936
|
+
validateCountMatches({
|
|
2937
|
+
ctx,
|
|
2938
|
+
actualCount: data.certificates.length,
|
|
2939
|
+
expectedCount: data.summary.total_certificates,
|
|
2940
|
+
path: ["summary", "total_certificates"],
|
|
2941
|
+
message: "summary.total_certificates must equal the number of certificates"
|
|
2942
|
+
});
|
|
2943
|
+
validateSummaryListMatchesData({
|
|
2944
|
+
ctx,
|
|
2945
|
+
summaryValues: data.summary.credit_symbols,
|
|
2946
|
+
dataValues: creditSymbols,
|
|
2947
|
+
summaryPath: ["summary", "credit_symbols"],
|
|
2948
|
+
missingFromDataMessage: "summary.credit_symbols must reference symbols from credits",
|
|
2949
|
+
missingFromSummaryMessage: "All credit symbols must be listed in summary.credit_symbols"
|
|
2950
|
+
});
|
|
2951
|
+
validateSummaryListMatchesData({
|
|
2952
|
+
ctx,
|
|
2953
|
+
summaryValues: data.summary.collection_slugs,
|
|
2954
|
+
dataValues: collectionSlugs,
|
|
2955
|
+
summaryPath: ["summary", "collection_slugs"],
|
|
2956
|
+
missingFromDataMessage: "summary.collection_slugs must reference slugs from collections",
|
|
2957
|
+
missingFromSummaryMessage: "All collection slugs must be listed in summary.collection_slugs"
|
|
2958
|
+
});
|
|
2959
|
+
validateSummaryListMatchesData({
|
|
2960
|
+
ctx,
|
|
2961
|
+
summaryValues: data.summary.certificate_types,
|
|
2962
|
+
dataValues: certificateTypes,
|
|
2963
|
+
summaryPath: ["summary", "certificate_types"],
|
|
2964
|
+
missingFromDataMessage: "summary.certificate_types must reference types present in certificates",
|
|
2965
|
+
missingFromSummaryMessage: "All certificate types must be listed in summary.certificate_types"
|
|
2966
|
+
});
|
|
2967
|
+
const creditTotalsBySymbol = /* @__PURE__ */ new Map();
|
|
2968
|
+
const collectionTotalsBySlug = /* @__PURE__ */ new Map();
|
|
2969
|
+
let totalRetiredFromCertificates = 0;
|
|
2970
|
+
data.certificates.forEach((certificate, index) => {
|
|
2971
|
+
if (!collectionSlugs.has(certificate.collection_slug)) {
|
|
2529
2972
|
ctx.addIssue({
|
|
2530
2973
|
code: "custom",
|
|
2531
|
-
message: "
|
|
2532
|
-
path: ["
|
|
2974
|
+
message: "collection_slug must match a collection slug in collections",
|
|
2975
|
+
path: ["certificates", index, "collection_slug"]
|
|
2533
2976
|
});
|
|
2534
|
-
}
|
|
2977
|
+
}
|
|
2978
|
+
if (certificate.retired_amount > certificate.total_amount) {
|
|
2535
2979
|
ctx.addIssue({
|
|
2536
2980
|
code: "custom",
|
|
2537
|
-
message:
|
|
2538
|
-
path: ["
|
|
2981
|
+
message: "retired_amount cannot exceed total_amount",
|
|
2982
|
+
path: ["certificates", index, "retired_amount"]
|
|
2539
2983
|
});
|
|
2540
2984
|
}
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2985
|
+
const creditsRetiredTotal = certificate.credits_retired.reduce(
|
|
2986
|
+
(sum, credit) => sum + Number(credit.amount),
|
|
2987
|
+
0
|
|
2988
|
+
);
|
|
2989
|
+
if (!nearlyEqual(creditsRetiredTotal, certificate.retired_amount)) {
|
|
2545
2990
|
ctx.addIssue({
|
|
2546
2991
|
code: "custom",
|
|
2547
|
-
message:
|
|
2548
|
-
path: ["
|
|
2992
|
+
message: "certificates.credits_retired amounts must sum to certificates.retired_amount",
|
|
2993
|
+
path: ["certificates", index, "credits_retired"]
|
|
2994
|
+
});
|
|
2995
|
+
}
|
|
2996
|
+
certificate.credits_retired.forEach((credit, creditIndex) => {
|
|
2997
|
+
const referencedCredit = creditBySlug.get(credit.credit_slug);
|
|
2998
|
+
if (!referencedCredit) {
|
|
2999
|
+
ctx.addIssue({
|
|
3000
|
+
code: "custom",
|
|
3001
|
+
message: "credit_slug must match a credit slug in credits",
|
|
3002
|
+
path: [
|
|
3003
|
+
"certificates",
|
|
3004
|
+
index,
|
|
3005
|
+
"credits_retired",
|
|
3006
|
+
creditIndex,
|
|
3007
|
+
"credit_slug"
|
|
3008
|
+
]
|
|
3009
|
+
});
|
|
3010
|
+
}
|
|
3011
|
+
if (!creditSymbols.has(credit.credit_symbol)) {
|
|
3012
|
+
ctx.addIssue({
|
|
3013
|
+
code: "custom",
|
|
3014
|
+
message: "credit_symbol must match a credit symbol in credits",
|
|
3015
|
+
path: [
|
|
3016
|
+
"certificates",
|
|
3017
|
+
index,
|
|
3018
|
+
"credits_retired",
|
|
3019
|
+
creditIndex,
|
|
3020
|
+
"credit_symbol"
|
|
3021
|
+
]
|
|
3022
|
+
});
|
|
3023
|
+
}
|
|
3024
|
+
if (referencedCredit && referencedCredit.symbol !== credit.credit_symbol) {
|
|
3025
|
+
ctx.addIssue({
|
|
3026
|
+
code: "custom",
|
|
3027
|
+
message: "credit_symbol must match the symbol for the referenced credit_slug",
|
|
3028
|
+
path: [
|
|
3029
|
+
"certificates",
|
|
3030
|
+
index,
|
|
3031
|
+
"credits_retired",
|
|
3032
|
+
creditIndex,
|
|
3033
|
+
"credit_symbol"
|
|
3034
|
+
]
|
|
3035
|
+
});
|
|
3036
|
+
}
|
|
3037
|
+
creditTotalsBySymbol.set(
|
|
3038
|
+
credit.credit_symbol,
|
|
3039
|
+
(creditTotalsBySymbol.get(credit.credit_symbol) ?? 0) + credit.amount
|
|
3040
|
+
);
|
|
3041
|
+
});
|
|
3042
|
+
collectionTotalsBySlug.set(
|
|
3043
|
+
String(certificate.collection_slug),
|
|
3044
|
+
(collectionTotalsBySlug.get(certificate.collection_slug) ?? 0) + Number(certificate.retired_amount)
|
|
3045
|
+
);
|
|
3046
|
+
totalRetiredFromCertificates += Number(certificate.retired_amount);
|
|
3047
|
+
});
|
|
3048
|
+
const totalRetiredFromCollections = data.collections.reduce(
|
|
3049
|
+
(sum, collection) => sum + Number(collection.amount),
|
|
3050
|
+
0
|
|
3051
|
+
);
|
|
3052
|
+
const totalRetiredFromCredits = data.credits.reduce(
|
|
3053
|
+
(sum, credit) => sum + Number(credit.amount),
|
|
3054
|
+
0
|
|
3055
|
+
);
|
|
3056
|
+
data.summary.credit_symbols.forEach((symbol) => {
|
|
3057
|
+
if ((creditTotalsBySymbol.get(symbol) ?? 0) === 0) {
|
|
3058
|
+
ctx.addIssue({
|
|
3059
|
+
code: "custom",
|
|
3060
|
+
message: "Each summary credit symbol must appear in certificates.credits_retired with a retired amount",
|
|
3061
|
+
path: ["summary", "credit_symbols"]
|
|
2549
3062
|
});
|
|
2550
|
-
return;
|
|
2551
3063
|
}
|
|
2552
|
-
|
|
3064
|
+
});
|
|
3065
|
+
validateTotalMatches({
|
|
3066
|
+
ctx,
|
|
3067
|
+
actualTotal: totalRetiredFromCertificates,
|
|
3068
|
+
expectedTotal: data.summary.total_retirement_amount,
|
|
3069
|
+
path: ["summary", "total_retirement_amount"],
|
|
3070
|
+
message: "summary.total_retirement_amount must equal sum of certificates.retired_amount"
|
|
3071
|
+
});
|
|
3072
|
+
validateTotalMatches({
|
|
3073
|
+
ctx,
|
|
3074
|
+
actualTotal: totalRetiredFromCredits,
|
|
3075
|
+
expectedTotal: data.summary.total_retirement_amount,
|
|
3076
|
+
path: ["summary", "total_retirement_amount"],
|
|
3077
|
+
message: "summary.total_retirement_amount must equal sum of credits.amount"
|
|
3078
|
+
});
|
|
3079
|
+
validateTotalMatches({
|
|
3080
|
+
ctx,
|
|
3081
|
+
actualTotal: totalRetiredFromCollections,
|
|
3082
|
+
expectedTotal: data.summary.total_retirement_amount,
|
|
3083
|
+
path: ["summary", "total_retirement_amount"],
|
|
3084
|
+
message: "summary.total_retirement_amount must equal sum of collections.amount"
|
|
3085
|
+
});
|
|
3086
|
+
data.credits.forEach((credit, index) => {
|
|
3087
|
+
const retiredTotal = creditTotalsBySymbol.get(String(credit.symbol)) ?? 0;
|
|
3088
|
+
if (!nearlyEqual(Number(credit.amount), retiredTotal)) {
|
|
2553
3089
|
ctx.addIssue({
|
|
2554
3090
|
code: "custom",
|
|
2555
|
-
message:
|
|
2556
|
-
path: ["
|
|
3091
|
+
message: "credit.amount must equal sum of retired amounts for the credit symbol across certificates",
|
|
3092
|
+
path: ["credits", index, "amount"]
|
|
2557
3093
|
});
|
|
2558
3094
|
}
|
|
2559
3095
|
});
|
|
2560
|
-
data.collections.forEach((collection) => {
|
|
2561
|
-
const
|
|
2562
|
-
if (
|
|
3096
|
+
data.collections.forEach((collection, index) => {
|
|
3097
|
+
const retiredTotal = collectionTotalsBySlug.get(String(collection.slug)) ?? 0;
|
|
3098
|
+
if (retiredTotal === 0) {
|
|
2563
3099
|
ctx.addIssue({
|
|
2564
3100
|
code: "custom",
|
|
2565
|
-
message:
|
|
2566
|
-
path: ["
|
|
3101
|
+
message: "collection must be referenced by at least one certificate with retired_amount > 0",
|
|
3102
|
+
path: ["collections", index, "slug"]
|
|
2567
3103
|
});
|
|
2568
|
-
return;
|
|
2569
3104
|
}
|
|
2570
|
-
if (
|
|
3105
|
+
if (Number(collection.amount) <= 0) {
|
|
2571
3106
|
ctx.addIssue({
|
|
2572
3107
|
code: "custom",
|
|
2573
|
-
message:
|
|
2574
|
-
path: ["
|
|
3108
|
+
message: "collection.amount must be greater than zero",
|
|
3109
|
+
path: ["collections", index, "amount"]
|
|
3110
|
+
});
|
|
3111
|
+
}
|
|
3112
|
+
if (!nearlyEqual(Number(collection.amount), retiredTotal)) {
|
|
3113
|
+
ctx.addIssue({
|
|
3114
|
+
code: "custom",
|
|
3115
|
+
message: "collection.amount must equal sum of certificate retired_amount for the collection slug",
|
|
3116
|
+
path: ["collections", index, "amount"]
|
|
2575
3117
|
});
|
|
2576
3118
|
}
|
|
2577
3119
|
});
|
|
2578
|
-
}).meta(
|
|
3120
|
+
}).meta({
|
|
3121
|
+
title: "Credit Retirement Receipt Data",
|
|
3122
|
+
description: "Complete data structure for a credit retirement receipt"
|
|
3123
|
+
});
|
|
3124
|
+
var CreditRetirementReceiptIpfsSchemaBase = NftIpfsSchema.omit({
|
|
3125
|
+
original_content_hash: true
|
|
3126
|
+
});
|
|
3127
|
+
var CreditRetirementReceiptIpfsSchemaMeta = {
|
|
3128
|
+
title: "CreditRetirementReceipt NFT IPFS Record",
|
|
3129
|
+
description: "Complete CreditRetirementReceipt NFT IPFS record including attributes and credit retirement data",
|
|
3130
|
+
$id: buildSchemaUrl(
|
|
3131
|
+
"credit-retirement-receipt/credit-retirement-receipt.schema.json"
|
|
3132
|
+
),
|
|
3133
|
+
version: getSchemaVersionOrDefault()
|
|
3134
|
+
};
|
|
3135
|
+
var CreditRetirementReceiptIpfsSchema = CreditRetirementReceiptIpfsSchemaBase.safeExtend({
|
|
3136
|
+
schema: CreditRetirementReceiptIpfsSchemaBase.shape.schema.safeExtend({
|
|
3137
|
+
type: zod.z.literal("CreditRetirementReceipt").meta({
|
|
3138
|
+
title: "CreditRetirementReceipt Schema Type",
|
|
3139
|
+
description: "CreditRetirementReceipt NFT schema type"
|
|
3140
|
+
})
|
|
3141
|
+
}),
|
|
3142
|
+
attributes: CreditRetirementReceiptAttributesSchema,
|
|
3143
|
+
data: CreditRetirementReceiptDataSchema
|
|
3144
|
+
}).superRefine((value, ctx) => {
|
|
3145
|
+
const attributes = value.attributes;
|
|
3146
|
+
const data = value.data;
|
|
3147
|
+
const attributeByTraitType = createAttributeMap(attributes);
|
|
3148
|
+
validateAttributeValue({
|
|
3149
|
+
ctx,
|
|
3150
|
+
attributeByTraitType,
|
|
3151
|
+
traitType: "Total Credits Retired",
|
|
3152
|
+
expectedValue: data.summary.total_retirement_amount,
|
|
3153
|
+
missingMessage: 'Attribute "Total Credits Retired" is required',
|
|
3154
|
+
mismatchMessage: 'Attribute "Total Credits Retired" must match data.summary.total_retirement_amount'
|
|
3155
|
+
});
|
|
3156
|
+
validateAttributeValue({
|
|
3157
|
+
ctx,
|
|
3158
|
+
attributeByTraitType,
|
|
3159
|
+
traitType: "Certificates Retired",
|
|
3160
|
+
expectedValue: data.summary.total_certificates,
|
|
3161
|
+
missingMessage: 'Attribute "Certificates Retired" is required',
|
|
3162
|
+
mismatchMessage: 'Attribute "Certificates Retired" must match data.summary.total_certificates'
|
|
3163
|
+
});
|
|
3164
|
+
validateAttributeValue({
|
|
3165
|
+
ctx,
|
|
3166
|
+
attributeByTraitType,
|
|
3167
|
+
traitType: "Beneficiary",
|
|
3168
|
+
expectedValue: String(data.beneficiary.identity.name),
|
|
3169
|
+
missingMessage: 'Attribute "Beneficiary" is required',
|
|
3170
|
+
mismatchMessage: 'Attribute "Beneficiary" must match beneficiary.identity.name'
|
|
3171
|
+
});
|
|
3172
|
+
const creditHolderName = data.credit_holder.identity?.name;
|
|
3173
|
+
if (creditHolderName) {
|
|
3174
|
+
validateAttributeValue({
|
|
3175
|
+
ctx,
|
|
3176
|
+
attributeByTraitType,
|
|
3177
|
+
traitType: "Credit Holder",
|
|
3178
|
+
expectedValue: String(creditHolderName),
|
|
3179
|
+
missingMessage: 'Attribute "Credit Holder" is required when credit_holder.identity.name is provided',
|
|
3180
|
+
mismatchMessage: 'Attribute "Credit Holder" must match credit_holder.identity.name'
|
|
3181
|
+
});
|
|
3182
|
+
}
|
|
3183
|
+
validateDateAttribute({
|
|
3184
|
+
ctx,
|
|
3185
|
+
attributeByTraitType,
|
|
3186
|
+
traitType: "Retirement Date",
|
|
3187
|
+
dateValue: data.summary.retirement_date,
|
|
3188
|
+
missingMessage: 'Attribute "Retirement Date" is required',
|
|
3189
|
+
invalidDateMessage: "data.summary.retirement_date must be a valid date string",
|
|
3190
|
+
mismatchMessage: 'Attribute "Retirement Date" must match data.summary.retirement_date as a Unix timestamp in milliseconds',
|
|
3191
|
+
datePath: ["data", "summary", "retirement_date"]
|
|
3192
|
+
});
|
|
3193
|
+
validateAttributesForItems({
|
|
3194
|
+
ctx,
|
|
3195
|
+
attributeByTraitType,
|
|
3196
|
+
items: data.credits,
|
|
3197
|
+
traitSelector: (credit) => String(credit.symbol),
|
|
3198
|
+
valueSelector: (credit) => Number(credit.amount),
|
|
3199
|
+
missingMessage: (symbol) => `Attribute for credit symbol ${symbol} is required`,
|
|
3200
|
+
mismatchMessage: (symbol) => `Attribute for credit symbol ${symbol} must match credit.amount`
|
|
3201
|
+
});
|
|
3202
|
+
validateAttributesForItems({
|
|
3203
|
+
ctx,
|
|
3204
|
+
attributeByTraitType,
|
|
3205
|
+
items: data.collections,
|
|
3206
|
+
traitSelector: (collection) => String(collection.name),
|
|
3207
|
+
valueSelector: (collection) => Number(collection.amount),
|
|
3208
|
+
missingMessage: (name) => `Attribute for collection ${name} is required`,
|
|
3209
|
+
mismatchMessage: (name) => `Attribute for collection ${name} must match collection.amount`
|
|
3210
|
+
});
|
|
3211
|
+
}).meta(CreditRetirementReceiptIpfsSchemaMeta);
|
|
2579
3212
|
var CollectionSchemaMeta = {
|
|
2580
3213
|
title: "Collection IPFS Record",
|
|
2581
3214
|
description: "Collection metadata stored in IPFS, extending the base schema with collection-specific fields required for NFT collection definitions in Carrot's ecosystem",
|
|
@@ -2782,11 +3415,19 @@ exports.CreditPurchaseReceiptAttributesSchema = CreditPurchaseReceiptAttributesS
|
|
|
2782
3415
|
exports.CreditPurchaseReceiptDataSchema = CreditPurchaseReceiptDataSchema;
|
|
2783
3416
|
exports.CreditPurchaseReceiptIpfsSchema = CreditPurchaseReceiptIpfsSchema;
|
|
2784
3417
|
exports.CreditPurchaseReceiptIpfsSchemaMeta = CreditPurchaseReceiptIpfsSchemaMeta;
|
|
3418
|
+
exports.CreditPurchaseReceiptSummarySchema = CreditPurchaseReceiptSummarySchema;
|
|
3419
|
+
exports.CreditRetirementReceiptAttributesSchema = CreditRetirementReceiptAttributesSchema;
|
|
3420
|
+
exports.CreditRetirementReceiptDataSchema = CreditRetirementReceiptDataSchema;
|
|
3421
|
+
exports.CreditRetirementReceiptIpfsSchema = CreditRetirementReceiptIpfsSchema;
|
|
3422
|
+
exports.CreditRetirementReceiptIpfsSchemaMeta = CreditRetirementReceiptIpfsSchemaMeta;
|
|
3423
|
+
exports.CreditRetirementReceiptSummarySchema = CreditRetirementReceiptSummarySchema;
|
|
2785
3424
|
exports.CreditSchema = CreditSchema;
|
|
2786
3425
|
exports.CreditSchemaMeta = CreditSchemaMeta;
|
|
3426
|
+
exports.CreditTokenSymbolSchema = CreditTokenSymbolSchema;
|
|
2787
3427
|
exports.CreditTypeAttributeSchema = CreditTypeAttributeSchema;
|
|
2788
3428
|
exports.CreditTypeSchema = CreditTypeSchema;
|
|
2789
3429
|
exports.DistributionNotesSchema = DistributionNotesSchema;
|
|
3430
|
+
exports.EPSILON = EPSILON;
|
|
2790
3431
|
exports.EthereumAddressSchema = EthereumAddressSchema;
|
|
2791
3432
|
exports.ExternalIdSchema = ExternalIdSchema;
|
|
2792
3433
|
exports.ExternalUrlSchema = ExternalUrlSchema;
|
|
@@ -2817,6 +3458,7 @@ exports.MassIDIpfsSchemaMeta = MassIDIpfsSchemaMeta;
|
|
|
2817
3458
|
exports.MassIDRecyclingDateAttributeSchema = MassIDRecyclingDateAttributeSchema;
|
|
2818
3459
|
exports.MassIDReferenceSchema = MassIDReferenceSchema;
|
|
2819
3460
|
exports.MassIDTokenIdAttributeSchema = MassIDTokenIdAttributeSchema;
|
|
3461
|
+
exports.MassIdReferenceWithContractSchema = MassIdReferenceWithContractSchema;
|
|
2820
3462
|
exports.MethodologyAttributeSchema = MethodologyAttributeSchema;
|
|
2821
3463
|
exports.MethodologyComplianceSchema = MethodologyComplianceSchema;
|
|
2822
3464
|
exports.MethodologyDataSchema = MethodologyDataSchema;
|
|
@@ -2839,6 +3481,7 @@ exports.ParticipantRoleSchema = ParticipantRoleSchema;
|
|
|
2839
3481
|
exports.ParticipantSchema = ParticipantSchema;
|
|
2840
3482
|
exports.PercentageSchema = PercentageSchema;
|
|
2841
3483
|
exports.PositiveIntegerSchema = PositiveIntegerSchema;
|
|
3484
|
+
exports.ReceiptIdentitySchema = ReceiptIdentitySchema;
|
|
2842
3485
|
exports.RecordEnvironmentSchema = RecordEnvironmentSchema;
|
|
2843
3486
|
exports.RecordRelationshipTypeSchema = RecordRelationshipTypeSchema;
|
|
2844
3487
|
exports.RecordSchemaTypeSchema = RecordSchemaTypeSchema;
|
|
@@ -2865,9 +3508,20 @@ exports.WasteSubtypeSchema = WasteSubtypeSchema;
|
|
|
2865
3508
|
exports.WasteTypeSchema = WasteTypeSchema;
|
|
2866
3509
|
exports.WeightKgSchema = WeightKgSchema;
|
|
2867
3510
|
exports.buildSchemaUrl = buildSchemaUrl;
|
|
3511
|
+
exports.createAttributeMap = createAttributeMap;
|
|
3512
|
+
exports.createReceiptCertificateSchema = createReceiptCertificateSchema;
|
|
3513
|
+
exports.createReceiptCollectionSchema = createReceiptCollectionSchema;
|
|
3514
|
+
exports.createReceiptCreditSchema = createReceiptCreditSchema;
|
|
2868
3515
|
exports.getSchemaBaseUrl = getSchemaBaseUrl;
|
|
2869
3516
|
exports.getSchemaVersionOrDefault = getSchemaVersionOrDefault;
|
|
3517
|
+
exports.nearlyEqual = nearlyEqual;
|
|
2870
3518
|
exports.uniqueArrayItems = uniqueArrayItems;
|
|
2871
3519
|
exports.uniqueBy = uniqueBy;
|
|
3520
|
+
exports.validateAttributeValue = validateAttributeValue;
|
|
3521
|
+
exports.validateAttributesForItems = validateAttributesForItems;
|
|
3522
|
+
exports.validateCountMatches = validateCountMatches;
|
|
3523
|
+
exports.validateDateAttribute = validateDateAttribute;
|
|
3524
|
+
exports.validateSummaryListMatchesData = validateSummaryListMatchesData;
|
|
3525
|
+
exports.validateTotalMatches = validateTotalMatches;
|
|
2872
3526
|
//# sourceMappingURL=index.cjs.map
|
|
2873
3527
|
//# sourceMappingURL=index.cjs.map
|