@carrot-foundation/schemas 0.1.36 → 0.1.38
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 +1778 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1510 -14
- package/dist/index.d.ts +1510 -14
- package/dist/index.js +1735 -37
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/schemas/ipfs/collection/collection.example.json +1 -0
- package/schemas/ipfs/collection/collection.schema.json +306 -32
- package/schemas/ipfs/credit/credit.example.json +1 -0
- package/schemas/ipfs/credit/credit.schema.json +327 -45
- package/schemas/ipfs/credit-purchase-receipt/credit-purchase-receipt.example.json +290 -0
- package/schemas/ipfs/credit-purchase-receipt/credit-purchase-receipt.schema.json +1772 -0
- 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 +7 -6
- package/schemas/ipfs/mass-id/mass-id.schema.json +7 -6
- package/schemas/ipfs/mass-id-audit/mass-id-audit.example.json +30 -29
- package/schemas/ipfs/mass-id-audit/mass-id-audit.schema.json +637 -15
- package/schemas/ipfs/methodology/methodology.example.json +27 -26
- package/schemas/ipfs/methodology/methodology.schema.json +458 -15
- package/schemas/ipfs/recycled-id/recycled-id.schema.json +7 -6
- package/schemas/ipfs/gas-id/gas-id.attributes.schema.json +0 -219
- package/schemas/ipfs/gas-id/gas-id.data.schema.json +0 -120
- package/schemas/ipfs/mass-id-audit/mass-id-audit.data.schema.json +0 -130
- package/schemas/ipfs/methodology/methodology.data.schema.json +0 -121
- package/schemas/ipfs/purchase-id/purchase-id.attributes.schema.json +0 -91
- package/schemas/ipfs/purchase-id/purchase-id.data.schema.json +0 -337
- package/schemas/ipfs/purchase-id/purchase-id.example.json +0 -224
- package/schemas/ipfs/purchase-id/purchase-id.schema.json +0 -29
- package/schemas/ipfs/recycled-id/recycled-id.attributes.schema.json +0 -202
- package/schemas/ipfs/recycled-id/recycled-id.data.schema.json +0 -63
- package/schemas/ipfs/shared/base/base.schema.json +0 -163
- package/schemas/ipfs/shared/certificate/certificate.schema.json +0 -145
- package/schemas/ipfs/shared/definitions/definitions.schema.json +0 -255
- package/schemas/ipfs/shared/entities/location/location.schema.json +0 -90
- package/schemas/ipfs/shared/entities/participant/participant.schema.json +0 -28
- package/schemas/ipfs/shared/nft/nft.schema.json +0 -182
- package/schemas/ipfs/shared/references/audit-reference/audit-reference.schema.json +0 -42
- package/schemas/ipfs/shared/references/gas-id-reference/gas-id-reference.schema.json +0 -27
- package/schemas/ipfs/shared/references/mass-id-reference/mass-id-reference.schema.json +0 -27
- package/schemas/ipfs/shared/references/methodology-reference/methodology-reference.schema.json +0 -34
package/dist/index.cjs
CHANGED
|
@@ -15,7 +15,7 @@ var UuidSchema = zod.z.uuidv4("Must be a valid UUID v4 string").meta({
|
|
|
15
15
|
]
|
|
16
16
|
});
|
|
17
17
|
var EthereumAddressSchema = zod.z.string().regex(
|
|
18
|
-
/^0x[a-
|
|
18
|
+
/^0x[a-f0-9]{40}$/,
|
|
19
19
|
"Must be a valid Ethereum address in lowercase hexadecimal format"
|
|
20
20
|
).meta({
|
|
21
21
|
title: "Ethereum Address",
|
|
@@ -90,6 +90,11 @@ var CountryNameSchema = NonEmptyStringSchema.max(50).meta({
|
|
|
90
90
|
description: "Full country name in English",
|
|
91
91
|
examples: ["Brazil", "United States", "Germany", "Japan"]
|
|
92
92
|
});
|
|
93
|
+
var CollectionNameSchema = NonEmptyStringSchema.max(150).meta({
|
|
94
|
+
title: "Collection Name",
|
|
95
|
+
description: "Display name of the collection",
|
|
96
|
+
examples: ["BOLD Cold Start - Carazinho", "BOLD Brazil"]
|
|
97
|
+
});
|
|
93
98
|
var MethodologyNameSchema = NonEmptyStringSchema.max(100).meta({
|
|
94
99
|
title: "Methodology Name",
|
|
95
100
|
description: "Name of the methodology used for certification",
|
|
@@ -111,6 +116,11 @@ var SlugSchema = NonEmptyStringSchema.regex(
|
|
|
111
116
|
description: "URL-friendly identifier with lowercase letters, numbers, and hyphens",
|
|
112
117
|
examples: ["mass-id-123", "recycled-plastic", "organic-waste"]
|
|
113
118
|
});
|
|
119
|
+
var CollectionSlugSchema = SlugSchema.meta({
|
|
120
|
+
title: "Collection Slug",
|
|
121
|
+
description: "URL-friendly identifier for a collection",
|
|
122
|
+
examples: ["bold-cold-start-carazinho", "bold-brazil"]
|
|
123
|
+
});
|
|
114
124
|
var WasteTypeSchema = NonEmptyStringSchema.max(100).meta({
|
|
115
125
|
title: "Waste Type",
|
|
116
126
|
description: "Category or type of waste material",
|
|
@@ -150,6 +160,23 @@ var BlockchainChainIdSchema = zod.z.number().int().min(1).meta({
|
|
|
150
160
|
description: "Blockchain network identifier",
|
|
151
161
|
examples: [1, 137, 11155111]
|
|
152
162
|
});
|
|
163
|
+
var BlockchainNetworkNameSchema = NonEmptyStringSchema.max(100).meta({
|
|
164
|
+
title: "Blockchain Network Name",
|
|
165
|
+
description: "Name of the blockchain network",
|
|
166
|
+
examples: ["Polygon", "Ethereum mainnet", "Sepolia"]
|
|
167
|
+
});
|
|
168
|
+
var SmartContractAddressSchema = EthereumAddressSchema.meta({
|
|
169
|
+
title: "Smart Contract Address",
|
|
170
|
+
description: "Address of the smart contract"
|
|
171
|
+
});
|
|
172
|
+
var SmartContractSchema = zod.z.strictObject({
|
|
173
|
+
address: SmartContractAddressSchema,
|
|
174
|
+
chain_id: BlockchainChainIdSchema,
|
|
175
|
+
network_name: BlockchainNetworkNameSchema
|
|
176
|
+
}).meta({
|
|
177
|
+
title: "Smart Contract",
|
|
178
|
+
description: "Smart contract details for on-chain references"
|
|
179
|
+
});
|
|
153
180
|
var PercentageSchema = zod.z.number().min(0).max(100).meta({
|
|
154
181
|
title: "Percentage",
|
|
155
182
|
description: "Percentage value between 0 and 100",
|
|
@@ -264,7 +291,8 @@ var RecordSchemaTypeSchema = zod.z.enum([
|
|
|
264
291
|
"MassID Audit",
|
|
265
292
|
"RecycledID",
|
|
266
293
|
"GasID",
|
|
267
|
-
"
|
|
294
|
+
"CreditPurchaseReceipt",
|
|
295
|
+
"CreditRetirementReceipt",
|
|
268
296
|
"Methodology",
|
|
269
297
|
"Credit",
|
|
270
298
|
"Collection"
|
|
@@ -281,6 +309,11 @@ var TokenSymbolSchema = NonEmptyStringSchema.max(10).regex(
|
|
|
281
309
|
description: "Symbol representing a token or cryptocurrency",
|
|
282
310
|
examples: ["MASS", "REC", "GAS"]
|
|
283
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
|
+
});
|
|
284
317
|
var RecordRelationshipTypeSchema = zod.z.enum([
|
|
285
318
|
"collection",
|
|
286
319
|
"credit",
|
|
@@ -288,12 +321,13 @@ var RecordRelationshipTypeSchema = zod.z.enum([
|
|
|
288
321
|
"mass-id",
|
|
289
322
|
"mass-id-audit",
|
|
290
323
|
"methodology",
|
|
291
|
-
"purchase-
|
|
324
|
+
"credit-purchase-receipt",
|
|
325
|
+
"credit-retirement-receipt",
|
|
292
326
|
"recycled-id"
|
|
293
327
|
]).meta({
|
|
294
328
|
title: "Relationship Type",
|
|
295
329
|
description: "Type of relationship between different entities in the system",
|
|
296
|
-
examples: ["mass-id", "
|
|
330
|
+
examples: ["mass-id", "collection", "credit-purchase-receipt"]
|
|
297
331
|
});
|
|
298
332
|
function uniqueArrayItems(schema, errorMessage = "Array items must be unique") {
|
|
299
333
|
return zod.z.array(schema).refine((items) => new Set(items).size === items.length, {
|
|
@@ -706,7 +740,8 @@ var NftSchemaTypeSchema = RecordSchemaTypeSchema.extract([
|
|
|
706
740
|
"MassID",
|
|
707
741
|
"RecycledID",
|
|
708
742
|
"GasID",
|
|
709
|
-
"
|
|
743
|
+
"CreditPurchaseReceipt",
|
|
744
|
+
"CreditRetirementReceipt"
|
|
710
745
|
]).meta({
|
|
711
746
|
title: "NFT Schema Type",
|
|
712
747
|
description: "Type of schema for NFT records"
|
|
@@ -883,16 +918,16 @@ function buildSchemaUrl(schemaPath) {
|
|
|
883
918
|
return `${getSchemaBaseUrl()}/${cleanPath}`;
|
|
884
919
|
}
|
|
885
920
|
function getSchemaVersionOrDefault() {
|
|
886
|
-
return "0.1.
|
|
921
|
+
return "0.1.38";
|
|
887
922
|
}
|
|
888
|
-
var MethodologyAttributeSchema = NftAttributeSchema.
|
|
923
|
+
var MethodologyAttributeSchema = NftAttributeSchema.safeExtend({
|
|
889
924
|
trait_type: zod.z.literal("Methodology"),
|
|
890
925
|
value: MethodologyNameSchema
|
|
891
926
|
}).meta({
|
|
892
927
|
title: "Methodology Attribute",
|
|
893
928
|
description: "Methodology used for certification"
|
|
894
929
|
});
|
|
895
|
-
var CreditAmountAttributeSchema = NftAttributeSchema.
|
|
930
|
+
var CreditAmountAttributeSchema = NftAttributeSchema.safeExtend({
|
|
896
931
|
trait_type: zod.z.literal("Credit Amount"),
|
|
897
932
|
value: CreditAmountSchema,
|
|
898
933
|
display_type: zod.z.literal("number")
|
|
@@ -900,21 +935,21 @@ var CreditAmountAttributeSchema = NftAttributeSchema.extend({
|
|
|
900
935
|
title: "Credit Amount Attribute",
|
|
901
936
|
description: "Credit amount attribute with numeric display"
|
|
902
937
|
});
|
|
903
|
-
var CreditTypeAttributeSchema = NftAttributeSchema.
|
|
938
|
+
var CreditTypeAttributeSchema = NftAttributeSchema.safeExtend({
|
|
904
939
|
trait_type: zod.z.literal("Credit Type"),
|
|
905
940
|
value: CreditTypeSchema
|
|
906
941
|
}).meta({
|
|
907
942
|
title: "Credit Type Attribute",
|
|
908
943
|
description: "Credit type attribute"
|
|
909
944
|
});
|
|
910
|
-
var SourceWasteTypeAttributeSchema = NftAttributeSchema.
|
|
945
|
+
var SourceWasteTypeAttributeSchema = NftAttributeSchema.safeExtend({
|
|
911
946
|
trait_type: zod.z.literal("Source Waste Type"),
|
|
912
947
|
value: WasteTypeSchema
|
|
913
948
|
}).meta({
|
|
914
949
|
title: "Source Waste Type Attribute",
|
|
915
950
|
description: "Source waste type attribute"
|
|
916
951
|
});
|
|
917
|
-
var SourceWeightAttributeSchema = NftAttributeSchema.
|
|
952
|
+
var SourceWeightAttributeSchema = NftAttributeSchema.safeExtend({
|
|
918
953
|
trait_type: zod.z.literal("Source Weight (kg)"),
|
|
919
954
|
value: WeightKgSchema.meta({
|
|
920
955
|
title: "Source Weight",
|
|
@@ -925,21 +960,21 @@ var SourceWeightAttributeSchema = NftAttributeSchema.extend({
|
|
|
925
960
|
title: "Source Weight Attribute",
|
|
926
961
|
description: "Source weight attribute with numeric display"
|
|
927
962
|
});
|
|
928
|
-
var OriginCountryAttributeSchema = NftAttributeSchema.
|
|
963
|
+
var OriginCountryAttributeSchema = NftAttributeSchema.safeExtend({
|
|
929
964
|
trait_type: zod.z.literal("Origin Country"),
|
|
930
965
|
value: CountryNameSchema
|
|
931
966
|
}).meta({
|
|
932
967
|
title: "Origin Country Attribute",
|
|
933
968
|
description: "Origin country attribute"
|
|
934
969
|
});
|
|
935
|
-
var OriginMunicipalityAttributeSchema = NftAttributeSchema.
|
|
970
|
+
var OriginMunicipalityAttributeSchema = NftAttributeSchema.safeExtend({
|
|
936
971
|
trait_type: zod.z.literal("Origin Municipality"),
|
|
937
972
|
value: MunicipalitySchema
|
|
938
973
|
}).meta({
|
|
939
974
|
title: "Origin Municipality Attribute",
|
|
940
975
|
description: "Origin municipality attribute"
|
|
941
976
|
});
|
|
942
|
-
var RecyclerAttributeSchema = NftAttributeSchema.
|
|
977
|
+
var RecyclerAttributeSchema = NftAttributeSchema.safeExtend({
|
|
943
978
|
trait_type: zod.z.literal("Recycler"),
|
|
944
979
|
value: NonEmptyStringSchema.max(100).meta({
|
|
945
980
|
title: "Recycler",
|
|
@@ -950,7 +985,7 @@ var RecyclerAttributeSchema = NftAttributeSchema.extend({
|
|
|
950
985
|
title: "Recycler Attribute",
|
|
951
986
|
description: "Recycler attribute"
|
|
952
987
|
});
|
|
953
|
-
var MassIDTokenIdAttributeSchema = NftAttributeSchema.
|
|
988
|
+
var MassIDTokenIdAttributeSchema = NftAttributeSchema.safeExtend({
|
|
954
989
|
trait_type: zod.z.literal("MassID"),
|
|
955
990
|
value: StringifiedTokenIdSchema.meta({
|
|
956
991
|
title: "MassID Token ID",
|
|
@@ -962,7 +997,7 @@ var MassIDTokenIdAttributeSchema = NftAttributeSchema.extend({
|
|
|
962
997
|
});
|
|
963
998
|
var MassIDRecyclingDateAttributeSchema = NftAttributeSchema.omit({
|
|
964
999
|
max_value: true
|
|
965
|
-
}).
|
|
1000
|
+
}).safeExtend({
|
|
966
1001
|
trait_type: zod.z.literal("MassID Recycling Date"),
|
|
967
1002
|
value: UnixTimestampSchema.meta({
|
|
968
1003
|
title: "MassID Recycling Date",
|
|
@@ -973,23 +1008,433 @@ var MassIDRecyclingDateAttributeSchema = NftAttributeSchema.omit({
|
|
|
973
1008
|
title: "MassID Recycling Date Attribute",
|
|
974
1009
|
description: "MassID recycling date attribute using Unix timestamp in milliseconds"
|
|
975
1010
|
});
|
|
1011
|
+
var AuditRuleDefinitionSchema = zod.z.strictObject({
|
|
1012
|
+
rule_id: UuidSchema.meta({
|
|
1013
|
+
title: "Rule ID",
|
|
1014
|
+
description: "Unique identifier for the audit rule"
|
|
1015
|
+
}),
|
|
1016
|
+
rule_slug: SlugSchema.meta({
|
|
1017
|
+
title: "Rule Slug",
|
|
1018
|
+
description: "URL-friendly identifier for the rule"
|
|
1019
|
+
}),
|
|
1020
|
+
rule_name: NonEmptyStringSchema.max(100).meta({
|
|
1021
|
+
title: "Rule Name",
|
|
1022
|
+
description: "Human-readable name of the rule",
|
|
1023
|
+
examples: ["Waste Mass is Unique", "No Conflicting GasID or Credit"]
|
|
1024
|
+
}),
|
|
1025
|
+
description: zod.z.string().min(10).max(500).meta({
|
|
1026
|
+
title: "Rule Description",
|
|
1027
|
+
description: "Detailed description of what the rule validates and why it is necessary",
|
|
1028
|
+
examples: [
|
|
1029
|
+
"Validates that each MassID is unique within the system to prevent duplicate entries"
|
|
1030
|
+
]
|
|
1031
|
+
}),
|
|
1032
|
+
source_code_url: zod.z.url().regex(/^https:\/\/github\.com\/.*$/, "Must be a GitHub URL").meta({
|
|
1033
|
+
title: "Rule Source Code URL",
|
|
1034
|
+
description: "GitHub URL pointing to the implementation source code for this rule",
|
|
1035
|
+
examples: [
|
|
1036
|
+
"https://github.com/carrot-foundation/methodologies/blob/main/bold-carbon/rules/waste-mass-unique.js"
|
|
1037
|
+
]
|
|
1038
|
+
}),
|
|
1039
|
+
mandatory: zod.z.boolean().meta({
|
|
1040
|
+
title: "Mandatory",
|
|
1041
|
+
description: "Whether this rule is mandatory for methodology compliance"
|
|
1042
|
+
}),
|
|
1043
|
+
execution_order: PositiveIntegerSchema.meta({
|
|
1044
|
+
title: "Rule Execution Order",
|
|
1045
|
+
description: "Sequential order in which this rule must be executed"
|
|
1046
|
+
})
|
|
1047
|
+
}).meta({
|
|
1048
|
+
title: "Audit Rule Definition",
|
|
1049
|
+
description: "Definition of an audit rule that must be executed for methodology compliance"
|
|
1050
|
+
});
|
|
1051
|
+
var AuditRuleDefinitionsSchema = zod.z.array(AuditRuleDefinitionSchema).min(1).meta({
|
|
1052
|
+
title: "Audit Rule Definitions",
|
|
1053
|
+
description: "List of audit rules that must be executed to check methodology compliance"
|
|
1054
|
+
});
|
|
1055
|
+
var AuditRuleExecutionResultSchema = zod.z.strictObject({
|
|
1056
|
+
rule_name: NonEmptyStringSchema.meta({
|
|
1057
|
+
title: "Rule Name",
|
|
1058
|
+
description: "Human-readable name of the audit rule"
|
|
1059
|
+
}),
|
|
1060
|
+
rule_id: UuidSchema.meta({
|
|
1061
|
+
title: "Rule ID",
|
|
1062
|
+
description: "Unique identifier for the rule"
|
|
1063
|
+
}),
|
|
1064
|
+
rule_slug: SlugSchema.meta({
|
|
1065
|
+
title: "Rule Slug",
|
|
1066
|
+
description: "URL-friendly identifier for the rule"
|
|
1067
|
+
}),
|
|
1068
|
+
execution_order: PositiveIntegerSchema.meta({
|
|
1069
|
+
title: "Rule Execution Order",
|
|
1070
|
+
description: "Sequential order in which this rule was executed"
|
|
1071
|
+
}),
|
|
1072
|
+
result: MethodologyComplianceSchema.meta({
|
|
1073
|
+
title: "Rule Execution Result",
|
|
1074
|
+
description: "Result of the rule execution"
|
|
1075
|
+
}),
|
|
1076
|
+
description: zod.z.string().min(1).max(2e3).meta({
|
|
1077
|
+
title: "Rule Description",
|
|
1078
|
+
description: "Detailed description of what this rule validates"
|
|
1079
|
+
}),
|
|
1080
|
+
rule_processor_checksum: NonEmptyStringSchema.max(200).meta({
|
|
1081
|
+
title: "Rule Processor Checksum",
|
|
1082
|
+
description: "Checksum for rule processor integrity verification"
|
|
1083
|
+
}),
|
|
1084
|
+
rule_source_code_version: NonEmptyStringSchema.max(200).meta({
|
|
1085
|
+
title: "Rule Source Code Version",
|
|
1086
|
+
description: "Version identifier for the rule source code"
|
|
1087
|
+
})
|
|
1088
|
+
}).meta({
|
|
1089
|
+
title: "Audit Rule Execution Result",
|
|
1090
|
+
description: "Detailed result of an audit rule execution"
|
|
1091
|
+
});
|
|
1092
|
+
var AuditRuleExecutionResultsSchema = zod.z.array(AuditRuleExecutionResultSchema).meta({
|
|
1093
|
+
title: "Audit Rule Execution Results",
|
|
1094
|
+
description: "Detailed results of each audit rule execution"
|
|
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
|
+
}
|
|
976
1421
|
|
|
977
1422
|
// src/mass-id/mass-id.attributes.ts
|
|
978
|
-
var MassIDAttributeWasteTypeSchema = NftAttributeSchema.
|
|
1423
|
+
var MassIDAttributeWasteTypeSchema = NftAttributeSchema.safeExtend({
|
|
979
1424
|
trait_type: zod.z.literal("Waste Type"),
|
|
980
1425
|
value: WasteTypeSchema
|
|
981
1426
|
}).meta({
|
|
982
1427
|
title: "Waste Type Attribute",
|
|
983
1428
|
description: "Waste type attribute"
|
|
984
1429
|
});
|
|
985
|
-
var MassIDAttributeWasteSubtypeSchema = NftAttributeSchema.
|
|
1430
|
+
var MassIDAttributeWasteSubtypeSchema = NftAttributeSchema.safeExtend({
|
|
986
1431
|
trait_type: zod.z.literal("Waste Subtype"),
|
|
987
1432
|
value: WasteSubtypeSchema
|
|
988
1433
|
}).meta({
|
|
989
1434
|
title: "Waste Subtype Attribute",
|
|
990
1435
|
description: "Waste subtype attribute"
|
|
991
1436
|
});
|
|
992
|
-
var MassIDAttributeWeightSchema = NftAttributeSchema.
|
|
1437
|
+
var MassIDAttributeWeightSchema = NftAttributeSchema.safeExtend({
|
|
993
1438
|
trait_type: zod.z.literal("Weight (kg)"),
|
|
994
1439
|
value: WeightKgSchema,
|
|
995
1440
|
display_type: zod.z.literal("number")
|
|
@@ -997,20 +1442,20 @@ var MassIDAttributeWeightSchema = NftAttributeSchema.extend({
|
|
|
997
1442
|
title: "Weight Attribute",
|
|
998
1443
|
description: "Weight attribute with numeric display"
|
|
999
1444
|
});
|
|
1000
|
-
var MassIDAttributeOriginCountrySchema = OriginCountryAttributeSchema.
|
|
1445
|
+
var MassIDAttributeOriginCountrySchema = OriginCountryAttributeSchema.safeExtend({
|
|
1001
1446
|
value: CountryNameSchema
|
|
1002
1447
|
});
|
|
1003
|
-
var MassIDAttributeOriginMunicipalitySchema = OriginMunicipalityAttributeSchema.
|
|
1448
|
+
var MassIDAttributeOriginMunicipalitySchema = OriginMunicipalityAttributeSchema.safeExtend({
|
|
1004
1449
|
value: MunicipalitySchema
|
|
1005
1450
|
});
|
|
1006
|
-
var MassIDAttributeOriginDivisionSchema = NftAttributeSchema.
|
|
1451
|
+
var MassIDAttributeOriginDivisionSchema = NftAttributeSchema.safeExtend({
|
|
1007
1452
|
trait_type: zod.z.literal("Origin Administrative Division"),
|
|
1008
1453
|
value: AdministrativeDivisionSchema
|
|
1009
1454
|
}).meta({
|
|
1010
1455
|
title: "Origin Administrative Division Attribute",
|
|
1011
1456
|
description: "Origin administrative division attribute"
|
|
1012
1457
|
});
|
|
1013
|
-
var MassIDAttributeVehicleTypeSchema = NftAttributeSchema.
|
|
1458
|
+
var MassIDAttributeVehicleTypeSchema = NftAttributeSchema.safeExtend({
|
|
1014
1459
|
trait_type: zod.z.literal("Vehicle Type"),
|
|
1015
1460
|
value: NonEmptyStringSchema.max(100).meta({
|
|
1016
1461
|
title: "Vehicle Type",
|
|
@@ -1021,7 +1466,7 @@ var MassIDAttributeVehicleTypeSchema = NftAttributeSchema.extend({
|
|
|
1021
1466
|
title: "Vehicle Type Attribute",
|
|
1022
1467
|
description: "Vehicle type attribute"
|
|
1023
1468
|
});
|
|
1024
|
-
var MassIDAttributeRecyclingMethodSchema = NftAttributeSchema.
|
|
1469
|
+
var MassIDAttributeRecyclingMethodSchema = NftAttributeSchema.safeExtend({
|
|
1025
1470
|
trait_type: zod.z.literal("Recycling Method"),
|
|
1026
1471
|
value: NonEmptyStringSchema.max(100).meta({
|
|
1027
1472
|
title: "Recycling Method",
|
|
@@ -1036,7 +1481,7 @@ var MassIDAttributeRecyclingMethodSchema = NftAttributeSchema.extend({
|
|
|
1036
1481
|
title: "Recycling Method Attribute",
|
|
1037
1482
|
description: "Recycling method attribute"
|
|
1038
1483
|
});
|
|
1039
|
-
var MassIDAttributeProcessingTimeSchema = NftAttributeSchema.
|
|
1484
|
+
var MassIDAttributeProcessingTimeSchema = NftAttributeSchema.safeExtend({
|
|
1040
1485
|
trait_type: zod.z.literal("Processing Time (hours)"),
|
|
1041
1486
|
value: HoursSchema,
|
|
1042
1487
|
trait_description: NonEmptyStringSchema.max(200).optional().meta({
|
|
@@ -1047,7 +1492,7 @@ var MassIDAttributeProcessingTimeSchema = NftAttributeSchema.extend({
|
|
|
1047
1492
|
title: "Processing Time Attribute",
|
|
1048
1493
|
description: "Processing time attribute with optional trait description"
|
|
1049
1494
|
});
|
|
1050
|
-
var MassIDAttributeLocalWasteClassificationIdSchema = NftAttributeSchema.
|
|
1495
|
+
var MassIDAttributeLocalWasteClassificationIdSchema = NftAttributeSchema.safeExtend({
|
|
1051
1496
|
trait_type: zod.z.literal("Local Waste Classification ID"),
|
|
1052
1497
|
value: NonEmptyStringSchema.max(100).meta({
|
|
1053
1498
|
title: "Local Waste Classification ID",
|
|
@@ -1058,7 +1503,7 @@ var MassIDAttributeLocalWasteClassificationIdSchema = NftAttributeSchema.extend(
|
|
|
1058
1503
|
title: "Local Waste Classification ID Attribute",
|
|
1059
1504
|
description: "Local waste classification ID attribute"
|
|
1060
1505
|
});
|
|
1061
|
-
var MassIDAttributeRecyclingManifestCodeSchema = NftAttributeSchema.
|
|
1506
|
+
var MassIDAttributeRecyclingManifestCodeSchema = NftAttributeSchema.safeExtend({
|
|
1062
1507
|
trait_type: zod.z.literal("Recycling Manifest Code"),
|
|
1063
1508
|
value: NonEmptyStringSchema.max(100).meta({
|
|
1064
1509
|
title: "Recycling Manifest Code",
|
|
@@ -1069,7 +1514,7 @@ var MassIDAttributeRecyclingManifestCodeSchema = NftAttributeSchema.extend({
|
|
|
1069
1514
|
title: "Recycling Manifest Code Attribute",
|
|
1070
1515
|
description: "Recycling manifest code attribute (optional)"
|
|
1071
1516
|
});
|
|
1072
|
-
var MassIDAttributeTransportManifestCodeSchema = NftAttributeSchema.
|
|
1517
|
+
var MassIDAttributeTransportManifestCodeSchema = NftAttributeSchema.safeExtend({
|
|
1073
1518
|
trait_type: zod.z.literal("Transport Manifest Code"),
|
|
1074
1519
|
value: NonEmptyStringSchema.max(100).meta({
|
|
1075
1520
|
title: "Transport Manifest Code",
|
|
@@ -1080,7 +1525,7 @@ var MassIDAttributeTransportManifestCodeSchema = NftAttributeSchema.extend({
|
|
|
1080
1525
|
title: "Transport Manifest Code Attribute",
|
|
1081
1526
|
description: "Transport manifest code attribute (optional)"
|
|
1082
1527
|
});
|
|
1083
|
-
var MassIDAttributeWeighingCaptureMethodSchema = NftAttributeSchema.
|
|
1528
|
+
var MassIDAttributeWeighingCaptureMethodSchema = NftAttributeSchema.safeExtend({
|
|
1084
1529
|
trait_type: zod.z.literal("Weighing Capture Method"),
|
|
1085
1530
|
value: NonEmptyStringSchema.max(100).meta({
|
|
1086
1531
|
title: "Weighing Capture Method",
|
|
@@ -1091,7 +1536,7 @@ var MassIDAttributeWeighingCaptureMethodSchema = NftAttributeSchema.extend({
|
|
|
1091
1536
|
title: "Weighing Capture Method Attribute",
|
|
1092
1537
|
description: "Weighing capture method attribute (optional)"
|
|
1093
1538
|
});
|
|
1094
|
-
var MassIDAttributeScaleTypeSchema = NftAttributeSchema.
|
|
1539
|
+
var MassIDAttributeScaleTypeSchema = NftAttributeSchema.safeExtend({
|
|
1095
1540
|
trait_type: zod.z.literal("Scale Type"),
|
|
1096
1541
|
value: NonEmptyStringSchema.max(100).meta({
|
|
1097
1542
|
title: "Scale Type",
|
|
@@ -1107,7 +1552,7 @@ var MassIDAttributeScaleTypeSchema = NftAttributeSchema.extend({
|
|
|
1107
1552
|
title: "Scale Type Attribute",
|
|
1108
1553
|
description: "Scale type attribute (optional)"
|
|
1109
1554
|
});
|
|
1110
|
-
var MassIDAttributeContainerTypeSchema = NftAttributeSchema.
|
|
1555
|
+
var MassIDAttributeContainerTypeSchema = NftAttributeSchema.safeExtend({
|
|
1111
1556
|
trait_type: zod.z.literal("Container Type"),
|
|
1112
1557
|
value: NonEmptyStringSchema.max(100).meta({
|
|
1113
1558
|
title: "Container Type",
|
|
@@ -1118,7 +1563,7 @@ var MassIDAttributeContainerTypeSchema = NftAttributeSchema.extend({
|
|
|
1118
1563
|
title: "Container Type Attribute",
|
|
1119
1564
|
description: "Container type attribute (optional)"
|
|
1120
1565
|
});
|
|
1121
|
-
var MassIDAttributePickUpDateSchema = NftAttributeSchema.
|
|
1566
|
+
var MassIDAttributePickUpDateSchema = NftAttributeSchema.safeExtend({
|
|
1122
1567
|
trait_type: zod.z.literal("Pick-up Date"),
|
|
1123
1568
|
value: UnixTimestampSchema.meta({
|
|
1124
1569
|
title: "Pick-up Date",
|
|
@@ -1130,7 +1575,7 @@ var MassIDAttributePickUpDateSchema = NftAttributeSchema.extend({
|
|
|
1130
1575
|
title: "Pick-up Date Attribute",
|
|
1131
1576
|
description: "Pick-up date attribute with Unix timestamp"
|
|
1132
1577
|
});
|
|
1133
|
-
var MassIDAttributeRecyclingDateSchema = NftAttributeSchema.
|
|
1578
|
+
var MassIDAttributeRecyclingDateSchema = NftAttributeSchema.safeExtend({
|
|
1134
1579
|
trait_type: zod.z.literal("Recycling Date"),
|
|
1135
1580
|
value: UnixTimestampSchema.meta({
|
|
1136
1581
|
title: "Recycling Date",
|
|
@@ -1469,7 +1914,7 @@ var MassIDIpfsSchema = NftIpfsSchema.safeExtend({
|
|
|
1469
1914
|
data: MassIDDataSchema
|
|
1470
1915
|
}).meta(MassIDIpfsSchemaMeta);
|
|
1471
1916
|
var GasIDAttributeMethodologySchema = MethodologyAttributeSchema;
|
|
1472
|
-
var GasIDAttributeGasTypeSchema = NftAttributeSchema.
|
|
1917
|
+
var GasIDAttributeGasTypeSchema = NftAttributeSchema.safeExtend({
|
|
1473
1918
|
trait_type: zod.z.literal("Gas Type"),
|
|
1474
1919
|
value: NonEmptyStringSchema.max(100).meta({
|
|
1475
1920
|
title: "Gas Type",
|
|
@@ -1480,7 +1925,7 @@ var GasIDAttributeGasTypeSchema = NftAttributeSchema.extend({
|
|
|
1480
1925
|
title: "Gas Type Attribute",
|
|
1481
1926
|
description: "Gas type attribute"
|
|
1482
1927
|
});
|
|
1483
|
-
var GasIDAttributeCo2ePreventedSchema = NftAttributeSchema.
|
|
1928
|
+
var GasIDAttributeCo2ePreventedSchema = NftAttributeSchema.safeExtend({
|
|
1484
1929
|
trait_type: zod.z.literal("CO\u2082e Prevented (kg)"),
|
|
1485
1930
|
value: NonNegativeFloatSchema.meta({
|
|
1486
1931
|
title: "CO\u2082e Prevented",
|
|
@@ -1614,7 +2059,7 @@ var GasIDIpfsSchema = NftIpfsSchema.safeExtend({
|
|
|
1614
2059
|
data: GasIDDataSchema
|
|
1615
2060
|
}).meta(GasIDIpfsSchemaMeta);
|
|
1616
2061
|
var RecycledIDAttributeMethodologySchema = MethodologyAttributeSchema;
|
|
1617
|
-
var RecycledIDAttributeRecycledMassWeightSchema = NftAttributeSchema.
|
|
2062
|
+
var RecycledIDAttributeRecycledMassWeightSchema = NftAttributeSchema.safeExtend({
|
|
1618
2063
|
trait_type: zod.z.literal("Recycled Mass Weight (kg)"),
|
|
1619
2064
|
value: WeightKgSchema.meta({
|
|
1620
2065
|
title: "Recycled Mass Weight",
|
|
@@ -1693,20 +2138,1296 @@ var RecycledIDIpfsSchema = NftIpfsSchema.safeExtend({
|
|
|
1693
2138
|
attributes: RecycledIDAttributesSchema,
|
|
1694
2139
|
data: RecycledIDDataSchema
|
|
1695
2140
|
}).meta(RecycledIDIpfsSchemaMeta);
|
|
2141
|
+
var CreditPurchaseReceiptCreditAttributeSchema = NftAttributeSchema.safeExtend({
|
|
2142
|
+
trait_type: TokenSymbolSchema.meta({
|
|
2143
|
+
title: "Credit Token Symbol",
|
|
2144
|
+
description: "Symbol of the credit token (e.g., C-CARB, C-BIOW)",
|
|
2145
|
+
examples: ["C-CARB", "C-BIOW"]
|
|
2146
|
+
}),
|
|
2147
|
+
value: CreditAmountSchema.meta({
|
|
2148
|
+
title: "Credit Amount",
|
|
2149
|
+
description: "Amount of credits purchased for the token symbol"
|
|
2150
|
+
}),
|
|
2151
|
+
display_type: zod.z.literal("number")
|
|
2152
|
+
}).meta({
|
|
2153
|
+
title: "Credit Attribute",
|
|
2154
|
+
description: "Attribute representing purchased amount per credit token symbol"
|
|
2155
|
+
});
|
|
2156
|
+
var CreditPurchaseReceiptTotalCreditsAttributeSchema = NftAttributeSchema.safeExtend({
|
|
2157
|
+
trait_type: zod.z.literal("Total Credits Purchased"),
|
|
2158
|
+
value: CreditAmountSchema.meta({
|
|
2159
|
+
title: "Total Credits Purchased",
|
|
2160
|
+
description: "Total number of credits purchased across all tokens"
|
|
2161
|
+
}),
|
|
2162
|
+
display_type: zod.z.literal("number")
|
|
2163
|
+
}).meta({
|
|
2164
|
+
title: "Total Credits Purchased Attribute",
|
|
2165
|
+
description: "Aggregate credits purchased attribute"
|
|
2166
|
+
});
|
|
2167
|
+
var CreditPurchaseReceiptTotalUsdcAttributeSchema = NftAttributeSchema.safeExtend({
|
|
2168
|
+
trait_type: zod.z.literal("Total USDC Amount"),
|
|
2169
|
+
value: CreditAmountSchema.meta({
|
|
2170
|
+
title: "Total USDC Amount",
|
|
2171
|
+
description: "Total USDC amount paid for the purchase"
|
|
2172
|
+
}),
|
|
2173
|
+
display_type: zod.z.literal("number")
|
|
2174
|
+
}).meta({
|
|
2175
|
+
title: "Total USDC Amount Attribute",
|
|
2176
|
+
description: "Aggregate USDC amount attribute"
|
|
2177
|
+
});
|
|
2178
|
+
var CreditPurchaseReceiptPurchaseDateAttributeSchema = NftAttributeSchema.safeExtend({
|
|
2179
|
+
trait_type: zod.z.literal("Purchase Date"),
|
|
2180
|
+
value: UnixTimestampSchema.meta({
|
|
2181
|
+
title: "Purchase Date",
|
|
2182
|
+
description: "Unix timestamp in milliseconds when the purchase was completed"
|
|
2183
|
+
}),
|
|
2184
|
+
display_type: zod.z.literal("date")
|
|
2185
|
+
}).meta({
|
|
2186
|
+
title: "Purchase Date Attribute",
|
|
2187
|
+
description: "Purchase date attribute using Unix timestamp in milliseconds"
|
|
2188
|
+
});
|
|
2189
|
+
var CreditPurchaseReceiptCertificatesAttributeSchema = NftAttributeSchema.safeExtend({
|
|
2190
|
+
trait_type: zod.z.literal("Certificates Purchased"),
|
|
2191
|
+
value: PositiveIntegerSchema.meta({
|
|
2192
|
+
title: "Certificates Purchased",
|
|
2193
|
+
description: "Total number of certificates purchased"
|
|
2194
|
+
}),
|
|
2195
|
+
display_type: zod.z.literal("number")
|
|
2196
|
+
}).meta({
|
|
2197
|
+
title: "Certificates Purchased Attribute",
|
|
2198
|
+
description: "Attribute representing how many certificates were purchased"
|
|
2199
|
+
});
|
|
2200
|
+
var CreditPurchaseReceiptReceiverAttributeSchema = NftAttributeSchema.omit({
|
|
2201
|
+
display_type: true,
|
|
2202
|
+
max_value: true
|
|
2203
|
+
}).safeExtend({
|
|
2204
|
+
trait_type: zod.z.literal("Receiver"),
|
|
2205
|
+
value: ParticipantNameSchema.meta({
|
|
2206
|
+
title: "Receiver",
|
|
2207
|
+
description: "Organization or individual receiving the credits from the purchase",
|
|
2208
|
+
examples: ["EcoTech Solutions Inc."]
|
|
2209
|
+
})
|
|
2210
|
+
}).meta({
|
|
2211
|
+
title: "Receiver Attribute",
|
|
2212
|
+
description: "Attribute containing the receiver display name"
|
|
2213
|
+
});
|
|
2214
|
+
var CreditPurchaseReceiptCollectionAttributeSchema = NftAttributeSchema.safeExtend({
|
|
2215
|
+
trait_type: CollectionNameSchema,
|
|
2216
|
+
value: CreditAmountSchema.meta({
|
|
2217
|
+
title: "Credits from Collection",
|
|
2218
|
+
description: "Amount of credits purchased from the collection"
|
|
2219
|
+
}),
|
|
2220
|
+
display_type: zod.z.literal("number")
|
|
2221
|
+
}).meta({
|
|
2222
|
+
title: "Collection Attribute",
|
|
2223
|
+
description: "Attribute representing the amount of credits purchased from a collection"
|
|
2224
|
+
});
|
|
2225
|
+
var CreditPurchaseReceiptAttributesSchema = uniqueBy(
|
|
2226
|
+
zod.z.union([
|
|
2227
|
+
CreditPurchaseReceiptCreditAttributeSchema,
|
|
2228
|
+
CreditPurchaseReceiptTotalCreditsAttributeSchema,
|
|
2229
|
+
CreditPurchaseReceiptTotalUsdcAttributeSchema,
|
|
2230
|
+
CreditPurchaseReceiptPurchaseDateAttributeSchema,
|
|
2231
|
+
CreditPurchaseReceiptCertificatesAttributeSchema,
|
|
2232
|
+
CreditPurchaseReceiptReceiverAttributeSchema,
|
|
2233
|
+
CreditPurchaseReceiptCollectionAttributeSchema
|
|
2234
|
+
]),
|
|
2235
|
+
(attribute) => attribute.trait_type,
|
|
2236
|
+
"Attribute trait_type values must be unique"
|
|
2237
|
+
).min(5).meta({
|
|
2238
|
+
title: "Credit Purchase Receipt NFT Attribute Array",
|
|
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."
|
|
2240
|
+
});
|
|
2241
|
+
var CreditPurchaseReceiptIdentitySchema = ReceiptIdentitySchema;
|
|
2242
|
+
var CreditPurchaseReceiptReceiverSchema = zod.z.strictObject({
|
|
2243
|
+
wallet_address: EthereumAddressSchema.meta({
|
|
2244
|
+
title: "Receiver Wallet Address",
|
|
2245
|
+
description: "Ethereum address of the receiver"
|
|
2246
|
+
}),
|
|
2247
|
+
identity: CreditPurchaseReceiptIdentitySchema.optional()
|
|
2248
|
+
}).meta({
|
|
2249
|
+
title: "Receiver",
|
|
2250
|
+
description: "Receiver wallet and optional identity information"
|
|
2251
|
+
});
|
|
2252
|
+
var CreditPurchaseReceiptBuyerSchema = zod.z.strictObject({
|
|
2253
|
+
buyer_id: ExternalIdSchema.meta({
|
|
2254
|
+
title: "Buyer ID",
|
|
2255
|
+
description: "Unique identifier for the buyer"
|
|
2256
|
+
}),
|
|
2257
|
+
identity: CreditPurchaseReceiptIdentitySchema.optional()
|
|
2258
|
+
}).meta({
|
|
2259
|
+
title: "Buyer",
|
|
2260
|
+
description: "Buyer identifier and optional identity information"
|
|
2261
|
+
});
|
|
2262
|
+
var CreditPurchaseReceiptPartiesSchema = zod.z.strictObject({
|
|
2263
|
+
payer: EthereumAddressSchema.meta({
|
|
2264
|
+
title: "Payer Wallet Address",
|
|
2265
|
+
description: "Ethereum address paying for the purchase"
|
|
2266
|
+
}),
|
|
2267
|
+
receiver: CreditPurchaseReceiptReceiverSchema,
|
|
2268
|
+
buyer: CreditPurchaseReceiptBuyerSchema.optional()
|
|
2269
|
+
}).meta({
|
|
2270
|
+
title: "Parties",
|
|
2271
|
+
description: "Parties involved in the purchase including payer, receiver, and optional buyer"
|
|
2272
|
+
});
|
|
2273
|
+
var CreditPurchaseReceiptCollectionSchema = createReceiptCollectionSchema({
|
|
2274
|
+
amountKey: "credit_amount",
|
|
2275
|
+
amountMeta: {
|
|
2276
|
+
title: "Collection Credit Amount",
|
|
2277
|
+
description: "Total credits purchased from this collection"
|
|
2278
|
+
},
|
|
2279
|
+
meta: {
|
|
2280
|
+
title: "Collection",
|
|
2281
|
+
description: "Collection included in the purchase"
|
|
2282
|
+
}
|
|
2283
|
+
});
|
|
2284
|
+
var CreditPurchaseReceiptCreditSchema = createReceiptCreditSchema({
|
|
2285
|
+
amountKey: "purchase_amount",
|
|
2286
|
+
amountMeta: {
|
|
2287
|
+
title: "Credit Purchase Amount",
|
|
2288
|
+
description: "Total credits purchased for this credit type"
|
|
2289
|
+
},
|
|
2290
|
+
retirementAmountMeta: {
|
|
2291
|
+
title: "Credit Retirement Amount",
|
|
2292
|
+
description: "Credits retired immediately for this credit type during purchase"
|
|
2293
|
+
},
|
|
2294
|
+
meta: {
|
|
2295
|
+
title: "Credit",
|
|
2296
|
+
description: "Credit token included in the purchase"
|
|
2297
|
+
}
|
|
2298
|
+
});
|
|
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
|
+
}
|
|
2319
|
+
});
|
|
2320
|
+
var CreditPurchaseReceiptParticipantRewardSchema = zod.z.strictObject({
|
|
2321
|
+
id_hash: Sha256HashSchema.meta({
|
|
2322
|
+
title: "Participant ID Hash",
|
|
2323
|
+
description: "Hash representing the participant identifier (SHA-256 hex string)"
|
|
2324
|
+
}),
|
|
2325
|
+
participant_name: ParticipantNameSchema.meta({
|
|
2326
|
+
title: "Participant Name",
|
|
2327
|
+
description: "Legal name of the participant receiving the reward"
|
|
2328
|
+
}),
|
|
2329
|
+
roles: uniqueArrayItems(
|
|
2330
|
+
ParticipantRoleSchema,
|
|
2331
|
+
"Participant roles must be unique"
|
|
2332
|
+
).min(1).meta({
|
|
2333
|
+
title: "Participant Roles",
|
|
2334
|
+
description: "Roles the participant has in the supply chain"
|
|
2335
|
+
}),
|
|
2336
|
+
usdc_amount: NonNegativeFloatSchema.meta({
|
|
2337
|
+
title: "USDC Reward Amount",
|
|
2338
|
+
description: "USDC amount allocated to this participant"
|
|
2339
|
+
})
|
|
2340
|
+
}).meta({
|
|
2341
|
+
title: "Participant Reward",
|
|
2342
|
+
description: "Reward distribution for a participant"
|
|
2343
|
+
});
|
|
2344
|
+
var CreditPurchaseReceiptRetirementReceiptSchema = zod.z.strictObject({
|
|
2345
|
+
token_id: TokenIdSchema.meta({
|
|
2346
|
+
title: "Retirement Receipt Token ID",
|
|
2347
|
+
description: "Token ID of the retirement receipt NFT"
|
|
2348
|
+
}),
|
|
2349
|
+
external_id: ExternalIdSchema.meta({
|
|
2350
|
+
title: "Retirement Receipt External ID",
|
|
2351
|
+
description: "External identifier for the retirement receipt"
|
|
2352
|
+
}),
|
|
2353
|
+
external_url: ExternalUrlSchema.meta({
|
|
2354
|
+
title: "Retirement Receipt External URL",
|
|
2355
|
+
description: "External URL for the retirement receipt"
|
|
2356
|
+
}),
|
|
2357
|
+
uri: IpfsUriSchema.meta({
|
|
2358
|
+
title: "Retirement Receipt URI",
|
|
2359
|
+
description: "IPFS URI for the retirement receipt metadata"
|
|
2360
|
+
}),
|
|
2361
|
+
smart_contract: SmartContractSchema
|
|
2362
|
+
}).meta({
|
|
2363
|
+
title: "Retirement Receipt Reference",
|
|
2364
|
+
description: "Reference to the retirement receipt NFT"
|
|
2365
|
+
});
|
|
2366
|
+
var CreditPurchaseReceiptRetirementSchema = zod.z.strictObject({
|
|
2367
|
+
beneficiary_id: ExternalIdSchema.meta({
|
|
2368
|
+
title: "Retirement Beneficiary ID",
|
|
2369
|
+
description: "UUID identifying the beneficiary of the retirement (bytes16 normalized to UUID)"
|
|
2370
|
+
}),
|
|
2371
|
+
retirement_receipt: CreditPurchaseReceiptRetirementReceiptSchema.optional()
|
|
2372
|
+
}).meta({
|
|
2373
|
+
title: "Retirement",
|
|
2374
|
+
description: "Immediate retirement details performed as part of purchase"
|
|
2375
|
+
});
|
|
2376
|
+
var CreditPurchaseReceiptDataSchema = zod.z.strictObject({
|
|
2377
|
+
summary: CreditPurchaseReceiptSummarySchema,
|
|
2378
|
+
parties: CreditPurchaseReceiptPartiesSchema,
|
|
2379
|
+
collections: uniqueBy(
|
|
2380
|
+
CreditPurchaseReceiptCollectionSchema,
|
|
2381
|
+
(collection) => collection.slug,
|
|
2382
|
+
"Collection slugs must be unique"
|
|
2383
|
+
).min(1).meta({
|
|
2384
|
+
title: "Collections",
|
|
2385
|
+
description: "Collections included in the purchase"
|
|
2386
|
+
}),
|
|
2387
|
+
credits: uniqueBy(
|
|
2388
|
+
CreditPurchaseReceiptCreditSchema,
|
|
2389
|
+
(credit) => credit.slug,
|
|
2390
|
+
"Credit slugs must be unique"
|
|
2391
|
+
).min(1).meta({
|
|
2392
|
+
title: "Credits",
|
|
2393
|
+
description: "Credits included in the purchase"
|
|
2394
|
+
}),
|
|
2395
|
+
certificates: uniqueBy(
|
|
2396
|
+
CreditPurchaseReceiptCertificateSchema,
|
|
2397
|
+
(certificate) => certificate.token_id,
|
|
2398
|
+
"Certificate token_ids must be unique"
|
|
2399
|
+
).min(1).meta({
|
|
2400
|
+
title: "Certificates",
|
|
2401
|
+
description: "Certificates involved in the purchase"
|
|
2402
|
+
}),
|
|
2403
|
+
participant_rewards: uniqueBy(
|
|
2404
|
+
CreditPurchaseReceiptParticipantRewardSchema,
|
|
2405
|
+
(reward) => reward.id_hash,
|
|
2406
|
+
"Participant id_hash must be unique"
|
|
2407
|
+
).min(1).meta({
|
|
2408
|
+
title: "Participant Rewards",
|
|
2409
|
+
description: "Rewards distributed to participants in the supply chain for this purchase"
|
|
2410
|
+
}),
|
|
2411
|
+
retirement: CreditPurchaseReceiptRetirementSchema.optional()
|
|
2412
|
+
}).superRefine((data, ctx) => {
|
|
2413
|
+
const retirementProvided = Boolean(data.retirement);
|
|
2414
|
+
const creditsWithRetirement = data.credits.reduce(
|
|
2415
|
+
(indices, credit, index) => {
|
|
2416
|
+
const retirementAmount = Number(credit.retirement_amount ?? 0);
|
|
2417
|
+
if (retirementAmount > 0) {
|
|
2418
|
+
indices.push(index);
|
|
2419
|
+
}
|
|
2420
|
+
return indices;
|
|
2421
|
+
},
|
|
2422
|
+
[]
|
|
2423
|
+
);
|
|
2424
|
+
if (retirementProvided && creditsWithRetirement.length === 0) {
|
|
2425
|
+
ctx.addIssue({
|
|
2426
|
+
code: "custom",
|
|
2427
|
+
message: "retirement is present but no credit has retirement_amount greater than 0",
|
|
2428
|
+
path: ["retirement"]
|
|
2429
|
+
});
|
|
2430
|
+
}
|
|
2431
|
+
if (!retirementProvided && creditsWithRetirement.length > 0) {
|
|
2432
|
+
creditsWithRetirement.forEach((index) => {
|
|
2433
|
+
ctx.addIssue({
|
|
2434
|
+
code: "custom",
|
|
2435
|
+
message: "credit retirement_amount greater than 0 requires retirement details",
|
|
2436
|
+
path: ["credits", index, "retirement_amount"]
|
|
2437
|
+
});
|
|
2438
|
+
});
|
|
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
|
+
});
|
|
2447
|
+
const collectionSlugs = new Set(
|
|
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))
|
|
2455
|
+
);
|
|
2456
|
+
const certificateTypes = new Set(
|
|
2457
|
+
data.certificates.map((certificate) => String(certificate.type))
|
|
2458
|
+
);
|
|
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"
|
|
2466
|
+
});
|
|
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"
|
|
2482
|
+
});
|
|
2483
|
+
const creditPurchaseTotalsBySlug = /* @__PURE__ */ new Map();
|
|
2484
|
+
const creditRetiredTotalsBySlug = /* @__PURE__ */ new Map();
|
|
2485
|
+
const collectionTotalsBySlug = /* @__PURE__ */ new Map();
|
|
2486
|
+
let totalCreditsFromCertificates = 0;
|
|
2487
|
+
data.certificates.forEach((certificate, index) => {
|
|
2488
|
+
if (!collectionSlugs.has(certificate.collection_slug)) {
|
|
2489
|
+
ctx.addIssue({
|
|
2490
|
+
code: "custom",
|
|
2491
|
+
message: "collection_slug must match a collection slug in collections",
|
|
2492
|
+
path: ["certificates", index, "collection_slug"]
|
|
2493
|
+
});
|
|
2494
|
+
}
|
|
2495
|
+
if (!creditSlugs.has(certificate.credit_slug)) {
|
|
2496
|
+
ctx.addIssue({
|
|
2497
|
+
code: "custom",
|
|
2498
|
+
message: "credit_slug must match a credit slug in credits",
|
|
2499
|
+
path: ["certificates", index, "credit_slug"]
|
|
2500
|
+
});
|
|
2501
|
+
}
|
|
2502
|
+
if (certificate.retired_amount > certificate.purchased_amount) {
|
|
2503
|
+
ctx.addIssue({
|
|
2504
|
+
code: "custom",
|
|
2505
|
+
message: "retired_amount cannot exceed purchased_amount",
|
|
2506
|
+
path: ["certificates", index, "retired_amount"]
|
|
2507
|
+
});
|
|
2508
|
+
}
|
|
2509
|
+
if (certificate.purchased_amount > certificate.total_amount) {
|
|
2510
|
+
ctx.addIssue({
|
|
2511
|
+
code: "custom",
|
|
2512
|
+
message: "purchased_amount cannot exceed total_amount",
|
|
2513
|
+
path: ["certificates", index, "purchased_amount"]
|
|
2514
|
+
});
|
|
2515
|
+
}
|
|
2516
|
+
totalCreditsFromCertificates += Number(certificate.purchased_amount);
|
|
2517
|
+
creditPurchaseTotalsBySlug.set(
|
|
2518
|
+
String(certificate.credit_slug),
|
|
2519
|
+
(creditPurchaseTotalsBySlug.get(certificate.credit_slug) ?? 0) + Number(certificate.purchased_amount)
|
|
2520
|
+
);
|
|
2521
|
+
creditRetiredTotalsBySlug.set(
|
|
2522
|
+
String(certificate.credit_slug),
|
|
2523
|
+
(creditRetiredTotalsBySlug.get(certificate.credit_slug) ?? 0) + Number(certificate.retired_amount)
|
|
2524
|
+
);
|
|
2525
|
+
collectionTotalsBySlug.set(
|
|
2526
|
+
String(certificate.collection_slug),
|
|
2527
|
+
(collectionTotalsBySlug.get(certificate.collection_slug) ?? 0) + Number(certificate.purchased_amount)
|
|
2528
|
+
);
|
|
2529
|
+
});
|
|
2530
|
+
const totalCreditsFromCollections = data.collections.reduce(
|
|
2531
|
+
(sum, collection) => sum + Number(collection.credit_amount),
|
|
2532
|
+
0
|
|
2533
|
+
);
|
|
2534
|
+
const totalCreditsFromCredits = data.credits.reduce(
|
|
2535
|
+
(sum, credit) => sum + Number(credit.purchase_amount),
|
|
2536
|
+
0
|
|
2537
|
+
);
|
|
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
|
+
});
|
|
2559
|
+
data.credits.forEach((credit, index) => {
|
|
2560
|
+
const purchasedTotal = creditPurchaseTotalsBySlug.get(String(credit.slug)) ?? 0;
|
|
2561
|
+
if (!nearlyEqual(Number(credit.purchase_amount), purchasedTotal)) {
|
|
2562
|
+
ctx.addIssue({
|
|
2563
|
+
code: "custom",
|
|
2564
|
+
message: "credit.purchase_amount must equal sum of certificate purchased_amount for the credit slug",
|
|
2565
|
+
path: ["credits", index, "purchase_amount"]
|
|
2566
|
+
});
|
|
2567
|
+
}
|
|
2568
|
+
const retiredTotal = creditRetiredTotalsBySlug.get(String(credit.slug)) ?? 0;
|
|
2569
|
+
const retirementAmount = Number(credit.retirement_amount ?? 0);
|
|
2570
|
+
if (!nearlyEqual(retirementAmount, retiredTotal)) {
|
|
2571
|
+
ctx.addIssue({
|
|
2572
|
+
code: "custom",
|
|
2573
|
+
message: "credit.retirement_amount must equal sum of certificate retired_amount for the credit slug",
|
|
2574
|
+
path: ["credits", index, "retirement_amount"]
|
|
2575
|
+
});
|
|
2576
|
+
}
|
|
2577
|
+
});
|
|
2578
|
+
data.collections.forEach((collection, index) => {
|
|
2579
|
+
const purchasedTotal = collectionTotalsBySlug.get(String(collection.slug)) ?? 0;
|
|
2580
|
+
if (!nearlyEqual(Number(collection.credit_amount), purchasedTotal)) {
|
|
2581
|
+
ctx.addIssue({
|
|
2582
|
+
code: "custom",
|
|
2583
|
+
message: "collection.credit_amount must equal sum of certificate purchased_amount for the collection slug",
|
|
2584
|
+
path: ["collections", index, "credit_amount"]
|
|
2585
|
+
});
|
|
2586
|
+
}
|
|
2587
|
+
});
|
|
2588
|
+
const participantRewardTotal = data.participant_rewards.reduce(
|
|
2589
|
+
(sum, reward) => sum + Number(reward.usdc_amount),
|
|
2590
|
+
0
|
|
2591
|
+
);
|
|
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
|
+
});
|
|
2599
|
+
}).meta({
|
|
2600
|
+
title: "Credit Purchase Receipt Data",
|
|
2601
|
+
description: "Complete data structure for a credit purchase receipt"
|
|
2602
|
+
});
|
|
2603
|
+
var CreditPurchaseReceiptIpfsSchemaMeta = {
|
|
2604
|
+
title: "CreditPurchaseReceipt NFT IPFS Record",
|
|
2605
|
+
description: "Complete CreditPurchaseReceipt NFT IPFS record including attributes and credit purchase data",
|
|
2606
|
+
$id: buildSchemaUrl(
|
|
2607
|
+
"credit-purchase-receipt/credit-purchase-receipt.schema.json"
|
|
2608
|
+
),
|
|
2609
|
+
version: getSchemaVersionOrDefault()
|
|
2610
|
+
};
|
|
2611
|
+
var CreditPurchaseReceiptIpfsSchema = NftIpfsSchema.safeExtend({
|
|
2612
|
+
schema: NftIpfsSchema.shape.schema.safeExtend({
|
|
2613
|
+
type: zod.z.literal("CreditPurchaseReceipt").meta({
|
|
2614
|
+
title: "CreditPurchaseReceipt Schema Type",
|
|
2615
|
+
description: "CreditPurchaseReceipt NFT schema type"
|
|
2616
|
+
})
|
|
2617
|
+
}),
|
|
2618
|
+
attributes: CreditPurchaseReceiptAttributesSchema,
|
|
2619
|
+
data: CreditPurchaseReceiptDataSchema
|
|
2620
|
+
}).superRefine((value, ctx) => {
|
|
2621
|
+
const attributes = value.attributes;
|
|
2622
|
+
const data = value.data;
|
|
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'
|
|
2657
|
+
});
|
|
2658
|
+
}
|
|
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"
|
|
2811
|
+
}
|
|
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"
|
|
2822
|
+
}
|
|
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
|
+
}
|
|
2892
|
+
}
|
|
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)) {
|
|
2972
|
+
ctx.addIssue({
|
|
2973
|
+
code: "custom",
|
|
2974
|
+
message: "collection_slug must match a collection slug in collections",
|
|
2975
|
+
path: ["certificates", index, "collection_slug"]
|
|
2976
|
+
});
|
|
2977
|
+
}
|
|
2978
|
+
if (certificate.retired_amount > certificate.total_amount) {
|
|
2979
|
+
ctx.addIssue({
|
|
2980
|
+
code: "custom",
|
|
2981
|
+
message: "retired_amount cannot exceed total_amount",
|
|
2982
|
+
path: ["certificates", index, "retired_amount"]
|
|
2983
|
+
});
|
|
2984
|
+
}
|
|
2985
|
+
const creditsRetiredTotal = certificate.credits_retired.reduce(
|
|
2986
|
+
(sum, credit) => sum + Number(credit.amount),
|
|
2987
|
+
0
|
|
2988
|
+
);
|
|
2989
|
+
if (!nearlyEqual(creditsRetiredTotal, certificate.retired_amount)) {
|
|
2990
|
+
ctx.addIssue({
|
|
2991
|
+
code: "custom",
|
|
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"]
|
|
3062
|
+
});
|
|
3063
|
+
}
|
|
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)) {
|
|
3089
|
+
ctx.addIssue({
|
|
3090
|
+
code: "custom",
|
|
3091
|
+
message: "credit.amount must equal sum of retired amounts for the credit symbol across certificates",
|
|
3092
|
+
path: ["credits", index, "amount"]
|
|
3093
|
+
});
|
|
3094
|
+
}
|
|
3095
|
+
});
|
|
3096
|
+
data.collections.forEach((collection, index) => {
|
|
3097
|
+
const retiredTotal = collectionTotalsBySlug.get(String(collection.slug)) ?? 0;
|
|
3098
|
+
if (retiredTotal === 0) {
|
|
3099
|
+
ctx.addIssue({
|
|
3100
|
+
code: "custom",
|
|
3101
|
+
message: "collection must be referenced by at least one certificate with retired_amount > 0",
|
|
3102
|
+
path: ["collections", index, "slug"]
|
|
3103
|
+
});
|
|
3104
|
+
}
|
|
3105
|
+
if (Number(collection.amount) <= 0) {
|
|
3106
|
+
ctx.addIssue({
|
|
3107
|
+
code: "custom",
|
|
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"]
|
|
3117
|
+
});
|
|
3118
|
+
}
|
|
3119
|
+
});
|
|
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);
|
|
3212
|
+
var CollectionSchemaMeta = {
|
|
3213
|
+
title: "Collection IPFS Record",
|
|
3214
|
+
description: "Collection metadata stored in IPFS, extending the base schema with collection-specific fields required for NFT collection definitions in Carrot's ecosystem",
|
|
3215
|
+
$id: buildSchemaUrl("collection/collection.schema.json"),
|
|
3216
|
+
version: getSchemaVersionOrDefault()
|
|
3217
|
+
};
|
|
3218
|
+
var CollectionSchema = BaseIpfsSchema.safeExtend({
|
|
3219
|
+
schema: BaseIpfsSchema.shape.schema.safeExtend({
|
|
3220
|
+
type: zod.z.literal("Collection").meta({
|
|
3221
|
+
title: "Collection Schema Type",
|
|
3222
|
+
description: "Collection schema type"
|
|
3223
|
+
})
|
|
3224
|
+
}),
|
|
3225
|
+
name: CollectionNameSchema,
|
|
3226
|
+
slug: CollectionSlugSchema.optional(),
|
|
3227
|
+
image: IpfsUriSchema.meta({
|
|
3228
|
+
title: "Collection Image",
|
|
3229
|
+
description: "IPFS URI pointing to the collection's visual representation",
|
|
3230
|
+
examples: ["ipfs://QmCollectionImageHash/collection-icon.png"]
|
|
3231
|
+
}),
|
|
3232
|
+
description: zod.z.string().min(50).max(1e3).meta({
|
|
3233
|
+
title: "Collection Description",
|
|
3234
|
+
description: "Comprehensive description of the collection, its purpose, and context",
|
|
3235
|
+
examples: [
|
|
3236
|
+
"Cold Start is a limited-edition collection created for early supporters of BOLD - Breakthrough in Organic Landfill Diversion. This purchase contributes to reducing global waste and promoting circularity, with funds distributed via smart contract to local recycling operations and communities."
|
|
3237
|
+
]
|
|
3238
|
+
})
|
|
3239
|
+
}).meta(CollectionSchemaMeta);
|
|
3240
|
+
var CreditSchemaMeta = {
|
|
3241
|
+
title: "Credit IPFS Record",
|
|
3242
|
+
description: "Credit token metadata stored in IPFS, extending the base schema with ERC20-specific details",
|
|
3243
|
+
$id: buildSchemaUrl("credit/credit.schema.json"),
|
|
3244
|
+
version: getSchemaVersionOrDefault()
|
|
3245
|
+
};
|
|
3246
|
+
var CreditSchema = BaseIpfsSchema.safeExtend({
|
|
3247
|
+
schema: BaseIpfsSchema.shape.schema.safeExtend({
|
|
3248
|
+
type: zod.z.literal("Credit").meta({
|
|
3249
|
+
title: "Credit Schema Type",
|
|
3250
|
+
description: "Credit schema type"
|
|
3251
|
+
})
|
|
3252
|
+
}),
|
|
3253
|
+
symbol: TokenSymbolSchema,
|
|
3254
|
+
slug: SlugSchema.meta({
|
|
3255
|
+
title: "Token Slug",
|
|
3256
|
+
description: "URL-friendly identifier for the token",
|
|
3257
|
+
examples: ["carbon"]
|
|
3258
|
+
}).optional(),
|
|
3259
|
+
name: NonEmptyStringSchema.meta({
|
|
3260
|
+
title: "Token Name",
|
|
3261
|
+
description: "Full human-readable name of the ERC20 token",
|
|
3262
|
+
examples: ["Carrot Carbon"]
|
|
3263
|
+
}),
|
|
3264
|
+
decimals: zod.z.number().int().min(0).max(18).meta({
|
|
3265
|
+
title: "Token Decimals",
|
|
3266
|
+
description: "Number of decimal places for the ERC20 token",
|
|
3267
|
+
examples: [18]
|
|
3268
|
+
}),
|
|
3269
|
+
image: IpfsUriSchema.meta({
|
|
3270
|
+
title: "Token Image",
|
|
3271
|
+
description: "IPFS URI pointing to the token's visual representation image",
|
|
3272
|
+
examples: ["ipfs://QmTokenImageHash/credit-icon.png"]
|
|
3273
|
+
}),
|
|
3274
|
+
description: zod.z.string().min(50).max(1e3).meta({
|
|
3275
|
+
title: "Token Description",
|
|
3276
|
+
description: "Comprehensive description of the credit token, its purpose, and impact",
|
|
3277
|
+
examples: [
|
|
3278
|
+
"Carrot Carbon (C-CARB) represents verified carbon emissions reductions from organic waste composting projects. Each token equals one metric ton of CO2 equivalent prevented from entering the atmosphere through sustainable waste management practices."
|
|
3279
|
+
]
|
|
3280
|
+
})
|
|
3281
|
+
}).meta(CreditSchemaMeta);
|
|
3282
|
+
var MethodologyDataSchema = zod.z.strictObject({
|
|
3283
|
+
name: MethodologyNameSchema.meta({
|
|
3284
|
+
title: "Methodology Name",
|
|
3285
|
+
description: "Full official name of the methodology"
|
|
3286
|
+
}),
|
|
3287
|
+
short_name: NonEmptyStringSchema.max(50).meta({
|
|
3288
|
+
title: "Methodology Short Name",
|
|
3289
|
+
description: "Abbreviated name for UI display and references",
|
|
3290
|
+
examples: ["BOLD Carbon", "BOLD Recycling"]
|
|
3291
|
+
}),
|
|
3292
|
+
slug: SlugSchema.meta({
|
|
3293
|
+
title: "Methodology Slug",
|
|
3294
|
+
description: "URL-friendly identifier for the methodology",
|
|
3295
|
+
examples: ["bold-carbon-ch4", "bold-recycling"]
|
|
3296
|
+
}),
|
|
3297
|
+
version: SemanticVersionSchema.meta({
|
|
3298
|
+
title: "Methodology Version",
|
|
3299
|
+
description: "Version of the methodology"
|
|
3300
|
+
}),
|
|
3301
|
+
description: zod.z.string().min(50).max(2e3).meta({
|
|
3302
|
+
title: "Methodology Description",
|
|
3303
|
+
description: "Comprehensive methodology description including purpose, scope, and implementation approach"
|
|
3304
|
+
}),
|
|
3305
|
+
revision_date: IsoDateSchema.meta({
|
|
3306
|
+
title: "Revision Date",
|
|
3307
|
+
description: "ISO 8601 date of the last revision to this methodology"
|
|
3308
|
+
}),
|
|
3309
|
+
publication_date: IsoDateSchema.meta({
|
|
3310
|
+
title: "Publication Date",
|
|
3311
|
+
description: "ISO 8601 date of the original publication of this methodology"
|
|
3312
|
+
}),
|
|
3313
|
+
methodology_pdf: IpfsUriSchema.meta({
|
|
3314
|
+
title: "Methodology PDF",
|
|
3315
|
+
description: "IPFS URI pointing to the complete methodology PDF document"
|
|
3316
|
+
}),
|
|
3317
|
+
mass_id_audit_rules: AuditRuleDefinitionsSchema.meta({
|
|
3318
|
+
title: "MassID Audit Rules",
|
|
3319
|
+
description: "Audit rules that must be executed to check MassID compliance with the methodology"
|
|
3320
|
+
})
|
|
3321
|
+
}).meta({
|
|
3322
|
+
title: "Methodology Data",
|
|
3323
|
+
description: "Methodology-specific data including audit rules"
|
|
3324
|
+
});
|
|
3325
|
+
|
|
3326
|
+
// src/methodology/methodology.schema.ts
|
|
3327
|
+
var MethodologySchemaMeta = {
|
|
3328
|
+
title: "Methodology IPFS Record",
|
|
3329
|
+
description: "Methodology metadata stored in IPFS, extending the base schema with methodology data and audit rules",
|
|
3330
|
+
$id: buildSchemaUrl("methodology/methodology.schema.json"),
|
|
3331
|
+
version: getSchemaVersionOrDefault()
|
|
3332
|
+
};
|
|
3333
|
+
var MethodologySchema = BaseIpfsSchema.safeExtend({
|
|
3334
|
+
schema: BaseIpfsSchema.shape.schema.safeExtend({
|
|
3335
|
+
type: zod.z.literal("Methodology").meta({
|
|
3336
|
+
title: "Methodology Schema Type",
|
|
3337
|
+
description: "Methodology schema type"
|
|
3338
|
+
})
|
|
3339
|
+
}),
|
|
3340
|
+
data: MethodologyDataSchema
|
|
3341
|
+
}).meta(MethodologySchemaMeta);
|
|
3342
|
+
var MassIDAuditSummarySchema = zod.z.strictObject({
|
|
3343
|
+
audit_date: IsoDateSchema.meta({
|
|
3344
|
+
title: "Audit Date",
|
|
3345
|
+
description: "Date when the audit was completed"
|
|
3346
|
+
}),
|
|
3347
|
+
methodology_compliance: MethodologyComplianceSchema.meta({
|
|
3348
|
+
title: "Methodology Compliance",
|
|
3349
|
+
description: "Overall outcome of the audit process"
|
|
3350
|
+
}),
|
|
3351
|
+
total_rules_executed: NonNegativeIntegerSchema.meta({
|
|
3352
|
+
title: "Total Rules Executed",
|
|
3353
|
+
description: "Total number of audit rules executed"
|
|
3354
|
+
}),
|
|
3355
|
+
passed_rules: NonNegativeIntegerSchema.meta({
|
|
3356
|
+
title: "Passed Rules Count",
|
|
3357
|
+
description: "Number of rules that passed verification"
|
|
3358
|
+
}),
|
|
3359
|
+
failed_rules: NonNegativeIntegerSchema.meta({
|
|
3360
|
+
title: "Failed Rules Count",
|
|
3361
|
+
description: "Number of rules that failed verification"
|
|
3362
|
+
})
|
|
3363
|
+
}).meta({
|
|
3364
|
+
title: "Audit Summary",
|
|
3365
|
+
description: "Summary of audit execution results"
|
|
3366
|
+
});
|
|
3367
|
+
var MassIDAuditDataSchema = zod.z.strictObject({
|
|
3368
|
+
methodology: MethodologyReferenceSchema,
|
|
3369
|
+
mass_id: MassIDReferenceSchema,
|
|
3370
|
+
gas_id: GasIDReferenceSchema,
|
|
3371
|
+
audit_summary: MassIDAuditSummarySchema,
|
|
3372
|
+
rules_execution_results: AuditRuleExecutionResultsSchema
|
|
3373
|
+
}).meta({
|
|
3374
|
+
title: "MassID Audit Data",
|
|
3375
|
+
description: "Complete data structure for MassID Audit records"
|
|
3376
|
+
});
|
|
3377
|
+
|
|
3378
|
+
// src/mass-id-audit/mass-id-audit.schema.ts
|
|
3379
|
+
var MassIDAuditSchemaMeta = {
|
|
3380
|
+
title: "MassID Audit IPFS Record",
|
|
3381
|
+
description: "MassID audit metadata stored in IPFS, extending the base schema with audit results and references",
|
|
3382
|
+
$id: buildSchemaUrl("mass-id-audit/mass-id-audit.schema.json"),
|
|
3383
|
+
version: getSchemaVersionOrDefault()
|
|
3384
|
+
};
|
|
3385
|
+
var MassIDAuditSchema = BaseIpfsSchema.safeExtend({
|
|
3386
|
+
schema: BaseIpfsSchema.shape.schema.safeExtend({
|
|
3387
|
+
type: zod.z.literal("MassID Audit").meta({
|
|
3388
|
+
title: "MassID Audit Schema Type",
|
|
3389
|
+
description: "MassID Audit schema type"
|
|
3390
|
+
})
|
|
3391
|
+
}),
|
|
3392
|
+
data: MassIDAuditDataSchema
|
|
3393
|
+
}).meta(MassIDAuditSchemaMeta);
|
|
1696
3394
|
|
|
1697
3395
|
exports.AccreditedParticipantSchema = AccreditedParticipantSchema;
|
|
1698
3396
|
exports.AccreditedParticipantsSchema = AccreditedParticipantsSchema;
|
|
1699
3397
|
exports.AdministrativeDivisionSchema = AdministrativeDivisionSchema;
|
|
1700
3398
|
exports.AuditReferenceSchema = AuditReferenceSchema;
|
|
3399
|
+
exports.AuditRuleDefinitionSchema = AuditRuleDefinitionSchema;
|
|
3400
|
+
exports.AuditRuleDefinitionsSchema = AuditRuleDefinitionsSchema;
|
|
3401
|
+
exports.AuditRuleExecutionResultSchema = AuditRuleExecutionResultSchema;
|
|
3402
|
+
exports.AuditRuleExecutionResultsSchema = AuditRuleExecutionResultsSchema;
|
|
1701
3403
|
exports.BaseIpfsSchema = BaseIpfsSchema;
|
|
1702
3404
|
exports.BlockchainChainIdSchema = BlockchainChainIdSchema;
|
|
3405
|
+
exports.BlockchainNetworkNameSchema = BlockchainNetworkNameSchema;
|
|
3406
|
+
exports.CollectionNameSchema = CollectionNameSchema;
|
|
3407
|
+
exports.CollectionSchema = CollectionSchema;
|
|
3408
|
+
exports.CollectionSchemaMeta = CollectionSchemaMeta;
|
|
3409
|
+
exports.CollectionSlugSchema = CollectionSlugSchema;
|
|
1703
3410
|
exports.CoordinatesSchema = CoordinatesSchema;
|
|
1704
3411
|
exports.CountryNameSchema = CountryNameSchema;
|
|
1705
3412
|
exports.CreditAmountAttributeSchema = CreditAmountAttributeSchema;
|
|
1706
3413
|
exports.CreditAmountSchema = CreditAmountSchema;
|
|
3414
|
+
exports.CreditPurchaseReceiptAttributesSchema = CreditPurchaseReceiptAttributesSchema;
|
|
3415
|
+
exports.CreditPurchaseReceiptDataSchema = CreditPurchaseReceiptDataSchema;
|
|
3416
|
+
exports.CreditPurchaseReceiptIpfsSchema = CreditPurchaseReceiptIpfsSchema;
|
|
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;
|
|
3424
|
+
exports.CreditSchema = CreditSchema;
|
|
3425
|
+
exports.CreditSchemaMeta = CreditSchemaMeta;
|
|
3426
|
+
exports.CreditTokenSymbolSchema = CreditTokenSymbolSchema;
|
|
1707
3427
|
exports.CreditTypeAttributeSchema = CreditTypeAttributeSchema;
|
|
1708
3428
|
exports.CreditTypeSchema = CreditTypeSchema;
|
|
1709
3429
|
exports.DistributionNotesSchema = DistributionNotesSchema;
|
|
3430
|
+
exports.EPSILON = EPSILON;
|
|
1710
3431
|
exports.EthereumAddressSchema = EthereumAddressSchema;
|
|
1711
3432
|
exports.ExternalIdSchema = ExternalIdSchema;
|
|
1712
3433
|
exports.ExternalUrlSchema = ExternalUrlSchema;
|
|
@@ -1728,16 +3449,23 @@ exports.LatitudeSchema = LatitudeSchema;
|
|
|
1728
3449
|
exports.LocationSchema = LocationSchema;
|
|
1729
3450
|
exports.LongitudeSchema = LongitudeSchema;
|
|
1730
3451
|
exports.MassIDAttributesSchema = MassIDAttributesSchema;
|
|
3452
|
+
exports.MassIDAuditDataSchema = MassIDAuditDataSchema;
|
|
3453
|
+
exports.MassIDAuditSchema = MassIDAuditSchema;
|
|
3454
|
+
exports.MassIDAuditSchemaMeta = MassIDAuditSchemaMeta;
|
|
1731
3455
|
exports.MassIDDataSchema = MassIDDataSchema;
|
|
1732
3456
|
exports.MassIDIpfsSchema = MassIDIpfsSchema;
|
|
1733
3457
|
exports.MassIDIpfsSchemaMeta = MassIDIpfsSchemaMeta;
|
|
1734
3458
|
exports.MassIDRecyclingDateAttributeSchema = MassIDRecyclingDateAttributeSchema;
|
|
1735
3459
|
exports.MassIDReferenceSchema = MassIDReferenceSchema;
|
|
1736
3460
|
exports.MassIDTokenIdAttributeSchema = MassIDTokenIdAttributeSchema;
|
|
3461
|
+
exports.MassIdReferenceWithContractSchema = MassIdReferenceWithContractSchema;
|
|
1737
3462
|
exports.MethodologyAttributeSchema = MethodologyAttributeSchema;
|
|
1738
3463
|
exports.MethodologyComplianceSchema = MethodologyComplianceSchema;
|
|
3464
|
+
exports.MethodologyDataSchema = MethodologyDataSchema;
|
|
1739
3465
|
exports.MethodologyNameSchema = MethodologyNameSchema;
|
|
1740
3466
|
exports.MethodologyReferenceSchema = MethodologyReferenceSchema;
|
|
3467
|
+
exports.MethodologySchema = MethodologySchema;
|
|
3468
|
+
exports.MethodologySchemaMeta = MethodologySchemaMeta;
|
|
1741
3469
|
exports.MinutesSchema = MinutesSchema;
|
|
1742
3470
|
exports.MunicipalitySchema = MunicipalitySchema;
|
|
1743
3471
|
exports.NftAttributeSchema = NftAttributeSchema;
|
|
@@ -1753,6 +3481,7 @@ exports.ParticipantRoleSchema = ParticipantRoleSchema;
|
|
|
1753
3481
|
exports.ParticipantSchema = ParticipantSchema;
|
|
1754
3482
|
exports.PercentageSchema = PercentageSchema;
|
|
1755
3483
|
exports.PositiveIntegerSchema = PositiveIntegerSchema;
|
|
3484
|
+
exports.ReceiptIdentitySchema = ReceiptIdentitySchema;
|
|
1756
3485
|
exports.RecordEnvironmentSchema = RecordEnvironmentSchema;
|
|
1757
3486
|
exports.RecordRelationshipTypeSchema = RecordRelationshipTypeSchema;
|
|
1758
3487
|
exports.RecordSchemaTypeSchema = RecordSchemaTypeSchema;
|
|
@@ -1765,6 +3494,8 @@ exports.RewardAllocationSchema = RewardAllocationSchema;
|
|
|
1765
3494
|
exports.SemanticVersionSchema = SemanticVersionSchema;
|
|
1766
3495
|
exports.Sha256HashSchema = Sha256HashSchema;
|
|
1767
3496
|
exports.SlugSchema = SlugSchema;
|
|
3497
|
+
exports.SmartContractAddressSchema = SmartContractAddressSchema;
|
|
3498
|
+
exports.SmartContractSchema = SmartContractSchema;
|
|
1768
3499
|
exports.SourceWasteTypeAttributeSchema = SourceWasteTypeAttributeSchema;
|
|
1769
3500
|
exports.SourceWeightAttributeSchema = SourceWeightAttributeSchema;
|
|
1770
3501
|
exports.StringifiedTokenIdSchema = StringifiedTokenIdSchema;
|
|
@@ -1777,9 +3508,20 @@ exports.WasteSubtypeSchema = WasteSubtypeSchema;
|
|
|
1777
3508
|
exports.WasteTypeSchema = WasteTypeSchema;
|
|
1778
3509
|
exports.WeightKgSchema = WeightKgSchema;
|
|
1779
3510
|
exports.buildSchemaUrl = buildSchemaUrl;
|
|
3511
|
+
exports.createAttributeMap = createAttributeMap;
|
|
3512
|
+
exports.createReceiptCertificateSchema = createReceiptCertificateSchema;
|
|
3513
|
+
exports.createReceiptCollectionSchema = createReceiptCollectionSchema;
|
|
3514
|
+
exports.createReceiptCreditSchema = createReceiptCreditSchema;
|
|
1780
3515
|
exports.getSchemaBaseUrl = getSchemaBaseUrl;
|
|
1781
3516
|
exports.getSchemaVersionOrDefault = getSchemaVersionOrDefault;
|
|
3517
|
+
exports.nearlyEqual = nearlyEqual;
|
|
1782
3518
|
exports.uniqueArrayItems = uniqueArrayItems;
|
|
1783
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;
|
|
1784
3526
|
//# sourceMappingURL=index.cjs.map
|
|
1785
3527
|
//# sourceMappingURL=index.cjs.map
|