@xyo-network/payment-plugin 5.1.2 → 5.1.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xyo-network/payment-plugin",
3
- "version": "5.1.2",
3
+ "version": "5.1.4",
4
4
  "description": "Typescript/Javascript Plugins for XYO Platform",
5
5
  "homepage": "https://xyo.network",
6
6
  "bugs": {
@@ -30,37 +30,40 @@
30
30
  "types": "dist/neutral/index.d.ts",
31
31
  "files": [
32
32
  "dist",
33
- "src"
33
+ "src",
34
+ "!**/*.bench.*",
35
+ "!**/*.spec.*",
36
+ "!**/*.test.*"
34
37
  ],
35
38
  "dependencies": {
36
- "@xylabs/array": "~5.0.11",
37
- "@xylabs/assert": "~5.0.11",
38
- "@xylabs/exists": "~5.0.11",
39
- "@xylabs/hex": "~5.0.11",
40
- "@xyo-network/archivist-model": "~5.1.2",
41
- "@xyo-network/diviner-abstract": "~5.1.2",
42
- "@xyo-network/diviner-boundwitness-model": "~5.1.2",
43
- "@xyo-network/diviner-hash-lease": "~5.1.2",
44
- "@xyo-network/diviner-model": "~5.1.2",
45
- "@xyo-network/module-model": "~5.1.2",
46
- "@xyo-network/payload-builder": "~5.1.2",
47
- "@xyo-network/payload-model": "~5.1.2",
48
- "@xyo-network/payment-payload-plugins": "~5.1.2",
49
- "@xyo-network/schema-payload-plugin": "~5.1.2",
50
- "@xyo-network/xns-record-payload-plugins": "~5.1.2",
39
+ "@xylabs/array": "~5.0.33",
40
+ "@xylabs/assert": "~5.0.33",
41
+ "@xylabs/exists": "~5.0.33",
42
+ "@xylabs/hex": "~5.0.33",
43
+ "@xyo-network/archivist-model": "~5.1.23",
44
+ "@xyo-network/diviner-abstract": "~5.1.23",
45
+ "@xyo-network/diviner-boundwitness-model": "~5.1.23",
46
+ "@xyo-network/diviner-hash-lease": "~5.1.23",
47
+ "@xyo-network/diviner-model": "~5.1.23",
48
+ "@xyo-network/module-model": "~5.1.23",
49
+ "@xyo-network/payload-builder": "~5.1.23",
50
+ "@xyo-network/payload-model": "~5.1.23",
51
+ "@xyo-network/payment-payload-plugins": "~5.1.4",
52
+ "@xyo-network/schema-payload-plugin": "~5.1.23",
53
+ "@xyo-network/xns-record-payload-plugins": "~5.1.4",
51
54
  "ajv": "~8.17.1"
52
55
  },
53
56
  "devDependencies": {
54
- "@xylabs/ts-scripts-yarn3": "~7.1.7",
55
- "@xylabs/tsconfig": "~7.1.7",
56
- "@xylabs/vitest-extended": "~5.0.11",
57
- "@xyo-network/archivist-memory": "~5.1.2",
58
- "@xyo-network/boundwitness-builder": "~5.1.2",
59
- "@xyo-network/diviner-boundwitness-memory": "~5.1.2",
60
- "@xyo-network/id-payload-plugin": "~5.1.2",
61
- "@xyo-network/node-memory": "~5.1.2",
62
- "@xyo-network/wallet": "~5.1.2",
63
- "@xyo-network/wallet-model": "~5.1.2",
57
+ "@xylabs/ts-scripts-yarn3": "~7.2.8",
58
+ "@xylabs/tsconfig": "~7.2.8",
59
+ "@xylabs/vitest-extended": "~5.0.33",
60
+ "@xyo-network/archivist-memory": "~5.1.23",
61
+ "@xyo-network/boundwitness-builder": "~5.1.23",
62
+ "@xyo-network/diviner-boundwitness-memory": "~5.1.23",
63
+ "@xyo-network/id-payload-plugin": "~5.1.23",
64
+ "@xyo-network/node-memory": "~5.1.23",
65
+ "@xyo-network/wallet": "~5.1.23",
66
+ "@xyo-network/wallet-model": "~5.1.23",
64
67
  "typescript": "~5.9.2",
65
68
  "vitest": "~3.2.4"
66
69
  },
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=applyCoupons.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"applyCoupons.spec.d.ts","sourceRoot":"","sources":["../../../../../src/Discount/lib/spec/applyCoupons.spec.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=findUnfulfilledConditions.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"findUnfulfilledConditions.spec.d.ts","sourceRoot":"","sources":["../../../../../src/Discount/lib/spec/findUnfulfilledConditions.spec.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- import '@xylabs/vitest-extended';
2
- //# sourceMappingURL=Diviner.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Diviner.spec.d.ts","sourceRoot":"","sources":["../../../../src/Discount/spec/Diviner.spec.ts"],"names":[],"mappings":"AAAA,OAAO,yBAAyB,CAAA"}
@@ -1,2 +0,0 @@
1
- import '@xylabs/vitest-extended';
2
- //# sourceMappingURL=getInvoiceForEscrow.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"getInvoiceForEscrow.spec.d.ts","sourceRoot":"","sources":["../../../../src/Invoice/spec/getInvoiceForEscrow.spec.ts"],"names":[],"mappings":"AAAA,OAAO,yBAAyB,CAAA"}
@@ -1,2 +0,0 @@
1
- import '@xylabs/vitest-extended';
2
- //# sourceMappingURL=Diviner.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Diviner.spec.d.ts","sourceRoot":"","sources":["../../../../src/Subtotal/spec/Diviner.spec.ts"],"names":[],"mappings":"AAAA,OAAO,yBAAyB,CAAA"}
@@ -1,2 +0,0 @@
1
- import '@xylabs/vitest-extended';
2
- //# sourceMappingURL=Diviner.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Diviner.spec.d.ts","sourceRoot":"","sources":["../../../../src/Total/spec/Diviner.spec.ts"],"names":[],"mappings":"AAAA,OAAO,yBAAyB,CAAA"}
@@ -1,104 +0,0 @@
1
- import type { HashLeaseEstimate } from '@xyo-network/diviner-hash-lease'
2
- import { HashLeaseEstimateSchema } from '@xyo-network/diviner-hash-lease'
3
- import type { Coupon } from '@xyo-network/payment-payload-plugins'
4
- import {
5
- DiscountSchema, FixedAmountCouponSchema, FixedPercentageCouponSchema,
6
- FixedPriceCouponSchema,
7
- } from '@xyo-network/payment-payload-plugins'
8
- import {
9
- beforeEach, describe, expect,
10
- it, vi,
11
- } from 'vitest'
12
-
13
- import { applyCoupons } from '../applyCoupons.ts'
14
-
15
- describe('applyCoupons', () => {
16
- const nbf = Date.now()
17
- const exp = Date.now() + 10_000_000
18
- // Coupons
19
- const TEN_DOLLAR_OFF_COUPON: Coupon = {
20
- amount: 10, exp, nbf, schema: FixedAmountCouponSchema, currency: 'USD',
21
- }
22
- const TEN_PERCENT_OFF_COUPON: Coupon = {
23
- percentage: 0.1, exp, nbf, schema: FixedPercentageCouponSchema,
24
- }
25
- const TEN_DOLLAR_ITEM_COUPON: Coupon = {
26
- amount: 10, exp, nbf, schema: FixedPriceCouponSchema, currency: 'USD',
27
- }
28
-
29
- // Appraisals
30
- const HUNDRED_DOLLAR_ESTIMATE: HashLeaseEstimate = {
31
- price: 100, currency: 'USD', exp, nbf, schema: HashLeaseEstimateSchema,
32
- }
33
- const SEVENTY_DOLLAR_ESTIMATE: HashLeaseEstimate = {
34
- price: 70, currency: 'USD', exp, nbf, schema: HashLeaseEstimateSchema,
35
- }
36
- const THIRTY_DOLLAR_ESTIMATE: HashLeaseEstimate = {
37
- price: 30, currency: 'USD', exp, nbf, schema: HashLeaseEstimateSchema,
38
- }
39
-
40
- beforeEach(() => {
41
- vi.clearAllMocks()
42
- })
43
- describe('when coupon is less than total', () => {
44
- const validCoupons: [estimates: HashLeaseEstimate[], coupons: Coupon[], discount: number][] = [
45
- // $100 item with $10 off coupon = $90 total/$10 discount
46
- [[HUNDRED_DOLLAR_ESTIMATE], [TEN_DOLLAR_OFF_COUPON], 10],
47
- // Two items (totalling $100) with $10 off coupon = $90 total/$10 discount
48
- [[SEVENTY_DOLLAR_ESTIMATE, THIRTY_DOLLAR_ESTIMATE], [TEN_DOLLAR_OFF_COUPON], 10],
49
- // $100 item with 10% off coupon = $90 total/$10 discount
50
- [[HUNDRED_DOLLAR_ESTIMATE], [TEN_PERCENT_OFF_COUPON], 10],
51
- // Two items (totalling $100) with 10% off coupon = $90 total/$10 discount
52
- [[SEVENTY_DOLLAR_ESTIMATE, THIRTY_DOLLAR_ESTIMATE], [TEN_PERCENT_OFF_COUPON], 10],
53
- // Two items (totalling $100) with 10% off coupon = $90 total/$10 discount
54
- [[THIRTY_DOLLAR_ESTIMATE, SEVENTY_DOLLAR_ESTIMATE], [TEN_PERCENT_OFF_COUPON], 10],
55
- // $100 item with $10 per item coupon = $10 total/$90 discount
56
- [[HUNDRED_DOLLAR_ESTIMATE], [TEN_DOLLAR_ITEM_COUPON], 90],
57
- // Two items (totalling $100) with $10 per item coupon = $20 total/$80 discount
58
- [[SEVENTY_DOLLAR_ESTIMATE, THIRTY_DOLLAR_ESTIMATE], [TEN_DOLLAR_ITEM_COUPON], 80],
59
- // Four items (totalling $200) with $10 per item coupon = $40 total/$160 discount
60
- [[SEVENTY_DOLLAR_ESTIMATE, THIRTY_DOLLAR_ESTIMATE, SEVENTY_DOLLAR_ESTIMATE, THIRTY_DOLLAR_ESTIMATE], [TEN_DOLLAR_ITEM_COUPON], 160],
61
- ]
62
- it.each(validCoupons)('Applies coupon discount', (estimates, coupons, amount) => {
63
- const results = applyCoupons(estimates, coupons)
64
- expect(results).toEqual({
65
- amount, schema: DiscountSchema, currency: 'USD',
66
- })
67
- })
68
- })
69
- describe('when discount exceeds total', () => {
70
- const discountExceedsTotal: [HashLeaseEstimate[], Coupon[]][] = [
71
- [
72
- [HUNDRED_DOLLAR_ESTIMATE],
73
- [{
74
- amount: 101, exp, nbf, schema: FixedAmountCouponSchema, currency: 'USD',
75
- }]],
76
- [
77
- [HUNDRED_DOLLAR_ESTIMATE],
78
- [{
79
- percentage: 1.1, exp, nbf, schema: FixedPercentageCouponSchema,
80
- }]],
81
- ]
82
- it.each(discountExceedsTotal)('Discounts only to total', (estimates, coupons) => {
83
- const results = applyCoupons(estimates, coupons)
84
- const amount = estimates.reduce((acc, a) => acc + a.price, 0)
85
- expect(results).toEqual({
86
- amount, schema: DiscountSchema, currency: 'USD',
87
- })
88
- })
89
- })
90
- describe('with stackable discounts', () => {
91
- const STACKABLE_TEN_DOLLAR_OFF_COUPON: Coupon = { ...TEN_DOLLAR_OFF_COUPON, stackable: true }
92
- const STACKABLE_TEN_PERCENT_OFF_COUPON: Coupon = { ...TEN_PERCENT_OFF_COUPON, stackable: true }
93
- const validCoupons: [HashLeaseEstimate[], Coupon[], number][] = [
94
- [[HUNDRED_DOLLAR_ESTIMATE], [STACKABLE_TEN_DOLLAR_OFF_COUPON, STACKABLE_TEN_PERCENT_OFF_COUPON], 19],
95
- [[HUNDRED_DOLLAR_ESTIMATE], [STACKABLE_TEN_PERCENT_OFF_COUPON, STACKABLE_TEN_DOLLAR_OFF_COUPON], 19],
96
- ]
97
- it.each(validCoupons)('Applies both discounts', (estimates, coupons, amount) => {
98
- const results = applyCoupons(estimates, coupons)
99
- expect(results).toEqual({
100
- amount, schema: DiscountSchema, currency: 'USD',
101
- })
102
- })
103
- })
104
- })
@@ -1,243 +0,0 @@
1
- import type { Address } from '@xylabs/hex'
2
- import type { HashLeaseEstimate } from '@xyo-network/diviner-hash-lease'
3
- import { HashLeaseEstimateSchema } from '@xyo-network/diviner-hash-lease'
4
- import type { Id } from '@xyo-network/id-payload-plugin'
5
- import { IdSchema } from '@xyo-network/id-payload-plugin'
6
- import { PayloadBuilder } from '@xyo-network/payload-builder'
7
- import type {
8
- BuyerCondition,
9
- Condition, Coupon, EscrowTerms,
10
- } from '@xyo-network/payment-payload-plugins'
11
- import {
12
- createConditionForMaximumAppraisalAmount,
13
- createConditionForMinimumAssetQuantity, createConditionForRequiredBuyer,
14
- EscrowTermsSchema, FixedAmountCouponSchema,
15
- } from '@xyo-network/payment-payload-plugins'
16
- import type { SchemaPayload } from '@xyo-network/schema-payload-plugin'
17
- import { HDWallet } from '@xyo-network/wallet'
18
- import type { WalletInstance } from '@xyo-network/wallet-model'
19
- import {
20
- beforeEach, describe, expect,
21
- it,
22
- } from 'vitest'
23
-
24
- import { findUnfulfilledConditions } from '../findUnfulfilledConditions.ts'
25
-
26
- describe('findUnfulfilledConditions', () => {
27
- const nbf = Date.now()
28
- const exp = Date.now() + 10_000_000
29
- // Coupons
30
- const validCoupon: Coupon = {
31
- amount: 10, exp, nbf, schema: FixedAmountCouponSchema, currency: 'USD',
32
- }
33
-
34
- // Conditions
35
- const CONDITION_REQUIRES_BUYING_TWO: Condition = createConditionForMinimumAssetQuantity(2)
36
- const CONDITION_REQUIRES_APPRAISAL_DOES_NOT_EXCEED_AMOUNT: Condition = createConditionForMaximumAppraisalAmount(20)
37
- const CONDITION_FOR_SPECIFIC_BUYER: BuyerCondition = createConditionForRequiredBuyer('TODO: Replace in beforeAll' as Address)
38
-
39
- const allConditions: SchemaPayload[] = [
40
- CONDITION_REQUIRES_BUYING_TWO,
41
- CONDITION_REQUIRES_APPRAISAL_DOES_NOT_EXCEED_AMOUNT,
42
- CONDITION_FOR_SPECIFIC_BUYER,
43
- ]
44
-
45
- let buyer: WalletInstance
46
- let seller: WalletInstance
47
- const baseTerms: EscrowTerms = {
48
- schema: EscrowTermsSchema, appraisals: [], exp, nbf,
49
- }
50
- const appraisal1: HashLeaseEstimate = {
51
- schema: HashLeaseEstimateSchema, price: 10, currency: 'USD', exp, nbf,
52
- }
53
- const appraisal2: HashLeaseEstimate = {
54
- schema: HashLeaseEstimateSchema, price: 20, currency: 'USD', exp, nbf,
55
- }
56
- const appraisals = [appraisal1, appraisal2]
57
-
58
- const asset1: Id = { schema: IdSchema, salt: nbf.toString() }
59
- const asset2: Id = { schema: IdSchema, salt: exp.toString() }
60
- const assets = [asset1, asset2]
61
-
62
- beforeEach(async () => {
63
- buyer = await HDWallet.random()
64
- seller = await HDWallet.random()
65
-
66
- // Configure base terms
67
- baseTerms.buyer = [buyer.address]
68
- baseTerms.seller = [seller.address]
69
- baseTerms.appraisals = await PayloadBuilder.dataHashes(appraisals)
70
- baseTerms.assets = await PayloadBuilder.dataHashes(assets)
71
-
72
- // Configure condition for specific buyer
73
- CONDITION_FOR_SPECIFIC_BUYER.definition.contains.properties.buyer.items.const = buyer.address
74
- })
75
- describe('when all conditions are fulfilled', () => {
76
- describe('returns empty array', () => {
77
- it.each(allConditions)('for single condition', async (rule) => {
78
- const conditions = [await PayloadBuilder.dataHash(rule)]
79
- const coupon: Coupon = { ...validCoupon, conditions }
80
- const terms: EscrowTerms = { ...baseTerms, discounts: [await PayloadBuilder.dataHash(coupon)] }
81
- const payloads = [terms, coupon, rule, ...assets, ...appraisals]
82
- const results = await findUnfulfilledConditions(coupon, [rule], payloads)
83
- expect(results).toEqual([])
84
- })
85
- it('for multiple conditions', async () => {
86
- const conditions = await PayloadBuilder.dataHashes(allConditions)
87
- const coupon: Coupon = { ...validCoupon, conditions }
88
- const terms: EscrowTerms = { ...baseTerms, discounts: [await PayloadBuilder.dataHash(coupon)] }
89
- const payloads = [terms, coupon, ...allConditions, ...assets, ...appraisals]
90
- const results = await findUnfulfilledConditions(coupon, allConditions, payloads)
91
- expect(results).toEqual([])
92
- })
93
- })
94
- })
95
- describe('when conditions are not fulfilled', () => {
96
- describe('returns all unfulfilled condition hashes', () => {
97
- describe('for maximum appraisal amount', () => {
98
- const rule = CONDITION_REQUIRES_APPRAISAL_DOES_NOT_EXCEED_AMOUNT
99
- it('when escrow terms do not exist', async () => {
100
- const conditions = [await PayloadBuilder.dataHash(rule)]
101
- const coupon: Coupon = { ...validCoupon, conditions }
102
- const payloads = [coupon, rule, ...assets, ...appraisals]
103
- const results = await findUnfulfilledConditions(coupon, [rule], payloads)
104
- expect(results).toEqual(conditions)
105
- })
106
- it('when escrow terms appraisals do not exist', async () => {
107
- const conditions = [await PayloadBuilder.dataHash(rule)]
108
- const coupon: Coupon = { ...validCoupon, conditions }
109
- const terms: EscrowTerms = {
110
- ...baseTerms, discounts: [await PayloadBuilder.dataHash(coupon)], appraisals: undefined,
111
- }
112
- const payloads = [terms, coupon, rule, ...appraisals, ...assets]
113
- const results = await findUnfulfilledConditions(coupon, [rule], payloads)
114
- expect(results).toEqual(conditions)
115
- })
116
- it('when escrow terms appraisals is empty', async () => {
117
- const conditions = [await PayloadBuilder.dataHash(rule)]
118
- const coupon: Coupon = { ...validCoupon, conditions }
119
- const terms: EscrowTerms = {
120
- ...baseTerms, discounts: [await PayloadBuilder.dataHash(coupon)], appraisals: [],
121
- }
122
- const payloads = [terms, coupon, rule, ...appraisals, ...assets]
123
- const results = await findUnfulfilledConditions(coupon, [rule], payloads)
124
- expect(results).toEqual(conditions)
125
- })
126
- it('when appraisals not supplied', async () => {
127
- const conditions = [await PayloadBuilder.dataHash(rule)]
128
- const coupon: Coupon = { ...validCoupon, conditions }
129
- const terms: EscrowTerms = { ...baseTerms, discounts: [await PayloadBuilder.dataHash(coupon)] }
130
- const payloads = [terms, coupon, rule, ...assets]
131
- const results = await findUnfulfilledConditions(coupon, [rule], payloads)
132
- expect(results).toEqual(conditions)
133
- })
134
- it('when supplied appraisal price exceeds the maximum amount', async () => {
135
- const conditions = [await PayloadBuilder.dataHash(rule)]
136
- const coupon: Coupon = { ...validCoupon, conditions }
137
- const assets = [asset1]
138
- const appraisal1: HashLeaseEstimate = {
139
- schema: HashLeaseEstimateSchema, price: 1000, currency: 'USD', exp, nbf,
140
- }
141
- const appraisals = [appraisal1]
142
- const terms: EscrowTerms = {
143
- ...baseTerms,
144
- discounts: [await PayloadBuilder.dataHash(coupon)],
145
- assets: await PayloadBuilder.dataHashes(assets),
146
- appraisals: await PayloadBuilder.dataHashes(appraisals),
147
- }
148
- const payloads = [terms, coupon, rule, ...assets, ...appraisals]
149
- const results = await findUnfulfilledConditions(coupon, [rule], payloads)
150
- expect(results).toEqual(conditions)
151
- })
152
- })
153
- describe('for minimum purchase quantity', () => {
154
- const rule = CONDITION_REQUIRES_BUYING_TWO
155
- it('when escrow terms do not exist', async () => {
156
- const conditions = [await PayloadBuilder.dataHash(rule)]
157
- const coupon: Coupon = { ...validCoupon, conditions }
158
- const payloads = [coupon, rule, ...assets, ...appraisals]
159
- const results = await findUnfulfilledConditions(coupon, [rule], payloads)
160
- expect(results).toEqual(conditions)
161
- })
162
- it('when escrow terms assets do not exist', async () => {
163
- const conditions = [await PayloadBuilder.dataHash(rule)]
164
- const coupon: Coupon = { ...validCoupon, conditions }
165
- const terms: EscrowTerms = {
166
- ...baseTerms, discounts: [await PayloadBuilder.dataHash(coupon)], assets: undefined,
167
- }
168
- const payloads = [terms, coupon, rule, ...appraisals, ...assets]
169
- const results = await findUnfulfilledConditions(coupon, [rule], payloads)
170
- expect(results).toEqual(conditions)
171
- })
172
- it('when escrow terms assets is empty', async () => {
173
- const conditions = [await PayloadBuilder.dataHash(rule)]
174
- const coupon: Coupon = { ...validCoupon, conditions }
175
- const terms: EscrowTerms = {
176
- ...baseTerms, discounts: [await PayloadBuilder.dataHash(coupon)], assets: [],
177
- }
178
- const payloads = [terms, coupon, rule, ...appraisals, ...assets]
179
- const results = await findUnfulfilledConditions(coupon, [rule], payloads)
180
- expect(results).toEqual(conditions)
181
- })
182
- it('when escrow terms assets quantity does not exceed the required amount', async () => {
183
- const conditions = [await PayloadBuilder.dataHash(rule)]
184
- const coupon: Coupon = { ...validCoupon, conditions }
185
- const assets = [asset1]
186
- const terms: EscrowTerms = {
187
- ...baseTerms, discounts: [await PayloadBuilder.dataHash(coupon)], assets: await PayloadBuilder.dataHashes(assets),
188
- }
189
- const payloads = [terms, coupon, rule, ...assets, ...appraisals]
190
- const results = await findUnfulfilledConditions(coupon, [rule], payloads)
191
- expect(results).toEqual(conditions)
192
- })
193
- })
194
- describe('for specific buyer', () => {
195
- const rule = CONDITION_FOR_SPECIFIC_BUYER
196
- it('when escrow terms do not exist', async () => {
197
- const conditions = [await PayloadBuilder.dataHash(rule)]
198
- const coupon: Coupon = { ...validCoupon, conditions }
199
- const payloads = [coupon, rule, ...assets, ...appraisals]
200
- const results = await findUnfulfilledConditions(coupon, [rule], payloads)
201
- expect(results).toEqual(conditions)
202
- })
203
- it('when escrow terms buyer does not exist', async () => {
204
- const conditions = [await PayloadBuilder.dataHash(rule)]
205
- const coupon: Coupon = { ...validCoupon, conditions }
206
- const terms: EscrowTerms = {
207
- ...baseTerms, discounts: [await PayloadBuilder.dataHash(coupon)], buyer: undefined,
208
- }
209
- const payloads = [terms, coupon, rule, ...assets, ...appraisals]
210
- const results = await findUnfulfilledConditions(coupon, [rule], payloads)
211
- expect(results).toEqual(conditions)
212
- })
213
- it('when escrow terms buyers is empty', async () => {
214
- const conditions = [await PayloadBuilder.dataHash(rule)]
215
- const coupon: Coupon = { ...validCoupon, conditions }
216
- const terms: EscrowTerms = {
217
- ...baseTerms, discounts: [await PayloadBuilder.dataHash(coupon)], buyer: [],
218
- }
219
- const payloads = [terms, coupon, rule, ...assets, ...appraisals]
220
- const results = await findUnfulfilledConditions(coupon, [rule], payloads)
221
- expect(results).toEqual(conditions)
222
- })
223
- it('when escrow terms buyer does not contain specified address', async () => {
224
- const buyer = await HDWallet.random()
225
- const conditions = [await PayloadBuilder.dataHash(rule)]
226
- const coupon: Coupon = { ...validCoupon, conditions }
227
- const assets = [asset1]
228
- const appraisals = [appraisal1]
229
- const terms: EscrowTerms = {
230
- ...baseTerms,
231
- discounts: [await PayloadBuilder.dataHash(coupon)],
232
- assets: await PayloadBuilder.dataHashes(assets),
233
- appraisals: await PayloadBuilder.dataHashes(appraisals),
234
- buyer: [buyer.address],
235
- }
236
- const payloads = [terms, coupon, rule, ...assets, ...appraisals]
237
- const results = await findUnfulfilledConditions(coupon, [rule], payloads)
238
- expect(results).toEqual(conditions)
239
- })
240
- })
241
- })
242
- })
243
- })
@@ -1,128 +0,0 @@
1
- import '@xylabs/vitest-extended'
2
-
3
- import { MemoryArchivist } from '@xyo-network/archivist-memory'
4
- import { BoundWitnessBuilder } from '@xyo-network/boundwitness-builder'
5
- import { MemoryBoundWitnessDiviner } from '@xyo-network/diviner-boundwitness-memory'
6
- import type { HashLeaseEstimate } from '@xyo-network/diviner-hash-lease'
7
- import { HashLeaseEstimateSchema } from '@xyo-network/diviner-hash-lease'
8
- import { MemoryNode } from '@xyo-network/node-memory'
9
- import { PayloadBuilder } from '@xyo-network/payload-builder'
10
- import type { Coupon, EscrowTerms } from '@xyo-network/payment-payload-plugins'
11
- import {
12
- DiscountSchema,
13
- EscrowTermsSchema, FixedAmountCouponSchema, FixedPercentageCouponSchema,
14
- isDiscount,
15
- PaymentDiscountDivinerConfigSchema,
16
- } from '@xyo-network/payment-payload-plugins'
17
- import { HDWallet } from '@xyo-network/wallet'
18
- import {
19
- beforeAll, beforeEach, describe, expect, it, vi,
20
- } from 'vitest'
21
-
22
- import { PaymentDiscountDiviner } from '../Diviner.ts'
23
-
24
- describe('PaymentDiscountDiviner', () => {
25
- let sut: PaymentDiscountDiviner
26
- const nbf = Date.now()
27
- const exp = Number.MAX_SAFE_INTEGER
28
- const termsBase: EscrowTerms = {
29
- schema: EscrowTermsSchema, appraisals: [], exp, nbf,
30
- }
31
- const HUNDRED_DOLLAR_ESTIMATE: HashLeaseEstimate = {
32
- price: 100, currency: 'USD', exp, nbf, schema: HashLeaseEstimateSchema,
33
- }
34
- const validCoupons: Coupon[] = [
35
- {
36
- amount: 10, exp, nbf: Date.now(), schema: FixedAmountCouponSchema, currency: 'USD',
37
- },
38
- {
39
- percentage: 0.1, exp, nbf: Date.now(), schema: FixedPercentageCouponSchema,
40
- },
41
- ]
42
- const unsignedCoupons: Coupon[] = [
43
- {
44
- amount: 10, exp: Number.MAX_SAFE_INTEGER, nbf: 0, schema: FixedAmountCouponSchema, currency: 'USD',
45
- },
46
- {
47
- percentage: 0.1, exp: Number.MAX_SAFE_INTEGER, nbf: 0, schema: FixedPercentageCouponSchema,
48
- },
49
- ]
50
- beforeAll(async () => {
51
- termsBase.appraisals?.push(await PayloadBuilder.hash(HUNDRED_DOLLAR_ESTIMATE))
52
- const node = await MemoryNode.create({ account: 'random' })
53
- const archivist = await MemoryArchivist.create({ account: 'random' })
54
- const signer = await HDWallet.random()
55
- // Sign the valid coupons and insert them into the archivist
56
- for (const coupon of validCoupons) {
57
- const [bw, payloads] = await new BoundWitnessBuilder().signer(signer).payload(coupon).build()
58
- await archivist.insert([bw, ...payloads])
59
- }
60
- // Insert (but do not sign) the unsigned coupons into the archivist
61
- await archivist.insert(unsignedCoupons)
62
- const boundWitnessDiviner = await MemoryBoundWitnessDiviner.create({
63
- account: 'random',
64
- config: {
65
- archivist: archivist.address,
66
- schema: MemoryBoundWitnessDiviner.defaultConfigSchema,
67
- },
68
- })
69
- sut = await PaymentDiscountDiviner.create({
70
- account: 'random',
71
- config: {
72
- archivist: archivist.address,
73
- boundWitnessDiviner: boundWitnessDiviner.address,
74
- couponAuthorities: [signer.address],
75
- schema: PaymentDiscountDivinerConfigSchema,
76
- },
77
- })
78
- const modules = [archivist, boundWitnessDiviner, sut]
79
- for (const mod of modules) {
80
- await node.register(mod)
81
- await node.attach(mod.address, false)
82
- }
83
- })
84
- beforeEach(() => {
85
- vi.clearAllMocks()
86
- })
87
- describe('with valid coupon', () => {
88
- it.each(validCoupons)('Applies coupon', async (coupon) => {
89
- const terms = { ...termsBase, discounts: [await PayloadBuilder.dataHash(coupon)] }
90
- const results = await sut.divine([terms, HUNDRED_DOLLAR_ESTIMATE, coupon])
91
- expect(results).toBeArrayOfSize(1)
92
- const result = results.find(isDiscount)
93
- expect(result).toBeDefined()
94
- expect(result).toMatchObject({ amount: 10, schema: DiscountSchema })
95
- })
96
- })
97
- describe('with invalid coupon', () => {
98
- it.each(unsignedCoupons)('Does not apply coupons', async (coupon) => {
99
- const terms = { ...termsBase, discounts: [await PayloadBuilder.dataHash(coupon)] }
100
- const results = await sut.divine([terms, HUNDRED_DOLLAR_ESTIMATE, coupon])
101
- expect(results).toBeArrayOfSize(1)
102
- const result = results.find(isDiscount)
103
- expect(result).toBeDefined()
104
- expect(result).toMatchObject({ amount: 0, schema: DiscountSchema })
105
- })
106
- })
107
- describe('with expired coupon', () => {
108
- const now = Date.now()
109
- const expiredCoupons: Coupon[] = [
110
- // In past
111
- {
112
- amount: 10, exp: now, nbf: 0, schema: FixedAmountCouponSchema, currency: 'USD',
113
- },
114
- // In future
115
- {
116
- percentage: 0.1, exp: now + 100_000_000, nbf: now + 10_000_000, schema: FixedPercentageCouponSchema,
117
- },
118
- ]
119
- it.each(expiredCoupons)('Does not apply coupons', async (coupon) => {
120
- const terms = { ...termsBase, discounts: [await PayloadBuilder.dataHash(coupon)] }
121
- const results = await sut.divine([terms, HUNDRED_DOLLAR_ESTIMATE, coupon])
122
- expect(results).toBeArrayOfSize(1)
123
- const result = results.find(isDiscount)
124
- expect(result).toBeDefined()
125
- expect(result).toMatchObject({ amount: 0, schema: DiscountSchema })
126
- })
127
- })
128
- })
@@ -1,94 +0,0 @@
1
- import '@xylabs/vitest-extended'
2
-
3
- import { assertEx } from '@xylabs/assert'
4
- import { MemoryArchivist } from '@xyo-network/archivist-memory'
5
- import { MemoryBoundWitnessDiviner } from '@xyo-network/diviner-boundwitness-memory'
6
- import { BoundWitnessDivinerConfigSchema } from '@xyo-network/diviner-boundwitness-model'
7
- import type { HashLeaseEstimate } from '@xyo-network/diviner-hash-lease'
8
- import { HashLeaseEstimateSchema } from '@xyo-network/diviner-hash-lease'
9
- import { MemoryNode } from '@xyo-network/node-memory'
10
- import { PayloadBuilder } from '@xyo-network/payload-builder'
11
- import type { EscrowTerms } from '@xyo-network/payment-payload-plugins'
12
- import { EscrowTermsSchema, NO_DISCOUNT } from '@xyo-network/payment-payload-plugins'
13
- import {
14
- beforeAll,
15
- describe, expect, it,
16
- } from 'vitest'
17
-
18
- import { PaymentDiscountDiviner } from '../../Discount/index.ts'
19
- import { PaymentSubtotalDiviner } from '../../Subtotal/index.ts'
20
- import { PaymentTotalDiviner } from '../../Total/index.ts'
21
- import { getInvoiceForEscrow } from '../getInvoiceForEscrow.ts'
22
-
23
- describe('getInvoiceForEscrow', () => {
24
- let node: MemoryNode
25
- let paymentTotalDiviner: PaymentTotalDiviner
26
- beforeAll(async () => {
27
- node = await MemoryNode.create({ account: 'random' })
28
- const discountsArchivist = await MemoryArchivist.create({ account: 'random' })
29
- const discountsBoundWitnessDiviner = await MemoryBoundWitnessDiviner.create({
30
- account: 'random',
31
- config: { archivist: discountsArchivist.address, schema: BoundWitnessDivinerConfigSchema },
32
- })
33
- const paymentDiscountDiviner = await PaymentDiscountDiviner.create({
34
- account: 'random',
35
- config: {
36
- archivist: discountsArchivist.address,
37
- boundWitnessDiviner: discountsBoundWitnessDiviner.address,
38
- schema: PaymentDiscountDiviner.defaultConfigSchema,
39
- },
40
- })
41
- const paymentSubtotalDiviner = await PaymentSubtotalDiviner.create({ account: 'random' })
42
- paymentTotalDiviner = await PaymentTotalDiviner.create({
43
- account: 'random',
44
- config: {
45
- paymentDiscountDiviner: paymentDiscountDiviner.address,
46
- paymentSubtotalDiviner: paymentSubtotalDiviner.address,
47
- schema: PaymentTotalDiviner.defaultConfigSchema,
48
- },
49
- })
50
- const modules = [
51
- discountsArchivist,
52
- discountsBoundWitnessDiviner,
53
- paymentDiscountDiviner,
54
- paymentSubtotalDiviner,
55
- paymentTotalDiviner]
56
- for (const module of modules) {
57
- await node.register(module)
58
- await node.attach(module.address, true)
59
- }
60
- })
61
- describe('with no discount', () => {
62
- it('should return invoice values', async () => {
63
- const nbf = Date.now()
64
- const exp = nbf + 1000 * 60 * 10
65
- const appraisal: HashLeaseEstimate = {
66
- price: 10, currency: 'USD', schema: HashLeaseEstimateSchema, exp, nbf,
67
- }
68
- const appraisalHash = await PayloadBuilder.dataHash(appraisal)
69
- const terms: EscrowTerms = {
70
- schema: EscrowTermsSchema, appraisals: [appraisalHash], exp, nbf,
71
- }
72
- const dataHashMap = await PayloadBuilder.toDataHashMap([appraisal])
73
- const result = await getInvoiceForEscrow(terms, dataHashMap, paymentTotalDiviner)
74
- expect(result).toBeArray()
75
- expect(result?.length).toBeGreaterThan(0)
76
- const invoice = assertEx(result)
77
- const [subtotal, total, payment, discount] = invoice
78
- expect(subtotal).toBeDefined()
79
- expect(subtotal.amount).toBeNumber()
80
- expect(subtotal.amount).toBe(appraisal.price)
81
- expect(subtotal.currency).toBe('USD')
82
- expect(total).toBeDefined()
83
- expect(total.amount).toBeNumber()
84
- expect(total.amount).toBe(subtotal.amount)
85
- expect(total.currency).toBe('USD')
86
- expect(payment).toBeDefined()
87
- expect(payment.amount).toBeNumber()
88
- expect(payment.amount).toBe(total.amount)
89
- expect(payment.currency).toBe('USD')
90
- expect(discount).toBeDefined()
91
- expect(discount).toMatchObject(NO_DISCOUNT)
92
- })
93
- })
94
- })
@@ -1,113 +0,0 @@
1
- import '@xylabs/vitest-extended'
2
-
3
- import type { HashLeaseEstimate } from '@xyo-network/diviner-hash-lease'
4
- import { HashLeaseEstimateSchema } from '@xyo-network/diviner-hash-lease'
5
- import { PayloadBuilder } from '@xyo-network/payload-builder'
6
- import type { EscrowTerms } from '@xyo-network/payment-payload-plugins'
7
- import {
8
- EscrowTermsSchema,
9
- isSubtotal,
10
- SubtotalSchema,
11
- } from '@xyo-network/payment-payload-plugins'
12
- import {
13
- beforeAll, beforeEach, describe, expect,
14
- it, vi,
15
- } from 'vitest'
16
-
17
- import { PaymentSubtotalDiviner } from '../Diviner.ts'
18
-
19
- describe('PaymentSubtotalDiviner', () => {
20
- let sut: PaymentSubtotalDiviner
21
- const nbf = Date.now()
22
- const exp = Number.MAX_SAFE_INTEGER
23
- const termsBase: EscrowTerms = {
24
- schema: EscrowTermsSchema, appraisals: [], exp, nbf,
25
- }
26
- const cases: [estimates: HashLeaseEstimate[], subtotal: number][] = [
27
- [
28
- [
29
- {
30
- schema: HashLeaseEstimateSchema, price: 1, currency: 'USD', exp, nbf,
31
- },
32
- {
33
- schema: HashLeaseEstimateSchema, price: 10, currency: 'USD', exp, nbf,
34
- },
35
- ], 11],
36
- [
37
- [
38
- {
39
- schema: HashLeaseEstimateSchema, price: 10, currency: 'USD', exp, nbf,
40
- },
41
- {
42
- schema: HashLeaseEstimateSchema, price: 20, currency: 'USD', exp, nbf,
43
- },
44
- ], 30],
45
- [
46
- [
47
- {
48
- schema: HashLeaseEstimateSchema, price: 100, currency: 'USD', exp, nbf,
49
- },
50
- {
51
- schema: HashLeaseEstimateSchema, price: 100, currency: 'USD', exp, nbf,
52
- },
53
- {
54
- schema: HashLeaseEstimateSchema, price: 100, currency: 'USD', exp, nbf,
55
- },
56
- ], 300],
57
- ]
58
- beforeEach(() => {
59
- vi.clearAllMocks()
60
- })
61
- beforeAll(async () => {
62
- sut = await PaymentSubtotalDiviner.create({ account: 'random' })
63
- })
64
- describe('with escrow terms containing valid appraisals', () => {
65
- it.each(cases)('calculates the subtotal of all the appraisals', async (appraisals, total) => {
66
- const appraisalHashes = await PayloadBuilder.dataHashes(appraisals)
67
- const terms: EscrowTerms = { ...termsBase, appraisals: appraisalHashes }
68
- const results = await sut.divine([terms, ...appraisals])
69
- expect(results).toBeArrayOfSize(1)
70
- const result = results.find(isSubtotal)
71
- expect(result).toBeDefined()
72
- expect(result).toMatchObject({ amount: total, schema: SubtotalSchema })
73
- expect(result?.$sources).toEqual([await PayloadBuilder.dataHash(terms), ...appraisalHashes])
74
- })
75
- })
76
- describe('with escrow terms containing invalid appraisals', () => {
77
- describe('when containing negative values in appraisals', () => {
78
- it('calculates the subtotal of all the appraisals', async () => {
79
- const appraisals = [{
80
- schema: HashLeaseEstimateSchema, price: -1, currency: 'USD', exp, nbf,
81
- }]
82
- const appraisalHashes = await PayloadBuilder.dataHashes(appraisals)
83
- const terms: EscrowTerms = { ...termsBase, appraisals: appraisalHashes }
84
- const results = await sut.divine([terms, ...appraisals])
85
- expect(results).toBeArrayOfSize(0)
86
- })
87
- })
88
- describe('when containing non-numeric values in appraisals', () => {
89
- it('calculates the subtotal of all the appraisals', async () => {
90
- const appraisals = [{
91
- schema: HashLeaseEstimateSchema, price: 'three dollars', currency: 'USD', exp, nbf,
92
- }]
93
- const appraisalHashes = await PayloadBuilder.dataHashes(appraisals)
94
- const terms: EscrowTerms = { ...termsBase, appraisals: appraisalHashes }
95
- const results = await sut.divine([terms, ...appraisals])
96
- expect(results).toBeArrayOfSize(0)
97
- })
98
- })
99
- describe('when containing mixed currencies in appraisals', () => {
100
- it('calculates the subtotal of all the appraisals', async () => {
101
- const appraisals = [{
102
- schema: HashLeaseEstimateSchema, price: 1, currency: 'USD', exp, nbf,
103
- }, {
104
- schema: HashLeaseEstimateSchema, price: 1, currency: 'EUR', exp, nbf,
105
- }]
106
- const appraisalHashes = await PayloadBuilder.dataHashes(appraisals)
107
- const terms: EscrowTerms = { ...termsBase, appraisals: appraisalHashes }
108
- const results = await sut.divine([terms, ...appraisals])
109
- expect(results).toBeArrayOfSize(0)
110
- })
111
- })
112
- })
113
- })
@@ -1,173 +0,0 @@
1
- import '@xylabs/vitest-extended'
2
-
3
- import { MemoryArchivist } from '@xyo-network/archivist-memory'
4
- import { BoundWitnessBuilder } from '@xyo-network/boundwitness-builder'
5
- import { MemoryBoundWitnessDiviner } from '@xyo-network/diviner-boundwitness-memory'
6
- import type { HashLeaseEstimate } from '@xyo-network/diviner-hash-lease'
7
- import { HashLeaseEstimateSchema } from '@xyo-network/diviner-hash-lease'
8
- import { MemoryNode } from '@xyo-network/node-memory'
9
- import { PayloadBuilder } from '@xyo-network/payload-builder'
10
- import type { Coupon, EscrowTerms } from '@xyo-network/payment-payload-plugins'
11
- import {
12
- EscrowTermsSchema,
13
- FixedAmountCouponSchema, FixedPercentageCouponSchema, isTotal,
14
- TotalSchema,
15
- } from '@xyo-network/payment-payload-plugins'
16
- import { HDWallet } from '@xyo-network/wallet'
17
- import {
18
- beforeAll, beforeEach, describe, expect,
19
- it, vi,
20
- } from 'vitest'
21
-
22
- import { PaymentDiscountDiviner } from '../../Discount/index.ts'
23
- import { PaymentSubtotalDiviner } from '../../Subtotal/index.ts'
24
- import { PaymentTotalDiviner } from '../Diviner.ts'
25
-
26
- describe('PaymentTotalDiviner', () => {
27
- let sut: PaymentTotalDiviner
28
- const nbf = Date.now()
29
- const exp = nbf + 1000 * 60 * 10
30
- const termsBase: EscrowTerms = {
31
- schema: EscrowTermsSchema, appraisals: [], exp, nbf,
32
- }
33
- const cases: [estimates: HashLeaseEstimate[], subtotal: number][] = [
34
- [
35
- [
36
- {
37
- schema: HashLeaseEstimateSchema, price: 1, currency: 'USD', exp, nbf,
38
- },
39
- {
40
- schema: HashLeaseEstimateSchema, price: 10, currency: 'USD', exp, nbf,
41
- },
42
- ], 11],
43
- [
44
- [
45
- {
46
- schema: HashLeaseEstimateSchema, price: 10, currency: 'USD', exp, nbf,
47
- },
48
- {
49
- schema: HashLeaseEstimateSchema, price: 20, currency: 'USD', exp, nbf,
50
- },
51
- ], 30],
52
- [
53
- [
54
- {
55
- schema: HashLeaseEstimateSchema, price: 100, currency: 'USD', exp, nbf,
56
- },
57
- {
58
- schema: HashLeaseEstimateSchema, price: 100, currency: 'USD', exp, nbf,
59
- },
60
- {
61
- schema: HashLeaseEstimateSchema, price: 100, currency: 'USD', exp, nbf,
62
- },
63
- ], 300],
64
- ]
65
- const validCoupons: Coupon[] = [
66
- {
67
- amount: 10, exp, nbf: Date.now(), schema: FixedAmountCouponSchema, currency: 'USD',
68
- },
69
- {
70
- percentage: 0.1, exp, nbf: Date.now(), schema: FixedPercentageCouponSchema,
71
- },
72
- ]
73
- const unsignedCoupons: Coupon[] = [
74
- {
75
- amount: 10, exp: Number.MAX_SAFE_INTEGER, nbf: 0, schema: FixedAmountCouponSchema, currency: 'USD',
76
- },
77
- {
78
- percentage: 0.1, exp: Number.MAX_SAFE_INTEGER, nbf: 0, schema: FixedPercentageCouponSchema,
79
- },
80
- ]
81
- beforeEach(() => {
82
- vi.clearAllMocks()
83
- })
84
- beforeAll(async () => {
85
- const node = await MemoryNode.create({ account: 'random' })
86
- expect(node).toBeDefined()
87
- const paymentSubtotalDiviner = await PaymentSubtotalDiviner.create({ account: 'random' })
88
- const discountsArchivist = await MemoryArchivist.create({ account: 'random' })
89
- const signer = await HDWallet.random()
90
- // Sign the valid coupons and insert them into the archivist
91
- for (const coupon of validCoupons) {
92
- const [bw, payloads] = await new BoundWitnessBuilder().signer(signer).payload(coupon).build()
93
- await discountsArchivist.insert([bw, ...payloads])
94
- }
95
- // Insert (but do not sign) the unsigned coupons into the archivist
96
- await discountsArchivist.insert(unsignedCoupons)
97
- const discountsBoundWitnessDiviner = await MemoryBoundWitnessDiviner.create({
98
- account: 'random',
99
- config: {
100
- archivist: discountsArchivist.address,
101
- schema: MemoryBoundWitnessDiviner.defaultConfigSchema,
102
- },
103
- })
104
- const discountDiviner = await PaymentDiscountDiviner.create({
105
- account: 'random',
106
- config: {
107
- archivist: discountsArchivist.address,
108
- boundWitnessDiviner: discountsBoundWitnessDiviner.address,
109
- couponAuthorities: [signer.address],
110
- schema: PaymentDiscountDiviner.defaultConfigSchema,
111
- },
112
- })
113
- sut = await PaymentTotalDiviner.create({
114
- account: 'random',
115
- config: {
116
- paymentDiscountDiviner: discountDiviner.address,
117
- paymentSubtotalDiviner: paymentSubtotalDiviner.address,
118
- schema: PaymentTotalDiviner.defaultConfigSchema,
119
- },
120
- })
121
-
122
- const modules = [paymentSubtotalDiviner, discountsArchivist, discountsBoundWitnessDiviner, discountDiviner, sut]
123
- for (const mod of modules) {
124
- await node.register(mod)
125
- await node.attach(mod.address, true)
126
- }
127
- })
128
- describe('with valid escrow', () => {
129
- describe('with no discounts', () => {
130
- it.each(cases)('calculates total', async (appraisals, total) => {
131
- const appraisalHashes = await PayloadBuilder.dataHashes(appraisals)
132
- const terms: EscrowTerms = { ...termsBase, appraisals: appraisalHashes }
133
- const results = await sut.divine([terms, ...appraisals])
134
- expect(results).toBeArrayOfSize(3)
135
- const result = results.find(isTotal)
136
- expect(result).toBeDefined()
137
- expect(result).toMatchObject({ amount: total, schema: TotalSchema })
138
- })
139
- })
140
- describe('with valid discounts', () => {
141
- describe.each(cases)('calculates total', (appraisals, total) => {
142
- it.each(validCoupons)('applying coupon discount to total', async (coupon) => {
143
- const discounts = await PayloadBuilder.dataHashes([coupon])
144
- const appraisalHashes = await PayloadBuilder.dataHashes(appraisals)
145
- const terms: EscrowTerms = {
146
- ...termsBase, appraisals: appraisalHashes, discounts,
147
- }
148
- const results = await sut.divine([terms, ...appraisals, coupon])
149
- expect(results).toBeArrayOfSize(3)
150
- const result = results.find(isTotal)
151
- expect(result).toBeDefined()
152
- expect(result?.amount).toBeLessThan(total)
153
- })
154
- })
155
- })
156
- describe('with invalid discounts', () => {
157
- describe.each(cases)('calculates total', (appraisals, total) => {
158
- it.each(unsignedCoupons)('without applying coupon discount to total', async (coupon) => {
159
- const discounts = await PayloadBuilder.dataHashes([coupon])
160
- const appraisalHashes = await PayloadBuilder.dataHashes(appraisals)
161
- const terms: EscrowTerms = {
162
- ...termsBase, appraisals: appraisalHashes, discounts,
163
- }
164
- const results = await sut.divine([terms, ...appraisals, coupon])
165
- expect(results).toBeArrayOfSize(3)
166
- const result = results.find(isTotal)
167
- expect(result).toBeDefined()
168
- expect(result).toMatchObject({ amount: total, schema: TotalSchema })
169
- })
170
- })
171
- })
172
- })
173
- })