@xyo-network/payment-plugin 5.3.1 → 5.3.3

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.
@@ -1,4 +1,4 @@
1
- import { Address, Hash } from '@xylabs/hex';
1
+ import { Address, Hash } from '@xylabs/sdk-js';
2
2
  import { ArchivistInstance } from '@xyo-network/archivist-model';
3
3
  import { AbstractDiviner } from '@xyo-network/diviner-abstract';
4
4
  import { HashLeaseEstimate } from '@xyo-network/diviner-hash-lease';
@@ -1 +1 @@
1
- {"version":3,"file":"Diviner.d.ts","sourceRoot":"","sources":["../../../src/Discount/Diviner.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,iBAAiB,EAAuB,MAAM,8BAA8B,CAAA;AACrF,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAE/D,OAAO,EACL,iBAAiB,EAElB,MAAM,iCAAiC,CAAA;AACxC,OAAO,EACc,eAAe,EAAE,sBAAsB,EAC3D,MAAM,4BAA4B,CAAA;AAGnC,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AACpD,OAAO,EAGL,SAAS,EACT,MAAM,EACN,QAAQ,EACR,WAAW,EACqD,4BAA4B,EAC7F,MAAM,sCAAsC,CAAA;AAU7C,MAAM,MAAM,+BAA+B,GAAG,WAAW,GAAG,MAAM,GAAG,iBAAiB,GAAG,OAAO,CAAA;AAEhG,qBACa,sBAAsB,CACjC,OAAO,SAAS,4BAA4B,GAAG,4BAA4B,EAC3E,GAAG,SAAS,+BAA+B,GAAG,+BAA+B,EAC7E,IAAI,SAAS,QAAQ,GAAG,QAAQ,EAChC,UAAU,SAAS,sBAAsB,CAAC,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,sBAAsB,CAChH,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,EACnC,GAAG,EACH,IAAI,CACL,CACD,SAAQ,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,CAAC;IACvD,gBAAyB,aAAa;;SAAuC;IAC7E,gBAAyB,mBAAmB;;MAAqC;IAEjF,SAAS,KAAK,iBAAiB,IAAI,OAAO,EAAE,CAE3C;cAEe,aAAa,CAAC,QAAQ,GAAE,GAAG,EAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAuCpE;;;;;OAKG;cACa,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;cAqBpD,qBAAqB,IAAI,OAAO,CAAC,iBAAiB,CAAC;cAMnD,+BAA+B,IAAI,OAAO,CAAC,eAAe,CAAC;IAM3E;;;;;OAKG;IACH,SAAS,CAAC,mBAAmB,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,iBAAiB,EAAE;IAMtG;;;;;;OAMG;cACa,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IAiDxH,SAAS,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;CAInD"}
1
+ {"version":3,"file":"Diviner.d.ts","sourceRoot":"","sources":["../../../src/Discount/Diviner.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EAA8B,IAAI,EAC1C,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,iBAAiB,EAAuB,MAAM,8BAA8B,CAAA;AACrF,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAE/D,OAAO,EACL,iBAAiB,EAElB,MAAM,iCAAiC,CAAA;AACxC,OAAO,EACc,eAAe,EAAE,sBAAsB,EAC3D,MAAM,4BAA4B,CAAA;AAEnC,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AACpD,OAAO,EAGL,SAAS,EACT,MAAM,EACN,QAAQ,EACR,WAAW,EACqD,4BAA4B,EAC7F,MAAM,sCAAsC,CAAA;AAW7C,MAAM,MAAM,+BAA+B,GAAG,WAAW,GAAG,MAAM,GAAG,iBAAiB,GAAG,OAAO,CAAA;AAEhG,qBACa,sBAAsB,CACjC,OAAO,SAAS,4BAA4B,GAAG,4BAA4B,EAC3E,GAAG,SAAS,+BAA+B,GAAG,+BAA+B,EAC7E,IAAI,SAAS,QAAQ,GAAG,QAAQ,EAChC,UAAU,SAAS,sBAAsB,CAAC,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,sBAAsB,CAChH,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,EACnC,GAAG,EACH,IAAI,CACL,CACD,SAAQ,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,CAAC;IACvD,gBAAyB,aAAa;;SAAuC;IAC7E,gBAAyB,mBAAmB;;MAAqC;IAEjF,SAAS,KAAK,iBAAiB,IAAI,OAAO,EAAE,CAE3C;cAEe,aAAa,CAAC,QAAQ,GAAE,GAAG,EAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAuCpE;;;;;OAKG;cACa,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;cAqBpD,qBAAqB,IAAI,OAAO,CAAC,iBAAiB,CAAC;cAMnD,+BAA+B,IAAI,OAAO,CAAC,eAAe,CAAC;IAM3E;;;;;OAKG;IACH,SAAS,CAAC,mBAAmB,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,iBAAiB,EAAE;IAMtG;;;;;;OAMG;cACa,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IAiDxH,SAAS,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;CAInD"}
@@ -1 +1 @@
1
- {"version":3,"file":"applyCoupons.d.ts","sourceRoot":"","sources":["../../../../src/Discount/lib/applyCoupons.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACxE,OAAO,KAAK,EAEV,MAAM,EAAE,QAAQ,EAGjB,MAAM,sCAAsC,CAAA;AAQ7C,eAAO,MAAM,YAAY,GAAI,YAAY,iBAAiB,EAAE,EAAE,SAAS,MAAM,EAAE,KAAG,QAiDjF,CAAA"}
1
+ {"version":3,"file":"applyCoupons.d.ts","sourceRoot":"","sources":["../../../../src/Discount/lib/applyCoupons.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACxE,OAAO,KAAK,EAEV,MAAM,EAAE,QAAQ,EAGjB,MAAM,sCAAsC,CAAA;AAQ7C,eAAO,MAAM,YAAY,GAAI,YAAY,iBAAiB,EAAE,EAAE,SAAS,MAAM,EAAE,KAAG,QAiDjF,CAAA"}
@@ -1,4 +1,4 @@
1
- import type { Hash } from '@xylabs/hex';
1
+ import type { Hash } from '@xylabs/sdk-js';
2
2
  import type { Payload } from '@xyo-network/payload-model';
3
3
  import type { Condition, Coupon } from '@xyo-network/payment-payload-plugins';
4
4
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"findUnfulfilledConditions.d.ts","sourceRoot":"","sources":["../../../../src/Discount/lib/findUnfulfilledConditions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAEvC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,sCAAsC,CAAA;AAW7E;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,GAAU,QAAQ,MAAM,EAAE,aAAY,SAAS,EAAO,EAAE,WAAU,OAAO,EAAO,KAAG,OAAO,CAAC,OAAO,CACvD,CAAA;AAE9E;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,GAAU,QAAQ,MAAM,EAAE,aAAY,SAAS,EAAO,EAAE,WAAU,OAAO,EAAO,KAAG,OAAO,CAAC,IAAI,EAAE,CAwCtI,CAAA"}
1
+ {"version":3,"file":"findUnfulfilledConditions.d.ts","sourceRoot":"","sources":["../../../../src/Discount/lib/findUnfulfilledConditions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,sCAAsC,CAAA;AAY7E;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,GAAU,QAAQ,MAAM,EAAE,aAAY,SAAS,EAAO,EAAE,WAAU,OAAO,EAAO,KAAG,OAAO,CAAC,OAAO,CACvD,CAAA;AAE9E;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,GAAU,QAAQ,MAAM,EAAE,aAAY,SAAS,EAAO,EAAE,WAAU,OAAO,EAAO,KAAG,OAAO,CAAC,IAAI,EAAE,CAwCtI,CAAA"}
@@ -1,4 +1,4 @@
1
- import type { Hash } from '@xylabs/hex';
1
+ import type { Hash } from '@xylabs/sdk-js';
2
2
  import type { DivinerInstance } from '@xyo-network/diviner-model';
3
3
  import type { Payload } from '@xyo-network/payload-model';
4
4
  import type { EscrowTerms, Invoice } from '@xyo-network/payment-payload-plugins';
@@ -1 +1 @@
1
- {"version":3,"file":"getInvoiceForEscrow.d.ts","sourceRoot":"","sources":["../../../src/Invoice/getInvoiceForEscrow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAEjE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AACzD,OAAO,KAAK,EACA,WAAW,EAAE,OAAO,EAE/B,MAAM,sCAAsC,CAAA;AAK7C;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAC9B,OAAO,WAAW,EAClB,aAAa,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,EAClC,qBAAqB,eAAe,KACnC,OAAO,CAAC,OAAO,GAAG,SAAS,CAc7B,CAAA"}
1
+ {"version":3,"file":"getInvoiceForEscrow.d.ts","sourceRoot":"","sources":["../../../src/Invoice/getInvoiceForEscrow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AACjE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AACzD,OAAO,KAAK,EACA,WAAW,EAAE,OAAO,EAE/B,MAAM,sCAAsC,CAAA;AAM7C;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAC9B,OAAO,WAAW,EAClB,aAAa,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,EAClC,qBAAqB,eAAe,KACnC,OAAO,CAAC,OAAO,GAAG,SAAS,CAc7B,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"Diviner.d.ts","sourceRoot":"","sources":["../../../src/Subtotal/Diviner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,iBAAiB,EAAuB,MAAM,iCAAiC,CAAA;AACxF,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAA;AAGpF,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AACpD,OAAO,EACL,WAAW,EAAqD,4BAA4B,EAAE,QAAQ,EACvG,MAAM,sCAAsC,CAAA;AAQ7C;;GAEG;AACH,MAAM,MAAM,+BAA+B,GAAG,WAAW,GAAG,iBAAiB,GAAG,OAAO,CAAA;AAEvF,qBACa,sBAAsB,CACjC,OAAO,SAAS,4BAA4B,GAAG,4BAA4B,EAC3E,GAAG,SAAS,+BAA+B,GAAG,+BAA+B,EAC7E,IAAI,SAAS,QAAQ,GAAG,QAAQ,EAChC,UAAU,SAAS,sBAAsB,CAAC,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,sBAAsB,CAChH,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,EACnC,GAAG,EACH,IAAI,CACL,CACD,SAAQ,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,CAAC;IACvD,gBAAyB,aAAa;;SAAuC;IAC7E,gBAAyB,mBAAmB;;MAAqC;cAEjE,aAAa,CAAC,QAAQ,GAAE,GAAG,EAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;CAwBrE"}
1
+ {"version":3,"file":"Diviner.d.ts","sourceRoot":"","sources":["../../../src/Subtotal/Diviner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,iBAAiB,EAAuB,MAAM,iCAAiC,CAAA;AACxF,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAA;AAEpF,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AACpD,OAAO,EACL,WAAW,EAAqD,4BAA4B,EAAE,QAAQ,EACvG,MAAM,sCAAsC,CAAA;AAS7C;;GAEG;AACH,MAAM,MAAM,+BAA+B,GAAG,WAAW,GAAG,iBAAiB,GAAG,OAAO,CAAA;AAEvF,qBACa,sBAAsB,CACjC,OAAO,SAAS,4BAA4B,GAAG,4BAA4B,EAC3E,GAAG,SAAS,+BAA+B,GAAG,+BAA+B,EAC7E,IAAI,SAAS,QAAQ,GAAG,QAAQ,EAChC,UAAU,SAAS,sBAAsB,CAAC,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,sBAAsB,CAChH,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,EACnC,GAAG,EACH,IAAI,CACL,CACD,SAAQ,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,CAAC;IACvD,gBAAyB,aAAa;;SAAuC;IAC7E,gBAAyB,mBAAmB;;MAAqC;cAEjE,aAAa,CAAC,QAAQ,GAAE,GAAG,EAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;CAwBrE"}
@@ -1 +1 @@
1
- {"version":3,"file":"Diviner.d.ts","sourceRoot":"","sources":["../../../src/Total/Diviner.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EACc,eAAe,EAAE,sBAAsB,EAC3D,MAAM,4BAA4B,CAAA;AAGnC,OAAO,EACL,QAAQ,EAGR,+BAA+B,EAAE,yBAAyB,EAAE,QAAQ,EAAE,KAAK,EAC5E,MAAM,sCAAsC,CAAA;AAE7C,OAAO,EAAE,sBAAsB,EAAE,+BAA+B,EAAE,MAAM,sBAAsB,CAAA;AAC9F,OAAO,EAAE,sBAAsB,EAAE,+BAA+B,EAAE,MAAM,sBAAsB,CAAA;AAE9F,KAAK,SAAS,GAAG,+BAA+B,GAAG,+BAA+B,CAAA;AAClF,KAAK,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,KAAK,CAAA;AAE7C,qBACa,mBAAmB,CAC9B,OAAO,SAAS,yBAAyB,GAAG,yBAAyB,EACrE,GAAG,SAAS,SAAS,GAAG,SAAS,EACjC,IAAI,SAAS,UAAU,GAAG,UAAU,EACpC,UAAU,SAAS,sBAAsB,CAAC,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,sBAAsB,CAChH,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,EACnC,GAAG,EACH,IAAI,CACL,CACD,SAAQ,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,CAAC;IACvD,gBAAyB,aAAa;;SAAoC;IAC1E,gBAAyB,mBAAmB,EAAE,+BAA+B,CAAkC;cAE/F,aAAa,CAAC,QAAQ,GAAE,GAAG,EAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;cAqBpD,0BAA0B,IAAI,OAAO,CAAC,sBAAsB,CAAC;cAM7D,yBAAyB,IAAI,OAAO,CAAC,sBAAsB,CAAC;CAK7E"}
1
+ {"version":3,"file":"Diviner.d.ts","sourceRoot":"","sources":["../../../src/Total/Diviner.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EACc,eAAe,EAAE,sBAAsB,EAC3D,MAAM,4BAA4B,CAAA;AAEnC,OAAO,EACL,QAAQ,EAGR,+BAA+B,EAAE,yBAAyB,EAAE,QAAQ,EAAE,KAAK,EAC5E,MAAM,sCAAsC,CAAA;AAG7C,OAAO,EAAE,sBAAsB,EAAE,+BAA+B,EAAE,MAAM,sBAAsB,CAAA;AAC9F,OAAO,EAAE,sBAAsB,EAAE,+BAA+B,EAAE,MAAM,sBAAsB,CAAA;AAE9F,KAAK,SAAS,GAAG,+BAA+B,GAAG,+BAA+B,CAAA;AAClF,KAAK,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,KAAK,CAAA;AAE7C,qBACa,mBAAmB,CAC9B,OAAO,SAAS,yBAAyB,GAAG,yBAAyB,EACrE,GAAG,SAAS,SAAS,GAAG,SAAS,EACjC,IAAI,SAAS,UAAU,GAAG,UAAU,EACpC,UAAU,SAAS,sBAAsB,CAAC,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,sBAAsB,CAChH,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,EACnC,GAAG,EACH,IAAI,CACL,CACD,SAAQ,eAAe,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,CAAC;IACvD,gBAAyB,aAAa;;SAAoC;IAC1E,gBAAyB,mBAAmB,EAAE,+BAA+B,CAAkC;cAE/F,aAAa,CAAC,QAAQ,GAAE,GAAG,EAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;cAqBpD,0BAA0B,IAAI,OAAO,CAAC,sBAAsB,CAAC;cAM7D,yBAAyB,IAAI,OAAO,CAAC,sBAAsB,CAAC;CAK7E"}
@@ -12,9 +12,11 @@ var __decorateClass = (decorators, target, key, kind) => {
12
12
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
13
13
 
14
14
  // src/Discount/Diviner.ts
15
- import { filterAs } from "@xylabs/array";
16
- import { assertEx as assertEx2 } from "@xylabs/assert";
17
- import { exists as exists2 } from "@xylabs/exists";
15
+ import {
16
+ assertEx as assertEx2,
17
+ exists as exists2,
18
+ filterAs
19
+ } from "@xylabs/sdk-js";
18
20
  import { asArchivistInstance } from "@xyo-network/archivist-model";
19
21
  import { AbstractDiviner } from "@xyo-network/diviner-abstract";
20
22
  import { BoundWitnessDivinerQuerySchema } from "@xyo-network/diviner-boundwitness-model";
@@ -25,7 +27,6 @@ import {
25
27
  asDivinerInstance
26
28
  } from "@xyo-network/diviner-model";
27
29
  import { creatableModule } from "@xyo-network/module-model";
28
- import { PayloadBuilder as PayloadBuilder2 } from "@xyo-network/payload-builder";
29
30
  import {
30
31
  asCondition,
31
32
  asCoupon,
@@ -35,10 +36,10 @@ import {
35
36
  NO_DISCOUNT,
36
37
  PaymentDiscountDivinerConfigSchema
37
38
  } from "@xyo-network/payment-payload-plugins";
39
+ import { PayloadBuilder as PayloadBuilder2 } from "@xyo-network/sdk-js";
38
40
 
39
41
  // src/Discount/lib/applyCoupons.ts
40
- import { assertEx } from "@xylabs/assert";
41
- import { exists } from "@xylabs/exists";
42
+ import { assertEx, exists } from "@xylabs/sdk-js";
42
43
  import {
43
44
  DiscountSchema,
44
45
  isFixedAmountCoupon,
@@ -87,9 +88,9 @@ var calculateSingularFixedPriceDiscount = (total, appraisals, coupons, stackable
87
88
  };
88
89
 
89
90
  // src/Discount/lib/findUnfulfilledConditions.ts
90
- import { PayloadBuilder } from "@xyo-network/payload-builder";
91
91
  import { isCondition } from "@xyo-network/payment-payload-plugins";
92
92
  import { isSchemaPayload } from "@xyo-network/schema-payload-plugin";
93
+ import { PayloadBuilder } from "@xyo-network/sdk-js";
93
94
  import { Ajv } from "ajv";
94
95
  var ajv = new Ajv({ strict: false });
95
96
  var schemaCache = /* @__PURE__ */ new Map();
@@ -255,13 +256,13 @@ PaymentDiscountDiviner = __decorateClass([
255
256
  ], PaymentDiscountDiviner);
256
257
 
257
258
  // src/Invoice/getInvoiceForEscrow.ts
258
- import { PayloadBuilder as PayloadBuilder3 } from "@xyo-network/payload-builder";
259
259
  import {
260
260
  isDiscount,
261
261
  isSubtotal,
262
262
  isTotal,
263
263
  PaymentSchema
264
264
  } from "@xyo-network/payment-payload-plugins";
265
+ import { PayloadBuilder as PayloadBuilder3 } from "@xyo-network/sdk-js";
265
266
  var getInvoiceForEscrow = async (terms, dataHashMap, paymentTotalDiviner) => {
266
267
  const payloads = Object.values(dataHashMap);
267
268
  const results = await paymentTotalDiviner.divine([terms, ...payloads]);
@@ -289,12 +290,12 @@ var getSources = async (terms, subtotal, total, discount) => {
289
290
  import { AbstractDiviner as AbstractDiviner2 } from "@xyo-network/diviner-abstract";
290
291
  import { isHashLeaseEstimate as isHashLeaseEstimate2 } from "@xyo-network/diviner-hash-lease";
291
292
  import { creatableModule as creatableModule2 } from "@xyo-network/module-model";
292
- import { PayloadBuilder as PayloadBuilder4 } from "@xyo-network/payload-builder";
293
293
  import {
294
294
  isEscrowTerms as isEscrowTerms2,
295
295
  PaymentSubtotalDivinerConfigSchema,
296
296
  SubtotalSchema
297
297
  } from "@xyo-network/payment-payload-plugins";
298
+ import { PayloadBuilder as PayloadBuilder4 } from "@xyo-network/sdk-js";
298
299
 
299
300
  // src/Subtotal/lib/appraisalValidators.ts
300
301
  import { isIso4217CurrencyCode } from "@xyo-network/payment-payload-plugins";
@@ -373,19 +374,19 @@ var calculateSubtotal = (appraisals) => {
373
374
  };
374
375
 
375
376
  // src/Total/Diviner.ts
376
- import { assertEx as assertEx3 } from "@xylabs/assert";
377
+ import { assertEx as assertEx3 } from "@xylabs/sdk-js";
377
378
  import { AbstractDiviner as AbstractDiviner3 } from "@xyo-network/diviner-abstract";
378
379
  import {
379
380
  asDivinerInstance as asDivinerInstance2
380
381
  } from "@xyo-network/diviner-model";
381
382
  import { creatableModule as creatableModule3 } from "@xyo-network/module-model";
382
- import { PayloadBuilder as PayloadBuilder5 } from "@xyo-network/payload-builder";
383
383
  import {
384
384
  isDiscount as isDiscount2,
385
385
  isSubtotal as isSubtotal2,
386
386
  PaymentTotalDivinerConfigSchema,
387
387
  TotalSchema
388
388
  } from "@xyo-network/payment-payload-plugins";
389
+ import { PayloadBuilder as PayloadBuilder5 } from "@xyo-network/sdk-js";
389
390
  var PaymentTotalDiviner = class extends AbstractDiviner3 {
390
391
  async divineHandler(payloads = []) {
391
392
  const subtotalDiviner = await this.getPaymentSubtotalDiviner();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/Discount/Diviner.ts","../../src/Discount/lib/applyCoupons.ts","../../src/Discount/lib/findUnfulfilledConditions.ts","../../src/Invoice/getInvoiceForEscrow.ts","../../src/Subtotal/Diviner.ts","../../src/Subtotal/lib/appraisalValidators.ts","../../src/Subtotal/lib/durationValidators.ts","../../src/Subtotal/lib/termsValidators.ts","../../src/Total/Diviner.ts"],"sourcesContent":["import { filterAs } from '@xylabs/array'\nimport { assertEx } from '@xylabs/assert'\nimport { exists } from '@xylabs/exists'\nimport { Address, Hash } from '@xylabs/hex'\nimport { ArchivistInstance, asArchivistInstance } from '@xyo-network/archivist-model'\nimport { AbstractDiviner } from '@xyo-network/diviner-abstract'\nimport { BoundWitnessDivinerQueryPayload, BoundWitnessDivinerQuerySchema } from '@xyo-network/diviner-boundwitness-model'\nimport {\n HashLeaseEstimate,\n isHashLeaseEstimate,\n} from '@xyo-network/diviner-hash-lease'\nimport {\n asDivinerInstance, DivinerInstance, DivinerModuleEventData,\n} from '@xyo-network/diviner-model'\nimport { creatableModule } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload } from '@xyo-network/payload-model'\nimport {\n asCondition,\n asCoupon,\n Condition,\n Coupon,\n Discount,\n EscrowTerms, isCondition, isCoupon,\n isEscrowTerms, NO_DISCOUNT, PaymentDiscountDivinerConfigSchema, PaymentDiscountDivinerParams,\n} from '@xyo-network/payment-payload-plugins'\n\nimport { applyCoupons, areConditionsFulfilled } from './lib/index.ts'\n\nconst DEFAULT_BOUND_WITNESS_DIVINER_QUERY_PROPS: Readonly<BoundWitnessDivinerQueryPayload> = {\n limit: 1,\n order: 'desc',\n schema: BoundWitnessDivinerQuerySchema,\n}\n\nexport type PaymentDiscountDivinerInputType = EscrowTerms | Coupon | HashLeaseEstimate | Payload\n\n@creatableModule()\nexport class PaymentDiscountDiviner<\n TParams extends PaymentDiscountDivinerParams = PaymentDiscountDivinerParams,\n TIn extends PaymentDiscountDivinerInputType = PaymentDiscountDivinerInputType,\n TOut extends Discount = Discount,\n TEventData extends DivinerModuleEventData<DivinerInstance<TParams, TIn, TOut>, TIn, TOut> = DivinerModuleEventData<\n DivinerInstance<TParams, TIn, TOut>,\n TIn,\n TOut\n >,\n> extends AbstractDiviner<TParams, TIn, TOut, TEventData> {\n static override readonly configSchemas = [PaymentDiscountDivinerConfigSchema]\n static override readonly defaultConfigSchema = PaymentDiscountDivinerConfigSchema\n\n protected get couponAuthorities(): Address[] {\n return [...(this.config.couponAuthorities ?? []), ...(this.params.couponAuthorities ?? [])]\n }\n\n protected async divineHandler(payloads: TIn[] = []): Promise<TOut[]> {\n const $sources: Hash[] = []\n\n // Parse terms\n const terms = payloads.find(isEscrowTerms) as EscrowTerms | undefined\n if (!terms) return [{ ...NO_DISCOUNT, $sources }] as TOut[]\n $sources.push(await PayloadBuilder.hash(terms))\n\n // Parse appraisals\n const termsAppraisals = terms?.appraisals\n // If the escrow terms do not have appraisals, return no discount\n if (!termsAppraisals || termsAppraisals.length === 0) return [{ ...NO_DISCOUNT, $sources }] as TOut[]\n const hashMap = await PayloadBuilder.toAllHashMap(payloads) as Record<Hash, Payload>\n const appraisals = this.getEscrowAppraisals(terms, hashMap)\n // Add the appraisals that were found to the sources\n $sources.push(...termsAppraisals)\n // If not all appraisals are found, return no discount\n if (appraisals.length !== termsAppraisals.length) return [{ ...NO_DISCOUNT, $sources }] as TOut[]\n\n // Parse coupons\n const [coupons, conditions] = await this.getEscrowDiscounts(terms, hashMap)\n // Add the coupons that were found to the sources\n // TODO: Should we throw if not all coupons are found?\n const couponHashes = await PayloadBuilder.hashes(coupons)\n $sources.push(...couponHashes)\n\n const currentCoupons = coupons.filter(this.isCouponCurrent)\n const conditionsMetCoupons = (\n await Promise.all(currentCoupons.map(async coupon => await areConditionsFulfilled(coupon, conditions, payloads) ? coupon : undefined))).filter(exists)\n\n const validCoupons = await this.filterToSigned(conditionsMetCoupons)\n // TODO: Should we throw if not all coupons are valid?\n if (validCoupons.length === 0) return [{ ...NO_DISCOUNT, $sources }] as TOut[]\n\n // TODO: Call paymentSubtotalDiviner to get the subtotal to centralize the logic\n const discount = applyCoupons(appraisals, validCoupons)\n return [{ ...discount, $sources }] as TOut[]\n }\n\n /**\n * Filters the supplied list of coupons to only those that are signed by\n * addresses specified in the couponAuthorities\n * @param coupons The list of coupons to filter\n * @returns The filtered list of coupons that are signed by the couponAuthorities\n */\n protected async filterToSigned(coupons: Coupon[]): Promise<Coupon[]> {\n const signed: Coupon[] = []\n const dataHashMap = await PayloadBuilder.toDataHashMap(coupons)\n const boundWitnessDiviner = await this.getDiscountsBoundWitnessDiviner()\n const hashes = Object.keys(dataHashMap)\n const addresses = this.couponAuthorities\n // TODO: Keep an in memory cache of the hashes queried and their results\n // to avoid querying the same hash multiple times\n await Promise.all(hashes.map((h) => {\n const hash = h as Hash\n return Promise.all(addresses.map(async (address) => {\n const query: BoundWitnessDivinerQueryPayload = {\n ...DEFAULT_BOUND_WITNESS_DIVINER_QUERY_PROPS, addresses: [address], payload_hashes: [hash],\n }\n const result = await boundWitnessDiviner.divine([query])\n if (result.length > 0) signed.push(dataHashMap[hash])\n }))\n }))\n return signed\n }\n\n protected async getDiscountsArchivist(): Promise<ArchivistInstance> {\n const name = assertEx(this.config.archivist, () => 'Missing archivist in config')\n const mod = assertEx(await this.resolve(name), () => `Error resolving archivist: ${name}`)\n return assertEx(asArchivistInstance(mod), () => `Resolved module ${mod.address} not a valid Archivist`)\n }\n\n protected async getDiscountsBoundWitnessDiviner(): Promise<DivinerInstance> {\n const name = assertEx(this.config.boundWitnessDiviner, () => 'Missing boundWitnessDiviner in config')\n const mod = assertEx(await this.resolve(name), () => `Error resolving boundWitnessDiviner: ${name}`)\n return assertEx(asDivinerInstance(mod), () => `Resolved module ${mod.address} not a valid Diviner`)\n }\n\n /**\n * Finds the appraisals specified by the escrow terms from the supplied payloads\n * @param terms The escrow terms\n * @param payloads The payloads to search for the appraisals\n * @returns The appraisals found in the payloads\n */\n protected getEscrowAppraisals(terms: EscrowTerms, hashMap: Record<Hash, Payload>): HashLeaseEstimate[] {\n const hashes = terms?.appraisals ?? []\n if (hashes.length === 0) return []\n return hashes.map(hash => hashMap[hash]).filter(exists).filter(isHashLeaseEstimate)\n }\n\n /**\n * Finds the discounts specified by the escrow terms from the supplied payloads\n * @param terms The escrow terms\n * @param hashMap The payloads to search for the discounts\n * @returns A tuple containing all the escrow coupons and conditions referenced in those coupons\n * that were found in the either the supplied payloads or the archivist\n */\n protected async getEscrowDiscounts(terms: EscrowTerms, hashMap: Record<Hash, Payload>): Promise<[Coupon[], Condition[]]> {\n // Parse discounts\n const discountsHashes = terms.discounts ?? []\n if (discountsHashes.length === 0) return [[], []]\n\n // Use the supplied payloads to find the discounts\n const discounts: Coupon[] = discountsHashes.map(hash => hashMap[hash]).filter(exists).filter(isCoupon)\n const missingDiscounts = discountsHashes.filter(hash => !hashMap[hash])\n // If not all discounts are found\n if (missingDiscounts.length > 0) {\n // Find any remaining from discounts archivist\n const discountsArchivist = await this.getDiscountsArchivist()\n const payloads = await discountsArchivist.get(missingDiscounts)\n discounts.push(...filterAs(payloads, asCoupon))\n }\n // If not all discounts are found\n if (discounts.length !== discountsHashes.length) {\n const termsHash = await PayloadBuilder.hash(terms)\n const foundHashes = await PayloadBuilder.hashes(discounts)\n // Log individual discounts that were not found\n for (const hash of discountsHashes) {\n if (!foundHashes.includes(hash)) console.warn(`Discount ${hash} not found for terms ${termsHash}`)\n }\n }\n\n const conditionsHashes: Hash[] = discounts.flatMap(discount => discount.conditions ?? [])\n const conditions: Condition[] = conditionsHashes.map(hash => hashMap[hash]).filter(exists).filter(isCondition)\n const missingConditions = conditionsHashes.filter(hash => !hashMap[hash])\n\n // If not all conditions are found\n if (missingConditions.length > 0) {\n // Find any remaining from discounts archivist\n const discountsArchivist = await this.getDiscountsArchivist()\n const payloads = await discountsArchivist.get(missingConditions)\n conditions.push(...filterAs(payloads, asCondition))\n }\n // If not all conditions are found\n if (conditions.length !== conditionsHashes.length) {\n const termsHash = await PayloadBuilder.hash(terms)\n const foundHashes = await PayloadBuilder.hashes(conditions)\n // Log individual conditions that were not found\n for (const hash of discountsHashes) {\n if (!foundHashes.includes(hash)) console.warn(`Coupon condition ${hash} not found for terms ${termsHash}`)\n }\n }\n\n return [discounts, conditions]\n }\n\n protected isCouponCurrent(coupon: Coupon): boolean {\n const now = Date.now()\n return coupon.exp > now && coupon.nbf < now\n }\n}\n","import { assertEx } from '@xylabs/assert'\nimport { exists } from '@xylabs/exists'\nimport type { HashLeaseEstimate } from '@xyo-network/diviner-hash-lease'\nimport type {\n AmountFields,\n Coupon, Discount, FixedAmountCoupon,\n FixedPercentageCoupon,\n FixedPriceCoupon,\n} from '@xyo-network/payment-payload-plugins'\nimport {\n DiscountSchema,\n isFixedAmountCoupon, isFixedPercentageCoupon,\n isFixedPriceCoupon,\n isStackable,\n} from '@xyo-network/payment-payload-plugins'\n\nexport const applyCoupons = (appraisals: HashLeaseEstimate[], coupons: Coupon[]): Discount => {\n // Ensure all appraisals and coupons are in USD\n const allAppraisalsAreUSD = appraisals.every(appraisal => appraisal.currency === 'USD')\n assertEx(allAppraisalsAreUSD, () => 'All appraisals must be in USD')\n const allCouponsAreUSD = coupons.map(coupon => (coupon as Partial<AmountFields>)?.currency).filter(exists).every(currency => currency === 'USD')\n assertEx(allCouponsAreUSD, () => 'All coupons must be in USD')\n const total = appraisals.reduce((acc, appraisal) => acc + appraisal.price, 0)\n\n // Calculated non-stackable discount coupons\n const singularFixedDiscount = Math.max(...coupons\n .filter(coupon => isFixedAmountCoupon(coupon) && !isStackable(coupon))\n .map(coupon => (coupon as FixedAmountCoupon).amount), 0)\n const singularPercentageDiscount = (Math.max(...coupons\n .filter(coupon => isFixedPercentageCoupon(coupon) && !isStackable(coupon))\n .map(coupon => (coupon as FixedPercentageCoupon).percentage), 0)) * total\n const singularFixedPriceDiscount = calculateSingularFixedPriceDiscount(total, appraisals, coupons, false)\n\n // Calculate stackable discount coupons\n // First calculate the total discount from fixed amount coupons\n const stackedFixedDiscount = coupons\n .filter(coupon => isFixedAmountCoupon(coupon) && isStackable(coupon))\n .reduce((acc, coupon) => acc + (coupon as FixedAmountCoupon).amount, 0)\n // Then calculate the total discount from percentage coupons and apply\n // the percentage discount to the remaining total after fixed discounts\n const stackedPercentageDiscount = coupons\n .filter(coupon => isFixedPercentageCoupon(coupon) && isStackable(coupon))\n .reduce((acc, coupon) => acc + (coupon as FixedPercentageCoupon).percentage, 0) * (total - stackedFixedDiscount)\n // Then calculate the total discount from fixed price coupons\n const stackedFixedPriceDiscount = calculateSingularFixedPriceDiscount(total, appraisals, coupons, true)\n\n // Sum all stackable discounts\n const stackedDiscount = stackedFixedDiscount + stackedPercentageDiscount + stackedFixedPriceDiscount\n\n // Find the best coupon(s) to apply\n const maxDiscount = Math.max(\n singularFixedDiscount,\n singularFixedPriceDiscount,\n singularPercentageDiscount,\n stackedDiscount,\n 0,\n )\n\n // Ensure discount is not more than the total\n const amount = Math.min(maxDiscount, total)\n\n // Return single discount payload\n return {\n amount, schema: DiscountSchema, currency: 'USD',\n }\n}\n\nconst calculateSingularFixedPriceDiscount = (total: number, appraisals: HashLeaseEstimate[], coupons: Coupon[], stackable = false): number => {\n // Find all singular fixed price discounts\n const singularFixedPriceDiscounts = coupons\n .filter(isFixedPriceCoupon)\n .filter(coupon => stackable ? isStackable(coupon) : !isStackable(coupon))\n .map(coupon => (coupon as FixedPriceCoupon).amount)\n // Ensure all fixed price discounts are positive\n .filter(amount => amount > 0)\n\n // If there are no singular fixed price discounts, return no discount\n if (singularFixedPriceDiscounts.length === 0) return 0\n\n // Find the maximum discount (the lowest fixed price)\n const lowestFixedPrice = Math.min(...singularFixedPriceDiscounts)\n\n // Apply the fixed price to all appraisals to get the reduced prices\n const reducedPrices = appraisals.map(appraisal =>\n // If the appraisal price is less than the fixed price\n Math.min(appraisal.price, lowestFixedPrice))\n\n // Calculate the reduced total using the reduced prices\n const reducedTotal = reducedPrices.reduce((acc, price) => acc + price, 0)\n\n // Calculate the discount\n const discount = total - reducedTotal\n\n // Return the discount or 0 if the discount would have resulted in a negative value\n return Math.max(discount, 0)\n}\n","import type { Hash } from '@xylabs/hex'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport type { Payload } from '@xyo-network/payload-model'\nimport type { Condition, Coupon } from '@xyo-network/payment-payload-plugins'\nimport { isCondition } from '@xyo-network/payment-payload-plugins'\nimport type { SchemaPayload } from '@xyo-network/schema-payload-plugin'\nimport { isSchemaPayload } from '@xyo-network/schema-payload-plugin'\nimport type { ValidateFunction } from 'ajv'\nimport { Ajv } from 'ajv'\n\n// TODO: Use our schema cache\nconst ajv = new Ajv({ strict: false }) // Create the Ajv instance once\nconst schemaCache = new Map() // Cache to store compiled validators\n\n/**\n * Validates the conditions of a coupon against the provided payloads\n * @param coupon The coupon to check\n * @param conditions The conditions associated with the coupon\n * @param payloads The associated payloads (containing the conditions and data to validate the conditions against)\n * @returns True if all conditions are fulfilled, false otherwise\n */\nexport const areConditionsFulfilled = async (coupon: Coupon, conditions: Condition[] = [], payloads: Payload[] = []): Promise<boolean> =>\n (await findUnfulfilledConditions(coupon, conditions, payloads)).length === 0\n\n/**\n * Validates the conditions of a coupon against the provided payloads\n * @param coupon The coupon to check\n * @param conditions The conditions associated with the coupon\n * @param payloads The associated payloads (containing the conditions and data to validate the conditions against)\n * @returns The unfulfilled condition hashes\n */\nexport const findUnfulfilledConditions = async (coupon: Coupon, conditions: Condition[] = [], payloads: Payload[] = []): Promise<Hash[]> => {\n const unfulfilledConditions: Hash[] = []\n // If there are no conditions, then they are fulfilled\n if (!coupon.conditions || coupon.conditions.length === 0) return unfulfilledConditions\n const hashMap = await PayloadBuilder.toAllHashMap([...conditions, ...payloads])\n // Find all the conditions\n const foundConditions = coupon.conditions.map(hash => hashMap[hash]).filter(isCondition)\n // Not all conditions were found\n if (foundConditions.length !== coupon.conditions.length) {\n const missing = coupon.conditions.filter(hash => !hashMap[hash])\n unfulfilledConditions.push(...missing)\n return unfulfilledConditions\n }\n\n // Test each condition\n for (const hash of coupon.conditions) {\n let validator: ValidateFunction\n\n // Check if the schema is already cached\n if (schemaCache.has(hash)) {\n validator = schemaCache.get(hash)\n } else {\n const payload = hashMap[hash]\n const definition = isSchemaPayload(payload) ? (payload as SchemaPayload).definition : undefined\n if (definition) {\n // Compile and cache the validator\n validator = ajv.compile(definition)\n schemaCache.set(hash, validator)\n\n // Validate the payload\n } else {\n unfulfilledConditions.push(hash)\n continue\n }\n }\n if (!validator(payloads)) unfulfilledConditions.push(hash)\n }\n\n // All conditions passed\n return unfulfilledConditions\n}\n","import type { Hash } from '@xylabs/hex'\nimport type { DivinerInstance } from '@xyo-network/diviner-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport type { Payload } from '@xyo-network/payload-model'\nimport type {\n Discount, EscrowTerms, Invoice, Payment,\n Subtotal, Total,\n} from '@xyo-network/payment-payload-plugins'\nimport {\n isDiscount, isSubtotal, isTotal, PaymentSchema,\n} from '@xyo-network/payment-payload-plugins'\n\n/**\n * Validates the escrow terms to ensure they are valid for a purchase\n * @returns A payment if the terms are valid for a purchase, undefined otherwise\n */\nexport const getInvoiceForEscrow = async (\n terms: EscrowTerms,\n dataHashMap: Record<Hash, Payload>,\n paymentTotalDiviner: DivinerInstance,\n): Promise<Invoice | undefined> => {\n const payloads = Object.values(dataHashMap)\n const results = await paymentTotalDiviner.divine([terms, ...payloads])\n const subtotal = results.find(isSubtotal) as Subtotal | undefined\n const discount = results.find(isDiscount) as Discount | undefined\n const total = results.find(isTotal) as Total | undefined\n if (!subtotal || !total) return undefined\n const { amount, currency } = total\n if (currency !== 'USD') return undefined\n const $sources = await getSources(terms, subtotal, total, discount)\n const payment: Payment = {\n amount, currency, schema: PaymentSchema, $sources,\n }\n return discount ? [subtotal, total, payment, discount] : [subtotal, total, payment]\n}\n\nconst getSources = async (terms: EscrowTerms, subtotal: Subtotal, total: Total, discount?: Discount): Promise<Hash[]> => {\n const sources = discount ? [terms, subtotal, total, discount] : [terms, subtotal, total]\n return await Promise.all(sources.map(p => PayloadBuilder.dataHash(p)))\n}\n","import { AbstractDiviner } from '@xyo-network/diviner-abstract'\nimport { HashLeaseEstimate, isHashLeaseEstimate } from '@xyo-network/diviner-hash-lease'\nimport { DivinerInstance, DivinerModuleEventData } from '@xyo-network/diviner-model'\nimport { creatableModule } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport { Payload } from '@xyo-network/payload-model'\nimport {\n EscrowTerms, isEscrowTerms, PaymentSubtotalDivinerConfigSchema, PaymentSubtotalDivinerParams, Subtotal, SubtotalSchema,\n} from '@xyo-network/payment-payload-plugins'\n\nimport {\n appraisalValidators, termsValidators, ValidEscrowTerms,\n} from './lib/index.ts'\n\nconst currency = 'USD'\n\n/**\n * Escrow terms that contain all the valid fields for calculating a subtotal\n */\nexport type PaymentSubtotalDivinerInputType = EscrowTerms | HashLeaseEstimate | Payload\n\n@creatableModule()\nexport class PaymentSubtotalDiviner<\n TParams extends PaymentSubtotalDivinerParams = PaymentSubtotalDivinerParams,\n TIn extends PaymentSubtotalDivinerInputType = PaymentSubtotalDivinerInputType,\n TOut extends Subtotal = Subtotal,\n TEventData extends DivinerModuleEventData<DivinerInstance<TParams, TIn, TOut>, TIn, TOut> = DivinerModuleEventData<\n DivinerInstance<TParams, TIn, TOut>,\n TIn,\n TOut\n >,\n> extends AbstractDiviner<TParams, TIn, TOut, TEventData> {\n static override readonly configSchemas = [PaymentSubtotalDivinerConfigSchema]\n static override readonly defaultConfigSchema = PaymentSubtotalDivinerConfigSchema\n\n protected async divineHandler(payloads: TIn[] = []): Promise<TOut[]> {\n // Find the escrow terms\n const terms = payloads.find(isEscrowTerms) as EscrowTerms | undefined\n if (!terms) return []\n\n // Run all terms validations\n if (!termsValidators.every(validator => validator(terms))) return []\n const validTerms = terms as ValidEscrowTerms\n\n // Retrieve all appraisals from terms\n const hashMap = await PayloadBuilder.toAllHashMap(payloads)\n const appraisals = validTerms.appraisals.map(appraisal => hashMap[appraisal]).filter(isHashLeaseEstimate) as unknown as HashLeaseEstimate[]\n\n // Ensure all appraisals are present\n if (appraisals.length !== validTerms.appraisals.length) return []\n\n // Run all appraisal validations\n if (!appraisalValidators.every(validator => validator(appraisals))) return []\n const amount = calculateSubtotal(appraisals)\n const $sources = [await PayloadBuilder.dataHash(validTerms), ...validTerms.appraisals]\n return [{\n amount, currency, schema: SubtotalSchema, $sources,\n }] as TOut[]\n }\n}\n\n// TODO: Add support for other currencies\nconst calculateSubtotal = (appraisals: HashLeaseEstimate[]): number => {\n return appraisals.reduce((sum, appraisal) => sum + appraisal.price, 0)\n}\n","import type { HashLeaseEstimate } from '@xyo-network/diviner-hash-lease'\nimport { isIso4217CurrencyCode } from '@xyo-network/payment-payload-plugins'\n\nimport { validateDuration } from './durationValidators.ts'\n\nconst validateAppraisalAmount = (appraisals: HashLeaseEstimate[]): boolean => {\n // Ensure all appraisals are numeric\n if (appraisals.some(appraisal => typeof appraisal.price !== 'number')) return false\n // Ensure all appraisals are positive numbers\n return !(appraisals.some(appraisal => appraisal.price < 0))\n}\n\nconst validateAppraisalCurrency = (appraisals: HashLeaseEstimate[]): boolean => {\n // Only supporting USD for now, the remaining checks are for future-proofing.\n if (!appraisals.every(appraisal => appraisal.currency == 'USD')) return false\n\n // Check every object in the array to ensure they all are in a supported currency.\n return (appraisals.every(appraisal => isIso4217CurrencyCode(appraisal.currency)))\n}\n\nconst validateAppraisalConsistentCurrency = (appraisals: HashLeaseEstimate[]): boolean => {\n // Check if the array is empty or contains only one element, no need to compare.\n if (appraisals.length <= 1) return true\n\n // Get the currency of the first element to compare with others.\n const { currency } = appraisals[0]\n if (!currency) return false\n\n // Check every object in the array to ensure they all have the same currency.\n return (appraisals.every(item => item.currency === currency))\n}\n\nconst validateAppraisalWindow = (appraisals: HashLeaseEstimate[]): boolean => appraisals.every(validateDuration)\n\nexport const appraisalValidators = [\n validateAppraisalAmount,\n validateAppraisalCurrency,\n validateAppraisalConsistentCurrency,\n validateAppraisalWindow,\n]\n","import type { DurationFields } from '@xyo-network/xns-record-payload-plugins'\n\nconst FIVE_MINUTES = 1000 * 60 * 5\n\n/**\n * Validates that the current time is within the duration window, within a configurable a buffer\n * @param value The duration value\n * @param windowMs The window in milliseconds to allow for a buffer\n * @returns True if the duration is valid, false otherwise\n */\nexport const validateDuration = (value: Partial<DurationFields>, windowMs = FIVE_MINUTES): boolean => {\n const now = Date.now()\n if (!value.nbf || value.nbf > now) return false\n // If already expired (include for a 5 minute buffer to allow for a reasonable\n // minimum amount of time for the transaction to be processed)\n return !(!value.exp || value.exp - now < windowMs)\n}\n","import type { Hash } from '@xylabs/hex'\nimport type { EscrowTerms } from '@xyo-network/payment-payload-plugins'\n\nimport { validateDuration } from './durationValidators.ts'\n\nexport type ValidEscrowTerms = Required<EscrowTerms>\n\nconst validateTermsAppraisals = (terms: EscrowTerms): terms is Required<EscrowTerms & { appraisals: Hash[] }> => {\n if (!terms.appraisals) return false\n return terms.appraisals.length > 0\n}\nconst validateTermsWindow = (terms: EscrowTerms): boolean => validateDuration(terms)\n\nexport const termsValidators = [\n validateTermsAppraisals,\n validateTermsWindow,\n]\n","import { assertEx } from '@xylabs/assert'\nimport { Hash } from '@xylabs/hex'\nimport { AbstractDiviner } from '@xyo-network/diviner-abstract'\nimport {\n asDivinerInstance, DivinerInstance, DivinerModuleEventData,\n} from '@xyo-network/diviner-model'\nimport { creatableModule } from '@xyo-network/module-model'\nimport { PayloadBuilder } from '@xyo-network/payload-builder'\nimport {\n Discount,\n isDiscount,\n isSubtotal,\n PaymentTotalDivinerConfigSchema, PaymentTotalDivinerParams, Subtotal, Total, TotalSchema,\n} from '@xyo-network/payment-payload-plugins'\n\nimport { PaymentDiscountDiviner, PaymentDiscountDivinerInputType } from '../Discount/index.ts'\nimport { PaymentSubtotalDiviner, PaymentSubtotalDivinerInputType } from '../Subtotal/index.ts'\n\ntype InputType = PaymentDiscountDivinerInputType | PaymentSubtotalDivinerInputType\ntype OutputType = Subtotal | Discount | Total\n\n@creatableModule()\nexport class PaymentTotalDiviner<\n TParams extends PaymentTotalDivinerParams = PaymentTotalDivinerParams,\n TIn extends InputType = InputType,\n TOut extends OutputType = OutputType,\n TEventData extends DivinerModuleEventData<DivinerInstance<TParams, TIn, TOut>, TIn, TOut> = DivinerModuleEventData<\n DivinerInstance<TParams, TIn, TOut>,\n TIn,\n TOut\n >,\n> extends AbstractDiviner<TParams, TIn, TOut, TEventData> {\n static override readonly configSchemas = [PaymentTotalDivinerConfigSchema]\n static override readonly defaultConfigSchema: PaymentTotalDivinerConfigSchema = PaymentTotalDivinerConfigSchema\n\n protected async divineHandler(payloads: TIn[] = []): Promise<TOut[]> {\n const subtotalDiviner = await this.getPaymentSubtotalDiviner()\n const subtotalResult = await subtotalDiviner.divine(payloads)\n const subtotal = subtotalResult.find(isSubtotal)\n if (!subtotal) return []\n const discountDiviner = await this.getPaymentDiscountsDiviner()\n const discountResult = await discountDiviner.divine(payloads)\n const discount = discountResult.find(isDiscount)\n if (!discount) return []\n const { currency: subtotalCurrency } = subtotal\n const { currency: discountCurrency } = discount\n assertEx(subtotalCurrency === discountCurrency, () => `Subtotal currency ${subtotalCurrency} does not match discount currency ${discountCurrency}`)\n const amount = Math.max(0, subtotal.amount - discount.amount)\n const currency = subtotalCurrency\n const $sources = [await PayloadBuilder.dataHash(subtotal), await PayloadBuilder.dataHash(discount)] as Hash[]\n const total: Total = {\n amount, currency, $sources, schema: TotalSchema,\n }\n return [subtotal, discount, total] as TOut[]\n }\n\n protected async getPaymentDiscountsDiviner(): Promise<PaymentDiscountDiviner> {\n const name = assertEx(this.config.paymentDiscountDiviner, () => 'Missing paymentDiscountDiviner in config')\n const mod = assertEx(await this.resolve(name), () => `Error resolving paymentDiscountDiviner: ${name}`)\n return assertEx(asDivinerInstance(mod), () => `Resolved module ${mod.address} not a valid Diviner`) as PaymentDiscountDiviner\n }\n\n protected async getPaymentSubtotalDiviner(): Promise<PaymentSubtotalDiviner> {\n const name = assertEx(this.config.paymentSubtotalDiviner, () => 'Missing paymentSubtotalDiviner in config')\n const mod = assertEx(await this.resolve(name), () => `Error resolving paymentSubtotalDiviner: ${name}`)\n return assertEx(asDivinerInstance(mod), () => `Resolved module ${mod.address} not a valid Diviner`) as PaymentSubtotalDiviner\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA,SAAS,gBAAgB;AACzB,SAAS,YAAAA,iBAAgB;AACzB,SAAS,UAAAC,eAAc;AAEvB,SAA4B,2BAA2B;AACvD,SAAS,uBAAuB;AAChC,SAA0C,sCAAsC;AAChF;AAAA,EAEE;AAAA,OACK;AACP;AAAA,EACE;AAAA,OACK;AACP,SAAS,uBAAuB;AAChC,SAAS,kBAAAC,uBAAsB;AAE/B;AAAA,EACE;AAAA,EACA;AAAA,EAIa,eAAAC;AAAA,EAAa;AAAA,EAC1B;AAAA,EAAe;AAAA,EAAa;AAAA,OACvB;;;ACzBP,SAAS,gBAAgB;AACzB,SAAS,cAAc;AAQvB;AAAA,EACE;AAAA,EACA;AAAA,EAAqB;AAAA,EACrB;AAAA,EACA;AAAA,OACK;AAEA,IAAM,eAAe,CAAC,YAAiC,YAAgC;AAE5F,QAAM,sBAAsB,WAAW,MAAM,eAAa,UAAU,aAAa,KAAK;AACtF,WAAS,qBAAqB,MAAM,+BAA+B;AACnE,QAAM,mBAAmB,QAAQ,IAAI,YAAW,QAAkC,QAAQ,EAAE,OAAO,MAAM,EAAE,MAAM,CAAAC,cAAYA,cAAa,KAAK;AAC/I,WAAS,kBAAkB,MAAM,4BAA4B;AAC7D,QAAM,QAAQ,WAAW,OAAO,CAAC,KAAK,cAAc,MAAM,UAAU,OAAO,CAAC;AAG5E,QAAM,wBAAwB,KAAK,IAAI,GAAG,QACvC,OAAO,YAAU,oBAAoB,MAAM,KAAK,CAAC,YAAY,MAAM,CAAC,EACpE,IAAI,YAAW,OAA6B,MAAM,GAAG,CAAC;AACzD,QAAM,6BAA8B,KAAK,IAAI,GAAG,QAC7C,OAAO,YAAU,wBAAwB,MAAM,KAAK,CAAC,YAAY,MAAM,CAAC,EACxE,IAAI,YAAW,OAAiC,UAAU,GAAG,CAAC,IAAK;AACtE,QAAM,6BAA6B,oCAAoC,OAAO,YAAY,SAAS,KAAK;AAIxG,QAAM,uBAAuB,QAC1B,OAAO,YAAU,oBAAoB,MAAM,KAAK,YAAY,MAAM,CAAC,EACnE,OAAO,CAAC,KAAK,WAAW,MAAO,OAA6B,QAAQ,CAAC;AAGxE,QAAM,4BAA4B,QAC/B,OAAO,YAAU,wBAAwB,MAAM,KAAK,YAAY,MAAM,CAAC,EACvE,OAAO,CAAC,KAAK,WAAW,MAAO,OAAiC,YAAY,CAAC,KAAK,QAAQ;AAE7F,QAAM,4BAA4B,oCAAoC,OAAO,YAAY,SAAS,IAAI;AAGtG,QAAM,kBAAkB,uBAAuB,4BAA4B;AAG3E,QAAM,cAAc,KAAK;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAGA,QAAM,SAAS,KAAK,IAAI,aAAa,KAAK;AAG1C,SAAO;AAAA,IACL;AAAA,IAAQ,QAAQ;AAAA,IAAgB,UAAU;AAAA,EAC5C;AACF;AAEA,IAAM,sCAAsC,CAAC,OAAe,YAAiC,SAAmB,YAAY,UAAkB;AAE5I,QAAM,8BAA8B,QACjC,OAAO,kBAAkB,EACzB,OAAO,YAAU,YAAY,YAAY,MAAM,IAAI,CAAC,YAAY,MAAM,CAAC,EACvE,IAAI,YAAW,OAA4B,MAAM,EAEjD,OAAO,YAAU,SAAS,CAAC;AAG9B,MAAI,4BAA4B,WAAW,EAAG,QAAO;AAGrD,QAAM,mBAAmB,KAAK,IAAI,GAAG,2BAA2B;AAGhE,QAAM,gBAAgB,WAAW,IAAI;AAAA;AAAA,IAEnC,KAAK,IAAI,UAAU,OAAO,gBAAgB;AAAA,GAAC;AAG7C,QAAM,eAAe,cAAc,OAAO,CAAC,KAAK,UAAU,MAAM,OAAO,CAAC;AAGxE,QAAM,WAAW,QAAQ;AAGzB,SAAO,KAAK,IAAI,UAAU,CAAC;AAC7B;;;AC9FA,SAAS,sBAAsB;AAG/B,SAAS,mBAAmB;AAE5B,SAAS,uBAAuB;AAEhC,SAAS,WAAW;AAGpB,IAAM,MAAM,IAAI,IAAI,EAAE,QAAQ,MAAM,CAAC;AACrC,IAAM,cAAc,oBAAI,IAAI;AASrB,IAAM,yBAAyB,OAAO,QAAgB,aAA0B,CAAC,GAAG,WAAsB,CAAC,OAC/G,MAAM,0BAA0B,QAAQ,YAAY,QAAQ,GAAG,WAAW;AAStE,IAAM,4BAA4B,OAAO,QAAgB,aAA0B,CAAC,GAAG,WAAsB,CAAC,MAAuB;AAC1I,QAAM,wBAAgC,CAAC;AAEvC,MAAI,CAAC,OAAO,cAAc,OAAO,WAAW,WAAW,EAAG,QAAO;AACjE,QAAM,UAAU,MAAM,eAAe,aAAa,CAAC,GAAG,YAAY,GAAG,QAAQ,CAAC;AAE9E,QAAM,kBAAkB,OAAO,WAAW,IAAI,UAAQ,QAAQ,IAAI,CAAC,EAAE,OAAO,WAAW;AAEvF,MAAI,gBAAgB,WAAW,OAAO,WAAW,QAAQ;AACvD,UAAM,UAAU,OAAO,WAAW,OAAO,UAAQ,CAAC,QAAQ,IAAI,CAAC;AAC/D,0BAAsB,KAAK,GAAG,OAAO;AACrC,WAAO;AAAA,EACT;AAGA,aAAW,QAAQ,OAAO,YAAY;AACpC,QAAI;AAGJ,QAAI,YAAY,IAAI,IAAI,GAAG;AACzB,kBAAY,YAAY,IAAI,IAAI;AAAA,IAClC,OAAO;AACL,YAAM,UAAU,QAAQ,IAAI;AAC5B,YAAM,aAAa,gBAAgB,OAAO,IAAK,QAA0B,aAAa;AACtF,UAAI,YAAY;AAEd,oBAAY,IAAI,QAAQ,UAAU;AAClC,oBAAY,IAAI,MAAM,SAAS;AAAA,MAGjC,OAAO;AACL,8BAAsB,KAAK,IAAI;AAC/B;AAAA,MACF;AAAA,IACF;AACA,QAAI,CAAC,UAAU,QAAQ,EAAG,uBAAsB,KAAK,IAAI;AAAA,EAC3D;AAGA,SAAO;AACT;;;AF1CA,IAAM,4CAAuF;AAAA,EAC3F,OAAO;AAAA,EACP,OAAO;AAAA,EACP,QAAQ;AACV;AAKO,IAAM,yBAAN,cASG,gBAAgD;AAAA,EAIxD,IAAc,oBAA+B;AAC3C,WAAO,CAAC,GAAI,KAAK,OAAO,qBAAqB,CAAC,GAAI,GAAI,KAAK,OAAO,qBAAqB,CAAC,CAAE;AAAA,EAC5F;AAAA,EAEA,MAAgB,cAAc,WAAkB,CAAC,GAAoB;AACnE,UAAM,WAAmB,CAAC;AAG1B,UAAM,QAAQ,SAAS,KAAK,aAAa;AACzC,QAAI,CAAC,MAAO,QAAO,CAAC,EAAE,GAAG,aAAa,SAAS,CAAC;AAChD,aAAS,KAAK,MAAMC,gBAAe,KAAK,KAAK,CAAC;AAG9C,UAAM,kBAAkB,OAAO;AAE/B,QAAI,CAAC,mBAAmB,gBAAgB,WAAW,EAAG,QAAO,CAAC,EAAE,GAAG,aAAa,SAAS,CAAC;AAC1F,UAAM,UAAU,MAAMA,gBAAe,aAAa,QAAQ;AAC1D,UAAM,aAAa,KAAK,oBAAoB,OAAO,OAAO;AAE1D,aAAS,KAAK,GAAG,eAAe;AAEhC,QAAI,WAAW,WAAW,gBAAgB,OAAQ,QAAO,CAAC,EAAE,GAAG,aAAa,SAAS,CAAC;AAGtF,UAAM,CAAC,SAAS,UAAU,IAAI,MAAM,KAAK,mBAAmB,OAAO,OAAO;AAG1E,UAAM,eAAe,MAAMA,gBAAe,OAAO,OAAO;AACxD,aAAS,KAAK,GAAG,YAAY;AAE7B,UAAM,iBAAiB,QAAQ,OAAO,KAAK,eAAe;AAC1D,UAAM,wBACJ,MAAM,QAAQ,IAAI,eAAe,IAAI,OAAM,WAAU,MAAM,uBAAuB,QAAQ,YAAY,QAAQ,IAAI,SAAS,MAAS,CAAC,GAAG,OAAOC,OAAM;AAEvJ,UAAM,eAAe,MAAM,KAAK,eAAe,oBAAoB;AAEnE,QAAI,aAAa,WAAW,EAAG,QAAO,CAAC,EAAE,GAAG,aAAa,SAAS,CAAC;AAGnE,UAAM,WAAW,aAAa,YAAY,YAAY;AACtD,WAAO,CAAC,EAAE,GAAG,UAAU,SAAS,CAAC;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAgB,eAAe,SAAsC;AACnE,UAAM,SAAmB,CAAC;AAC1B,UAAM,cAAc,MAAMD,gBAAe,cAAc,OAAO;AAC9D,UAAM,sBAAsB,MAAM,KAAK,gCAAgC;AACvE,UAAM,SAAS,OAAO,KAAK,WAAW;AACtC,UAAM,YAAY,KAAK;AAGvB,UAAM,QAAQ,IAAI,OAAO,IAAI,CAAC,MAAM;AAClC,YAAM,OAAO;AACb,aAAO,QAAQ,IAAI,UAAU,IAAI,OAAO,YAAY;AAClD,cAAM,QAAyC;AAAA,UAC7C,GAAG;AAAA,UAA2C,WAAW,CAAC,OAAO;AAAA,UAAG,gBAAgB,CAAC,IAAI;AAAA,QAC3F;AACA,cAAM,SAAS,MAAM,oBAAoB,OAAO,CAAC,KAAK,CAAC;AACvD,YAAI,OAAO,SAAS,EAAG,QAAO,KAAK,YAAY,IAAI,CAAC;AAAA,MACtD,CAAC,CAAC;AAAA,IACJ,CAAC,CAAC;AACF,WAAO;AAAA,EACT;AAAA,EAEA,MAAgB,wBAAoD;AAClE,UAAM,OAAOE,UAAS,KAAK,OAAO,WAAW,MAAM,6BAA6B;AAChF,UAAM,MAAMA,UAAS,MAAM,KAAK,QAAQ,IAAI,GAAG,MAAM,8BAA8B,IAAI,EAAE;AACzF,WAAOA,UAAS,oBAAoB,GAAG,GAAG,MAAM,mBAAmB,IAAI,OAAO,wBAAwB;AAAA,EACxG;AAAA,EAEA,MAAgB,kCAA4D;AAC1E,UAAM,OAAOA,UAAS,KAAK,OAAO,qBAAqB,MAAM,uCAAuC;AACpG,UAAM,MAAMA,UAAS,MAAM,KAAK,QAAQ,IAAI,GAAG,MAAM,wCAAwC,IAAI,EAAE;AACnG,WAAOA,UAAS,kBAAkB,GAAG,GAAG,MAAM,mBAAmB,IAAI,OAAO,sBAAsB;AAAA,EACpG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQU,oBAAoB,OAAoB,SAAqD;AACrG,UAAM,SAAS,OAAO,cAAc,CAAC;AACrC,QAAI,OAAO,WAAW,EAAG,QAAO,CAAC;AACjC,WAAO,OAAO,IAAI,UAAQ,QAAQ,IAAI,CAAC,EAAE,OAAOD,OAAM,EAAE,OAAO,mBAAmB;AAAA,EACpF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAgB,mBAAmB,OAAoB,SAAkE;AAEvH,UAAM,kBAAkB,MAAM,aAAa,CAAC;AAC5C,QAAI,gBAAgB,WAAW,EAAG,QAAO,CAAC,CAAC,GAAG,CAAC,CAAC;AAGhD,UAAM,YAAsB,gBAAgB,IAAI,UAAQ,QAAQ,IAAI,CAAC,EAAE,OAAOA,OAAM,EAAE,OAAO,QAAQ;AACrG,UAAM,mBAAmB,gBAAgB,OAAO,UAAQ,CAAC,QAAQ,IAAI,CAAC;AAEtE,QAAI,iBAAiB,SAAS,GAAG;AAE/B,YAAM,qBAAqB,MAAM,KAAK,sBAAsB;AAC5D,YAAM,WAAW,MAAM,mBAAmB,IAAI,gBAAgB;AAC9D,gBAAU,KAAK,GAAG,SAAS,UAAU,QAAQ,CAAC;AAAA,IAChD;AAEA,QAAI,UAAU,WAAW,gBAAgB,QAAQ;AAC/C,YAAM,YAAY,MAAMD,gBAAe,KAAK,KAAK;AACjD,YAAM,cAAc,MAAMA,gBAAe,OAAO,SAAS;AAEzD,iBAAW,QAAQ,iBAAiB;AAClC,YAAI,CAAC,YAAY,SAAS,IAAI,EAAG,SAAQ,KAAK,YAAY,IAAI,wBAAwB,SAAS,EAAE;AAAA,MACnG;AAAA,IACF;AAEA,UAAM,mBAA2B,UAAU,QAAQ,cAAY,SAAS,cAAc,CAAC,CAAC;AACxF,UAAM,aAA0B,iBAAiB,IAAI,UAAQ,QAAQ,IAAI,CAAC,EAAE,OAAOC,OAAM,EAAE,OAAOE,YAAW;AAC7G,UAAM,oBAAoB,iBAAiB,OAAO,UAAQ,CAAC,QAAQ,IAAI,CAAC;AAGxE,QAAI,kBAAkB,SAAS,GAAG;AAEhC,YAAM,qBAAqB,MAAM,KAAK,sBAAsB;AAC5D,YAAM,WAAW,MAAM,mBAAmB,IAAI,iBAAiB;AAC/D,iBAAW,KAAK,GAAG,SAAS,UAAU,WAAW,CAAC;AAAA,IACpD;AAEA,QAAI,WAAW,WAAW,iBAAiB,QAAQ;AACjD,YAAM,YAAY,MAAMH,gBAAe,KAAK,KAAK;AACjD,YAAM,cAAc,MAAMA,gBAAe,OAAO,UAAU;AAE1D,iBAAW,QAAQ,iBAAiB;AAClC,YAAI,CAAC,YAAY,SAAS,IAAI,EAAG,SAAQ,KAAK,oBAAoB,IAAI,wBAAwB,SAAS,EAAE;AAAA,MAC3G;AAAA,IACF;AAEA,WAAO,CAAC,WAAW,UAAU;AAAA,EAC/B;AAAA,EAEU,gBAAgB,QAAyB;AACjD,UAAM,MAAM,KAAK,IAAI;AACrB,WAAO,OAAO,MAAM,OAAO,OAAO,MAAM;AAAA,EAC1C;AACF;AA7JE,cAVW,wBAUc,iBAAgB,CAAC,kCAAkC;AAC5E,cAXW,wBAWc,uBAAsB;AAXpC,yBAAN;AAAA,EADN,gBAAgB;AAAA,GACJ;;;AGpCb,SAAS,kBAAAI,uBAAsB;AAM/B;AAAA,EACE;AAAA,EAAY;AAAA,EAAY;AAAA,EAAS;AAAA,OAC5B;AAMA,IAAM,sBAAsB,OACjC,OACA,aACA,wBACiC;AACjC,QAAM,WAAW,OAAO,OAAO,WAAW;AAC1C,QAAM,UAAU,MAAM,oBAAoB,OAAO,CAAC,OAAO,GAAG,QAAQ,CAAC;AACrE,QAAM,WAAW,QAAQ,KAAK,UAAU;AACxC,QAAM,WAAW,QAAQ,KAAK,UAAU;AACxC,QAAM,QAAQ,QAAQ,KAAK,OAAO;AAClC,MAAI,CAAC,YAAY,CAAC,MAAO,QAAO;AAChC,QAAM,EAAE,QAAQ,UAAAC,UAAS,IAAI;AAC7B,MAAIA,cAAa,MAAO,QAAO;AAC/B,QAAM,WAAW,MAAM,WAAW,OAAO,UAAU,OAAO,QAAQ;AAClE,QAAM,UAAmB;AAAA,IACvB;AAAA,IAAQ,UAAAA;AAAA,IAAU,QAAQ;AAAA,IAAe;AAAA,EAC3C;AACA,SAAO,WAAW,CAAC,UAAU,OAAO,SAAS,QAAQ,IAAI,CAAC,UAAU,OAAO,OAAO;AACpF;AAEA,IAAM,aAAa,OAAO,OAAoB,UAAoB,OAAc,aAAyC;AACvH,QAAM,UAAU,WAAW,CAAC,OAAO,UAAU,OAAO,QAAQ,IAAI,CAAC,OAAO,UAAU,KAAK;AACvF,SAAO,MAAM,QAAQ,IAAI,QAAQ,IAAI,OAAKD,gBAAe,SAAS,CAAC,CAAC,CAAC;AACvE;;;ACvCA,SAAS,mBAAAE,wBAAuB;AAChC,SAA4B,uBAAAC,4BAA2B;AAEvD,SAAS,mBAAAC,wBAAuB;AAChC,SAAS,kBAAAC,uBAAsB;AAE/B;AAAA,EACe,iBAAAC;AAAA,EAAe;AAAA,EAA4E;AAAA,OACnG;;;ACPP,SAAS,6BAA6B;;;ACCtC,IAAM,eAAe,MAAO,KAAK;AAQ1B,IAAM,mBAAmB,CAAC,OAAgC,WAAW,iBAA0B;AACpG,QAAM,MAAM,KAAK,IAAI;AACrB,MAAI,CAAC,MAAM,OAAO,MAAM,MAAM,IAAK,QAAO;AAG1C,SAAO,EAAE,CAAC,MAAM,OAAO,MAAM,MAAM,MAAM;AAC3C;;;ADXA,IAAM,0BAA0B,CAAC,eAA6C;AAE5E,MAAI,WAAW,KAAK,eAAa,OAAO,UAAU,UAAU,QAAQ,EAAG,QAAO;AAE9E,SAAO,CAAE,WAAW,KAAK,eAAa,UAAU,QAAQ,CAAC;AAC3D;AAEA,IAAM,4BAA4B,CAAC,eAA6C;AAE9E,MAAI,CAAC,WAAW,MAAM,eAAa,UAAU,YAAY,KAAK,EAAG,QAAO;AAGxE,SAAQ,WAAW,MAAM,eAAa,sBAAsB,UAAU,QAAQ,CAAC;AACjF;AAEA,IAAM,sCAAsC,CAAC,eAA6C;AAExF,MAAI,WAAW,UAAU,EAAG,QAAO;AAGnC,QAAM,EAAE,UAAAC,UAAS,IAAI,WAAW,CAAC;AACjC,MAAI,CAACA,UAAU,QAAO;AAGtB,SAAQ,WAAW,MAAM,UAAQ,KAAK,aAAaA,SAAQ;AAC7D;AAEA,IAAM,0BAA0B,CAAC,eAA6C,WAAW,MAAM,gBAAgB;AAExG,IAAM,sBAAsB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;AEhCA,IAAM,0BAA0B,CAAC,UAAgF;AAC/G,MAAI,CAAC,MAAM,WAAY,QAAO;AAC9B,SAAO,MAAM,WAAW,SAAS;AACnC;AACA,IAAM,sBAAsB,CAAC,UAAgC,iBAAiB,KAAK;AAE5E,IAAM,kBAAkB;AAAA,EAC7B;AAAA,EACA;AACF;;;AHFA,IAAM,WAAW;AAQV,IAAM,yBAAN,cASGC,iBAAgD;AAAA,EAIxD,MAAgB,cAAc,WAAkB,CAAC,GAAoB;AAEnE,UAAM,QAAQ,SAAS,KAAKC,cAAa;AACzC,QAAI,CAAC,MAAO,QAAO,CAAC;AAGpB,QAAI,CAAC,gBAAgB,MAAM,eAAa,UAAU,KAAK,CAAC,EAAG,QAAO,CAAC;AACnE,UAAM,aAAa;AAGnB,UAAM,UAAU,MAAMC,gBAAe,aAAa,QAAQ;AAC1D,UAAM,aAAa,WAAW,WAAW,IAAI,eAAa,QAAQ,SAAS,CAAC,EAAE,OAAOC,oBAAmB;AAGxG,QAAI,WAAW,WAAW,WAAW,WAAW,OAAQ,QAAO,CAAC;AAGhE,QAAI,CAAC,oBAAoB,MAAM,eAAa,UAAU,UAAU,CAAC,EAAG,QAAO,CAAC;AAC5E,UAAM,SAAS,kBAAkB,UAAU;AAC3C,UAAM,WAAW,CAAC,MAAMD,gBAAe,SAAS,UAAU,GAAG,GAAG,WAAW,UAAU;AACrF,WAAO,CAAC;AAAA,MACN;AAAA,MAAQ;AAAA,MAAU,QAAQ;AAAA,MAAgB;AAAA,IAC5C,CAAC;AAAA,EACH;AACF;AA3BE,cAVW,wBAUc,iBAAgB,CAAC,kCAAkC;AAC5E,cAXW,wBAWc,uBAAsB;AAXpC,yBAAN;AAAA,EADNE,iBAAgB;AAAA,GACJ;AAwCb,IAAM,oBAAoB,CAAC,eAA4C;AACrE,SAAO,WAAW,OAAO,CAAC,KAAK,cAAc,MAAM,UAAU,OAAO,CAAC;AACvE;;;AIhEA,SAAS,YAAAC,iBAAgB;AAEzB,SAAS,mBAAAC,wBAAuB;AAChC;AAAA,EACE,qBAAAC;AAAA,OACK;AACP,SAAS,mBAAAC,wBAAuB;AAChC,SAAS,kBAAAC,uBAAsB;AAC/B;AAAA,EAEE,cAAAC;AAAA,EACA,cAAAC;AAAA,EACA;AAAA,EAA6E;AAAA,OACxE;AASA,IAAM,sBAAN,cASGC,iBAAgD;AAAA,EAIxD,MAAgB,cAAc,WAAkB,CAAC,GAAoB;AACnE,UAAM,kBAAkB,MAAM,KAAK,0BAA0B;AAC7D,UAAM,iBAAiB,MAAM,gBAAgB,OAAO,QAAQ;AAC5D,UAAM,WAAW,eAAe,KAAKC,WAAU;AAC/C,QAAI,CAAC,SAAU,QAAO,CAAC;AACvB,UAAM,kBAAkB,MAAM,KAAK,2BAA2B;AAC9D,UAAM,iBAAiB,MAAM,gBAAgB,OAAO,QAAQ;AAC5D,UAAM,WAAW,eAAe,KAAKC,WAAU;AAC/C,QAAI,CAAC,SAAU,QAAO,CAAC;AACvB,UAAM,EAAE,UAAU,iBAAiB,IAAI;AACvC,UAAM,EAAE,UAAU,iBAAiB,IAAI;AACvC,IAAAC,UAAS,qBAAqB,kBAAkB,MAAM,qBAAqB,gBAAgB,qCAAqC,gBAAgB,EAAE;AAClJ,UAAM,SAAS,KAAK,IAAI,GAAG,SAAS,SAAS,SAAS,MAAM;AAC5D,UAAMC,YAAW;AACjB,UAAM,WAAW,CAAC,MAAMC,gBAAe,SAAS,QAAQ,GAAG,MAAMA,gBAAe,SAAS,QAAQ,CAAC;AAClG,UAAM,QAAe;AAAA,MACnB;AAAA,MAAQ,UAAAD;AAAA,MAAU;AAAA,MAAU,QAAQ;AAAA,IACtC;AACA,WAAO,CAAC,UAAU,UAAU,KAAK;AAAA,EACnC;AAAA,EAEA,MAAgB,6BAA8D;AAC5E,UAAM,OAAOD,UAAS,KAAK,OAAO,wBAAwB,MAAM,0CAA0C;AAC1G,UAAM,MAAMA,UAAS,MAAM,KAAK,QAAQ,IAAI,GAAG,MAAM,2CAA2C,IAAI,EAAE;AACtG,WAAOA,UAASG,mBAAkB,GAAG,GAAG,MAAM,mBAAmB,IAAI,OAAO,sBAAsB;AAAA,EACpG;AAAA,EAEA,MAAgB,4BAA6D;AAC3E,UAAM,OAAOH,UAAS,KAAK,OAAO,wBAAwB,MAAM,0CAA0C;AAC1G,UAAM,MAAMA,UAAS,MAAM,KAAK,QAAQ,IAAI,GAAG,MAAM,2CAA2C,IAAI,EAAE;AACtG,WAAOA,UAASG,mBAAkB,GAAG,GAAG,MAAM,mBAAmB,IAAI,OAAO,sBAAsB;AAAA,EACpG;AACF;AAnCE,cAVW,qBAUc,iBAAgB,CAAC,+BAA+B;AACzE,cAXW,qBAWc,uBAAuD;AAXrE,sBAAN;AAAA,EADNC,iBAAgB;AAAA,GACJ;","names":["assertEx","exists","PayloadBuilder","isCondition","currency","PayloadBuilder","exists","assertEx","isCondition","PayloadBuilder","currency","AbstractDiviner","isHashLeaseEstimate","creatableModule","PayloadBuilder","isEscrowTerms","currency","AbstractDiviner","isEscrowTerms","PayloadBuilder","isHashLeaseEstimate","creatableModule","assertEx","AbstractDiviner","asDivinerInstance","creatableModule","PayloadBuilder","isDiscount","isSubtotal","AbstractDiviner","isSubtotal","isDiscount","assertEx","currency","PayloadBuilder","asDivinerInstance","creatableModule"]}
1
+ {"version":3,"sources":["../../src/Discount/Diviner.ts","../../src/Discount/lib/applyCoupons.ts","../../src/Discount/lib/findUnfulfilledConditions.ts","../../src/Invoice/getInvoiceForEscrow.ts","../../src/Subtotal/Diviner.ts","../../src/Subtotal/lib/appraisalValidators.ts","../../src/Subtotal/lib/durationValidators.ts","../../src/Subtotal/lib/termsValidators.ts","../../src/Total/Diviner.ts"],"sourcesContent":["import {\n Address, assertEx, exists, filterAs, Hash,\n} from '@xylabs/sdk-js'\nimport { ArchivistInstance, asArchivistInstance } from '@xyo-network/archivist-model'\nimport { AbstractDiviner } from '@xyo-network/diviner-abstract'\nimport { BoundWitnessDivinerQueryPayload, BoundWitnessDivinerQuerySchema } from '@xyo-network/diviner-boundwitness-model'\nimport {\n HashLeaseEstimate,\n isHashLeaseEstimate,\n} from '@xyo-network/diviner-hash-lease'\nimport {\n asDivinerInstance, DivinerInstance, DivinerModuleEventData,\n} from '@xyo-network/diviner-model'\nimport { creatableModule } from '@xyo-network/module-model'\nimport { Payload } from '@xyo-network/payload-model'\nimport {\n asCondition,\n asCoupon,\n Condition,\n Coupon,\n Discount,\n EscrowTerms, isCondition, isCoupon,\n isEscrowTerms, NO_DISCOUNT, PaymentDiscountDivinerConfigSchema, PaymentDiscountDivinerParams,\n} from '@xyo-network/payment-payload-plugins'\nimport { PayloadBuilder } from '@xyo-network/sdk-js'\n\nimport { applyCoupons, areConditionsFulfilled } from './lib/index.ts'\n\nconst DEFAULT_BOUND_WITNESS_DIVINER_QUERY_PROPS: Readonly<BoundWitnessDivinerQueryPayload> = {\n limit: 1,\n order: 'desc',\n schema: BoundWitnessDivinerQuerySchema,\n}\n\nexport type PaymentDiscountDivinerInputType = EscrowTerms | Coupon | HashLeaseEstimate | Payload\n\n@creatableModule()\nexport class PaymentDiscountDiviner<\n TParams extends PaymentDiscountDivinerParams = PaymentDiscountDivinerParams,\n TIn extends PaymentDiscountDivinerInputType = PaymentDiscountDivinerInputType,\n TOut extends Discount = Discount,\n TEventData extends DivinerModuleEventData<DivinerInstance<TParams, TIn, TOut>, TIn, TOut> = DivinerModuleEventData<\n DivinerInstance<TParams, TIn, TOut>,\n TIn,\n TOut\n >,\n> extends AbstractDiviner<TParams, TIn, TOut, TEventData> {\n static override readonly configSchemas = [PaymentDiscountDivinerConfigSchema]\n static override readonly defaultConfigSchema = PaymentDiscountDivinerConfigSchema\n\n protected get couponAuthorities(): Address[] {\n return [...(this.config.couponAuthorities ?? []), ...(this.params.couponAuthorities ?? [])]\n }\n\n protected async divineHandler(payloads: TIn[] = []): Promise<TOut[]> {\n const $sources: Hash[] = []\n\n // Parse terms\n const terms = payloads.find(isEscrowTerms) as EscrowTerms | undefined\n if (!terms) return [{ ...NO_DISCOUNT, $sources }] as TOut[]\n $sources.push(await PayloadBuilder.hash(terms))\n\n // Parse appraisals\n const termsAppraisals = terms?.appraisals\n // If the escrow terms do not have appraisals, return no discount\n if (!termsAppraisals || termsAppraisals.length === 0) return [{ ...NO_DISCOUNT, $sources }] as TOut[]\n const hashMap = await PayloadBuilder.toAllHashMap(payloads) as Record<Hash, Payload>\n const appraisals = this.getEscrowAppraisals(terms, hashMap)\n // Add the appraisals that were found to the sources\n $sources.push(...termsAppraisals)\n // If not all appraisals are found, return no discount\n if (appraisals.length !== termsAppraisals.length) return [{ ...NO_DISCOUNT, $sources }] as TOut[]\n\n // Parse coupons\n const [coupons, conditions] = await this.getEscrowDiscounts(terms, hashMap)\n // Add the coupons that were found to the sources\n // TODO: Should we throw if not all coupons are found?\n const couponHashes = await PayloadBuilder.hashes(coupons)\n $sources.push(...couponHashes)\n\n const currentCoupons = coupons.filter(this.isCouponCurrent)\n const conditionsMetCoupons = (\n await Promise.all(currentCoupons.map(async coupon => await areConditionsFulfilled(coupon, conditions, payloads) ? coupon : undefined))).filter(exists)\n\n const validCoupons = await this.filterToSigned(conditionsMetCoupons)\n // TODO: Should we throw if not all coupons are valid?\n if (validCoupons.length === 0) return [{ ...NO_DISCOUNT, $sources }] as TOut[]\n\n // TODO: Call paymentSubtotalDiviner to get the subtotal to centralize the logic\n const discount = applyCoupons(appraisals, validCoupons)\n return [{ ...discount, $sources }] as TOut[]\n }\n\n /**\n * Filters the supplied list of coupons to only those that are signed by\n * addresses specified in the couponAuthorities\n * @param coupons The list of coupons to filter\n * @returns The filtered list of coupons that are signed by the couponAuthorities\n */\n protected async filterToSigned(coupons: Coupon[]): Promise<Coupon[]> {\n const signed: Coupon[] = []\n const dataHashMap = await PayloadBuilder.toDataHashMap(coupons)\n const boundWitnessDiviner = await this.getDiscountsBoundWitnessDiviner()\n const hashes = Object.keys(dataHashMap)\n const addresses = this.couponAuthorities\n // TODO: Keep an in memory cache of the hashes queried and their results\n // to avoid querying the same hash multiple times\n await Promise.all(hashes.map((h) => {\n const hash = h as Hash\n return Promise.all(addresses.map(async (address) => {\n const query: BoundWitnessDivinerQueryPayload = {\n ...DEFAULT_BOUND_WITNESS_DIVINER_QUERY_PROPS, addresses: [address], payload_hashes: [hash],\n }\n const result = await boundWitnessDiviner.divine([query])\n if (result.length > 0) signed.push(dataHashMap[hash])\n }))\n }))\n return signed\n }\n\n protected async getDiscountsArchivist(): Promise<ArchivistInstance> {\n const name = assertEx(this.config.archivist, () => 'Missing archivist in config')\n const mod = assertEx(await this.resolve(name), () => `Error resolving archivist: ${name}`)\n return assertEx(asArchivistInstance(mod), () => `Resolved module ${mod.address} not a valid Archivist`)\n }\n\n protected async getDiscountsBoundWitnessDiviner(): Promise<DivinerInstance> {\n const name = assertEx(this.config.boundWitnessDiviner, () => 'Missing boundWitnessDiviner in config')\n const mod = assertEx(await this.resolve(name), () => `Error resolving boundWitnessDiviner: ${name}`)\n return assertEx(asDivinerInstance(mod), () => `Resolved module ${mod.address} not a valid Diviner`)\n }\n\n /**\n * Finds the appraisals specified by the escrow terms from the supplied payloads\n * @param terms The escrow terms\n * @param payloads The payloads to search for the appraisals\n * @returns The appraisals found in the payloads\n */\n protected getEscrowAppraisals(terms: EscrowTerms, hashMap: Record<Hash, Payload>): HashLeaseEstimate[] {\n const hashes = terms?.appraisals ?? []\n if (hashes.length === 0) return []\n return hashes.map(hash => hashMap[hash]).filter(exists).filter(isHashLeaseEstimate)\n }\n\n /**\n * Finds the discounts specified by the escrow terms from the supplied payloads\n * @param terms The escrow terms\n * @param hashMap The payloads to search for the discounts\n * @returns A tuple containing all the escrow coupons and conditions referenced in those coupons\n * that were found in the either the supplied payloads or the archivist\n */\n protected async getEscrowDiscounts(terms: EscrowTerms, hashMap: Record<Hash, Payload>): Promise<[Coupon[], Condition[]]> {\n // Parse discounts\n const discountsHashes = terms.discounts ?? []\n if (discountsHashes.length === 0) return [[], []]\n\n // Use the supplied payloads to find the discounts\n const discounts: Coupon[] = discountsHashes.map(hash => hashMap[hash]).filter(exists).filter(isCoupon)\n const missingDiscounts = discountsHashes.filter(hash => !hashMap[hash])\n // If not all discounts are found\n if (missingDiscounts.length > 0) {\n // Find any remaining from discounts archivist\n const discountsArchivist = await this.getDiscountsArchivist()\n const payloads = await discountsArchivist.get(missingDiscounts)\n discounts.push(...filterAs(payloads, asCoupon))\n }\n // If not all discounts are found\n if (discounts.length !== discountsHashes.length) {\n const termsHash = await PayloadBuilder.hash(terms)\n const foundHashes = await PayloadBuilder.hashes(discounts)\n // Log individual discounts that were not found\n for (const hash of discountsHashes) {\n if (!foundHashes.includes(hash)) console.warn(`Discount ${hash} not found for terms ${termsHash}`)\n }\n }\n\n const conditionsHashes: Hash[] = discounts.flatMap(discount => discount.conditions ?? [])\n const conditions: Condition[] = conditionsHashes.map(hash => hashMap[hash]).filter(exists).filter(isCondition)\n const missingConditions = conditionsHashes.filter(hash => !hashMap[hash])\n\n // If not all conditions are found\n if (missingConditions.length > 0) {\n // Find any remaining from discounts archivist\n const discountsArchivist = await this.getDiscountsArchivist()\n const payloads = await discountsArchivist.get(missingConditions)\n conditions.push(...filterAs(payloads, asCondition))\n }\n // If not all conditions are found\n if (conditions.length !== conditionsHashes.length) {\n const termsHash = await PayloadBuilder.hash(terms)\n const foundHashes = await PayloadBuilder.hashes(conditions)\n // Log individual conditions that were not found\n for (const hash of discountsHashes) {\n if (!foundHashes.includes(hash)) console.warn(`Coupon condition ${hash} not found for terms ${termsHash}`)\n }\n }\n\n return [discounts, conditions]\n }\n\n protected isCouponCurrent(coupon: Coupon): boolean {\n const now = Date.now()\n return coupon.exp > now && coupon.nbf < now\n }\n}\n","import { assertEx, exists } from '@xylabs/sdk-js'\nimport type { HashLeaseEstimate } from '@xyo-network/diviner-hash-lease'\nimport type {\n AmountFields,\n Coupon, Discount, FixedAmountCoupon,\n FixedPercentageCoupon,\n FixedPriceCoupon,\n} from '@xyo-network/payment-payload-plugins'\nimport {\n DiscountSchema,\n isFixedAmountCoupon, isFixedPercentageCoupon,\n isFixedPriceCoupon,\n isStackable,\n} from '@xyo-network/payment-payload-plugins'\n\nexport const applyCoupons = (appraisals: HashLeaseEstimate[], coupons: Coupon[]): Discount => {\n // Ensure all appraisals and coupons are in USD\n const allAppraisalsAreUSD = appraisals.every(appraisal => appraisal.currency === 'USD')\n assertEx(allAppraisalsAreUSD, () => 'All appraisals must be in USD')\n const allCouponsAreUSD = coupons.map(coupon => (coupon as Partial<AmountFields>)?.currency).filter(exists).every(currency => currency === 'USD')\n assertEx(allCouponsAreUSD, () => 'All coupons must be in USD')\n const total = appraisals.reduce((acc, appraisal) => acc + appraisal.price, 0)\n\n // Calculated non-stackable discount coupons\n const singularFixedDiscount = Math.max(...coupons\n .filter(coupon => isFixedAmountCoupon(coupon) && !isStackable(coupon))\n .map(coupon => (coupon as FixedAmountCoupon).amount), 0)\n const singularPercentageDiscount = (Math.max(...coupons\n .filter(coupon => isFixedPercentageCoupon(coupon) && !isStackable(coupon))\n .map(coupon => (coupon as FixedPercentageCoupon).percentage), 0)) * total\n const singularFixedPriceDiscount = calculateSingularFixedPriceDiscount(total, appraisals, coupons, false)\n\n // Calculate stackable discount coupons\n // First calculate the total discount from fixed amount coupons\n const stackedFixedDiscount = coupons\n .filter(coupon => isFixedAmountCoupon(coupon) && isStackable(coupon))\n .reduce((acc, coupon) => acc + (coupon as FixedAmountCoupon).amount, 0)\n // Then calculate the total discount from percentage coupons and apply\n // the percentage discount to the remaining total after fixed discounts\n const stackedPercentageDiscount = coupons\n .filter(coupon => isFixedPercentageCoupon(coupon) && isStackable(coupon))\n .reduce((acc, coupon) => acc + (coupon as FixedPercentageCoupon).percentage, 0) * (total - stackedFixedDiscount)\n // Then calculate the total discount from fixed price coupons\n const stackedFixedPriceDiscount = calculateSingularFixedPriceDiscount(total, appraisals, coupons, true)\n\n // Sum all stackable discounts\n const stackedDiscount = stackedFixedDiscount + stackedPercentageDiscount + stackedFixedPriceDiscount\n\n // Find the best coupon(s) to apply\n const maxDiscount = Math.max(\n singularFixedDiscount,\n singularFixedPriceDiscount,\n singularPercentageDiscount,\n stackedDiscount,\n 0,\n )\n\n // Ensure discount is not more than the total\n const amount = Math.min(maxDiscount, total)\n\n // Return single discount payload\n return {\n amount, schema: DiscountSchema, currency: 'USD',\n }\n}\n\nconst calculateSingularFixedPriceDiscount = (total: number, appraisals: HashLeaseEstimate[], coupons: Coupon[], stackable = false): number => {\n // Find all singular fixed price discounts\n const singularFixedPriceDiscounts = coupons\n .filter(isFixedPriceCoupon)\n .filter(coupon => stackable ? isStackable(coupon) : !isStackable(coupon))\n .map(coupon => (coupon as FixedPriceCoupon).amount)\n // Ensure all fixed price discounts are positive\n .filter(amount => amount > 0)\n\n // If there are no singular fixed price discounts, return no discount\n if (singularFixedPriceDiscounts.length === 0) return 0\n\n // Find the maximum discount (the lowest fixed price)\n const lowestFixedPrice = Math.min(...singularFixedPriceDiscounts)\n\n // Apply the fixed price to all appraisals to get the reduced prices\n const reducedPrices = appraisals.map(appraisal =>\n // If the appraisal price is less than the fixed price\n Math.min(appraisal.price, lowestFixedPrice))\n\n // Calculate the reduced total using the reduced prices\n const reducedTotal = reducedPrices.reduce((acc, price) => acc + price, 0)\n\n // Calculate the discount\n const discount = total - reducedTotal\n\n // Return the discount or 0 if the discount would have resulted in a negative value\n return Math.max(discount, 0)\n}\n","import type { Hash } from '@xylabs/sdk-js'\nimport type { Payload } from '@xyo-network/payload-model'\nimport type { Condition, Coupon } from '@xyo-network/payment-payload-plugins'\nimport { isCondition } from '@xyo-network/payment-payload-plugins'\nimport type { SchemaPayload } from '@xyo-network/schema-payload-plugin'\nimport { isSchemaPayload } from '@xyo-network/schema-payload-plugin'\nimport { PayloadBuilder } from '@xyo-network/sdk-js'\nimport type { ValidateFunction } from 'ajv'\nimport { Ajv } from 'ajv'\n\n// TODO: Use our schema cache\nconst ajv = new Ajv({ strict: false }) // Create the Ajv instance once\nconst schemaCache = new Map() // Cache to store compiled validators\n\n/**\n * Validates the conditions of a coupon against the provided payloads\n * @param coupon The coupon to check\n * @param conditions The conditions associated with the coupon\n * @param payloads The associated payloads (containing the conditions and data to validate the conditions against)\n * @returns True if all conditions are fulfilled, false otherwise\n */\nexport const areConditionsFulfilled = async (coupon: Coupon, conditions: Condition[] = [], payloads: Payload[] = []): Promise<boolean> =>\n (await findUnfulfilledConditions(coupon, conditions, payloads)).length === 0\n\n/**\n * Validates the conditions of a coupon against the provided payloads\n * @param coupon The coupon to check\n * @param conditions The conditions associated with the coupon\n * @param payloads The associated payloads (containing the conditions and data to validate the conditions against)\n * @returns The unfulfilled condition hashes\n */\nexport const findUnfulfilledConditions = async (coupon: Coupon, conditions: Condition[] = [], payloads: Payload[] = []): Promise<Hash[]> => {\n const unfulfilledConditions: Hash[] = []\n // If there are no conditions, then they are fulfilled\n if (!coupon.conditions || coupon.conditions.length === 0) return unfulfilledConditions\n const hashMap = await PayloadBuilder.toAllHashMap([...conditions, ...payloads])\n // Find all the conditions\n const foundConditions = coupon.conditions.map(hash => hashMap[hash]).filter(isCondition)\n // Not all conditions were found\n if (foundConditions.length !== coupon.conditions.length) {\n const missing = coupon.conditions.filter(hash => !hashMap[hash])\n unfulfilledConditions.push(...missing)\n return unfulfilledConditions\n }\n\n // Test each condition\n for (const hash of coupon.conditions) {\n let validator: ValidateFunction\n\n // Check if the schema is already cached\n if (schemaCache.has(hash)) {\n validator = schemaCache.get(hash)\n } else {\n const payload = hashMap[hash]\n const definition = isSchemaPayload(payload) ? (payload as SchemaPayload).definition : undefined\n if (definition) {\n // Compile and cache the validator\n validator = ajv.compile(definition)\n schemaCache.set(hash, validator)\n\n // Validate the payload\n } else {\n unfulfilledConditions.push(hash)\n continue\n }\n }\n if (!validator(payloads)) unfulfilledConditions.push(hash)\n }\n\n // All conditions passed\n return unfulfilledConditions\n}\n","import type { Hash } from '@xylabs/sdk-js'\nimport type { DivinerInstance } from '@xyo-network/diviner-model'\nimport type { Payload } from '@xyo-network/payload-model'\nimport type {\n Discount, EscrowTerms, Invoice, Payment,\n Subtotal, Total,\n} from '@xyo-network/payment-payload-plugins'\nimport {\n isDiscount, isSubtotal, isTotal, PaymentSchema,\n} from '@xyo-network/payment-payload-plugins'\nimport { PayloadBuilder } from '@xyo-network/sdk-js'\n\n/**\n * Validates the escrow terms to ensure they are valid for a purchase\n * @returns A payment if the terms are valid for a purchase, undefined otherwise\n */\nexport const getInvoiceForEscrow = async (\n terms: EscrowTerms,\n dataHashMap: Record<Hash, Payload>,\n paymentTotalDiviner: DivinerInstance,\n): Promise<Invoice | undefined> => {\n const payloads = Object.values(dataHashMap)\n const results = await paymentTotalDiviner.divine([terms, ...payloads])\n const subtotal = results.find(isSubtotal) as Subtotal | undefined\n const discount = results.find(isDiscount) as Discount | undefined\n const total = results.find(isTotal) as Total | undefined\n if (!subtotal || !total) return undefined\n const { amount, currency } = total\n if (currency !== 'USD') return undefined\n const $sources = await getSources(terms, subtotal, total, discount)\n const payment: Payment = {\n amount, currency, schema: PaymentSchema, $sources,\n }\n return discount ? [subtotal, total, payment, discount] : [subtotal, total, payment]\n}\n\nconst getSources = async (terms: EscrowTerms, subtotal: Subtotal, total: Total, discount?: Discount): Promise<Hash[]> => {\n const sources = discount ? [terms, subtotal, total, discount] : [terms, subtotal, total]\n return await Promise.all(sources.map(p => PayloadBuilder.dataHash(p)))\n}\n","import { AbstractDiviner } from '@xyo-network/diviner-abstract'\nimport { HashLeaseEstimate, isHashLeaseEstimate } from '@xyo-network/diviner-hash-lease'\nimport { DivinerInstance, DivinerModuleEventData } from '@xyo-network/diviner-model'\nimport { creatableModule } from '@xyo-network/module-model'\nimport { Payload } from '@xyo-network/payload-model'\nimport {\n EscrowTerms, isEscrowTerms, PaymentSubtotalDivinerConfigSchema, PaymentSubtotalDivinerParams, Subtotal, SubtotalSchema,\n} from '@xyo-network/payment-payload-plugins'\nimport { PayloadBuilder } from '@xyo-network/sdk-js'\n\nimport {\n appraisalValidators, termsValidators, ValidEscrowTerms,\n} from './lib/index.ts'\n\nconst currency = 'USD'\n\n/**\n * Escrow terms that contain all the valid fields for calculating a subtotal\n */\nexport type PaymentSubtotalDivinerInputType = EscrowTerms | HashLeaseEstimate | Payload\n\n@creatableModule()\nexport class PaymentSubtotalDiviner<\n TParams extends PaymentSubtotalDivinerParams = PaymentSubtotalDivinerParams,\n TIn extends PaymentSubtotalDivinerInputType = PaymentSubtotalDivinerInputType,\n TOut extends Subtotal = Subtotal,\n TEventData extends DivinerModuleEventData<DivinerInstance<TParams, TIn, TOut>, TIn, TOut> = DivinerModuleEventData<\n DivinerInstance<TParams, TIn, TOut>,\n TIn,\n TOut\n >,\n> extends AbstractDiviner<TParams, TIn, TOut, TEventData> {\n static override readonly configSchemas = [PaymentSubtotalDivinerConfigSchema]\n static override readonly defaultConfigSchema = PaymentSubtotalDivinerConfigSchema\n\n protected async divineHandler(payloads: TIn[] = []): Promise<TOut[]> {\n // Find the escrow terms\n const terms = payloads.find(isEscrowTerms) as EscrowTerms | undefined\n if (!terms) return []\n\n // Run all terms validations\n if (!termsValidators.every(validator => validator(terms))) return []\n const validTerms = terms as ValidEscrowTerms\n\n // Retrieve all appraisals from terms\n const hashMap = await PayloadBuilder.toAllHashMap(payloads)\n const appraisals = validTerms.appraisals.map(appraisal => hashMap[appraisal]).filter(isHashLeaseEstimate) as unknown as HashLeaseEstimate[]\n\n // Ensure all appraisals are present\n if (appraisals.length !== validTerms.appraisals.length) return []\n\n // Run all appraisal validations\n if (!appraisalValidators.every(validator => validator(appraisals))) return []\n const amount = calculateSubtotal(appraisals)\n const $sources = [await PayloadBuilder.dataHash(validTerms), ...validTerms.appraisals]\n return [{\n amount, currency, schema: SubtotalSchema, $sources,\n }] as TOut[]\n }\n}\n\n// TODO: Add support for other currencies\nconst calculateSubtotal = (appraisals: HashLeaseEstimate[]): number => {\n return appraisals.reduce((sum, appraisal) => sum + appraisal.price, 0)\n}\n","import type { HashLeaseEstimate } from '@xyo-network/diviner-hash-lease'\nimport { isIso4217CurrencyCode } from '@xyo-network/payment-payload-plugins'\n\nimport { validateDuration } from './durationValidators.ts'\n\nconst validateAppraisalAmount = (appraisals: HashLeaseEstimate[]): boolean => {\n // Ensure all appraisals are numeric\n if (appraisals.some(appraisal => typeof appraisal.price !== 'number')) return false\n // Ensure all appraisals are positive numbers\n return !(appraisals.some(appraisal => appraisal.price < 0))\n}\n\nconst validateAppraisalCurrency = (appraisals: HashLeaseEstimate[]): boolean => {\n // Only supporting USD for now, the remaining checks are for future-proofing.\n if (!appraisals.every(appraisal => appraisal.currency == 'USD')) return false\n\n // Check every object in the array to ensure they all are in a supported currency.\n return (appraisals.every(appraisal => isIso4217CurrencyCode(appraisal.currency)))\n}\n\nconst validateAppraisalConsistentCurrency = (appraisals: HashLeaseEstimate[]): boolean => {\n // Check if the array is empty or contains only one element, no need to compare.\n if (appraisals.length <= 1) return true\n\n // Get the currency of the first element to compare with others.\n const { currency } = appraisals[0]\n if (!currency) return false\n\n // Check every object in the array to ensure they all have the same currency.\n return (appraisals.every(item => item.currency === currency))\n}\n\nconst validateAppraisalWindow = (appraisals: HashLeaseEstimate[]): boolean => appraisals.every(validateDuration)\n\nexport const appraisalValidators = [\n validateAppraisalAmount,\n validateAppraisalCurrency,\n validateAppraisalConsistentCurrency,\n validateAppraisalWindow,\n]\n","import type { DurationFields } from '@xyo-network/xns-record-payload-plugins'\n\nconst FIVE_MINUTES = 1000 * 60 * 5\n\n/**\n * Validates that the current time is within the duration window, within a configurable a buffer\n * @param value The duration value\n * @param windowMs The window in milliseconds to allow for a buffer\n * @returns True if the duration is valid, false otherwise\n */\nexport const validateDuration = (value: Partial<DurationFields>, windowMs = FIVE_MINUTES): boolean => {\n const now = Date.now()\n if (!value.nbf || value.nbf > now) return false\n // If already expired (include for a 5 minute buffer to allow for a reasonable\n // minimum amount of time for the transaction to be processed)\n return !(!value.exp || value.exp - now < windowMs)\n}\n","import type { Hash } from '@xylabs/sdk-js'\nimport type { EscrowTerms } from '@xyo-network/payment-payload-plugins'\n\nimport { validateDuration } from './durationValidators.ts'\n\nexport type ValidEscrowTerms = Required<EscrowTerms>\n\nconst validateTermsAppraisals = (terms: EscrowTerms): terms is Required<EscrowTerms & { appraisals: Hash[] }> => {\n if (!terms.appraisals) return false\n return terms.appraisals.length > 0\n}\nconst validateTermsWindow = (terms: EscrowTerms): boolean => validateDuration(terms)\n\nexport const termsValidators = [\n validateTermsAppraisals,\n validateTermsWindow,\n]\n","import { assertEx, Hash } from '@xylabs/sdk-js'\nimport { AbstractDiviner } from '@xyo-network/diviner-abstract'\nimport {\n asDivinerInstance, DivinerInstance, DivinerModuleEventData,\n} from '@xyo-network/diviner-model'\nimport { creatableModule } from '@xyo-network/module-model'\nimport {\n Discount,\n isDiscount,\n isSubtotal,\n PaymentTotalDivinerConfigSchema, PaymentTotalDivinerParams, Subtotal, Total, TotalSchema,\n} from '@xyo-network/payment-payload-plugins'\nimport { PayloadBuilder } from '@xyo-network/sdk-js'\n\nimport { PaymentDiscountDiviner, PaymentDiscountDivinerInputType } from '../Discount/index.ts'\nimport { PaymentSubtotalDiviner, PaymentSubtotalDivinerInputType } from '../Subtotal/index.ts'\n\ntype InputType = PaymentDiscountDivinerInputType | PaymentSubtotalDivinerInputType\ntype OutputType = Subtotal | Discount | Total\n\n@creatableModule()\nexport class PaymentTotalDiviner<\n TParams extends PaymentTotalDivinerParams = PaymentTotalDivinerParams,\n TIn extends InputType = InputType,\n TOut extends OutputType = OutputType,\n TEventData extends DivinerModuleEventData<DivinerInstance<TParams, TIn, TOut>, TIn, TOut> = DivinerModuleEventData<\n DivinerInstance<TParams, TIn, TOut>,\n TIn,\n TOut\n >,\n> extends AbstractDiviner<TParams, TIn, TOut, TEventData> {\n static override readonly configSchemas = [PaymentTotalDivinerConfigSchema]\n static override readonly defaultConfigSchema: PaymentTotalDivinerConfigSchema = PaymentTotalDivinerConfigSchema\n\n protected async divineHandler(payloads: TIn[] = []): Promise<TOut[]> {\n const subtotalDiviner = await this.getPaymentSubtotalDiviner()\n const subtotalResult = await subtotalDiviner.divine(payloads)\n const subtotal = subtotalResult.find(isSubtotal)\n if (!subtotal) return []\n const discountDiviner = await this.getPaymentDiscountsDiviner()\n const discountResult = await discountDiviner.divine(payloads)\n const discount = discountResult.find(isDiscount)\n if (!discount) return []\n const { currency: subtotalCurrency } = subtotal\n const { currency: discountCurrency } = discount\n assertEx(subtotalCurrency === discountCurrency, () => `Subtotal currency ${subtotalCurrency} does not match discount currency ${discountCurrency}`)\n const amount = Math.max(0, subtotal.amount - discount.amount)\n const currency = subtotalCurrency\n const $sources = [await PayloadBuilder.dataHash(subtotal), await PayloadBuilder.dataHash(discount)] as Hash[]\n const total: Total = {\n amount, currency, $sources, schema: TotalSchema,\n }\n return [subtotal, discount, total] as TOut[]\n }\n\n protected async getPaymentDiscountsDiviner(): Promise<PaymentDiscountDiviner> {\n const name = assertEx(this.config.paymentDiscountDiviner, () => 'Missing paymentDiscountDiviner in config')\n const mod = assertEx(await this.resolve(name), () => `Error resolving paymentDiscountDiviner: ${name}`)\n return assertEx(asDivinerInstance(mod), () => `Resolved module ${mod.address} not a valid Diviner`) as PaymentDiscountDiviner\n }\n\n protected async getPaymentSubtotalDiviner(): Promise<PaymentSubtotalDiviner> {\n const name = assertEx(this.config.paymentSubtotalDiviner, () => 'Missing paymentSubtotalDiviner in config')\n const mod = assertEx(await this.resolve(name), () => `Error resolving paymentSubtotalDiviner: ${name}`)\n return assertEx(asDivinerInstance(mod), () => `Resolved module ${mod.address} not a valid Diviner`) as PaymentSubtotalDiviner\n }\n}\n"],"mappings":"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","names":["assertEx","exists","isCondition","PayloadBuilder","currency","PayloadBuilder","exists","assertEx","isCondition","PayloadBuilder","currency","AbstractDiviner","isHashLeaseEstimate","creatableModule","isEscrowTerms","PayloadBuilder","currency","AbstractDiviner","isEscrowTerms","PayloadBuilder","isHashLeaseEstimate","creatableModule","assertEx","AbstractDiviner","asDivinerInstance","creatableModule","isDiscount","isSubtotal","PayloadBuilder","AbstractDiviner","isSubtotal","isDiscount","assertEx","currency","PayloadBuilder","asDivinerInstance","creatableModule"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xyo-network/payment-plugin",
3
- "version": "5.3.1",
3
+ "version": "5.3.3",
4
4
  "description": "Typescript/Javascript Plugins for XYO Platform",
5
5
  "homepage": "https://xyo.network",
6
6
  "bugs": {
@@ -30,42 +30,57 @@
30
30
  "types": "dist/neutral/index.d.ts",
31
31
  "files": [
32
32
  "dist",
33
- "src",
34
- "!**/*.bench.*",
35
- "!**/*.spec.*",
36
- "!**/*.test.*"
33
+ "README.md"
37
34
  ],
38
35
  "dependencies": {
39
- "@xylabs/array": "~5.0.64",
40
- "@xylabs/assert": "~5.0.64",
41
- "@xylabs/exists": "~5.0.64",
42
- "@xylabs/hex": "~5.0.64",
43
- "@xyo-network/archivist-model": "~5.3.2",
44
- "@xyo-network/diviner-abstract": "~5.3.2",
45
- "@xyo-network/diviner-boundwitness-model": "~5.3.2",
46
- "@xyo-network/diviner-hash-lease": "~5.3.2",
47
- "@xyo-network/diviner-model": "~5.3.2",
48
- "@xyo-network/module-model": "~5.3.2",
49
- "@xyo-network/payload-builder": "~5.3.2",
50
- "@xyo-network/payload-model": "~5.3.2",
51
- "@xyo-network/payment-payload-plugins": "5.3.1",
52
- "@xyo-network/schema-payload-plugin": "~5.3.2",
53
- "@xyo-network/xns-record-payload-plugins": "5.3.1",
54
- "ajv": "~8.17.1"
36
+ "@xyo-network/payment-payload-plugins": "workspace:^",
37
+ "@xyo-network/xns-record-payload-plugins": "workspace:^"
55
38
  },
56
39
  "devDependencies": {
57
- "@xylabs/ts-scripts-yarn3": "~7.3.2",
58
- "@xylabs/tsconfig": "~7.3.2",
59
- "@xylabs/vitest-extended": "~5.0.64",
60
- "@xyo-network/archivist-memory": "~5.3.2",
61
- "@xyo-network/boundwitness-builder": "~5.3.2",
62
- "@xyo-network/diviner-boundwitness-memory": "~5.3.2",
63
- "@xyo-network/id-payload-plugin": "~5.3.2",
64
- "@xyo-network/node-memory": "~5.3.2",
65
- "@xyo-network/wallet": "~5.3.2",
66
- "@xyo-network/wallet-model": "~5.3.2",
40
+ "@xylabs/sdk-js": "^5.0.90",
41
+ "@xylabs/ts-scripts-common": "~7.5.10",
42
+ "@xylabs/ts-scripts-yarn3": "~7.5.10",
43
+ "@xylabs/tsconfig": "~7.5.10",
44
+ "@xylabs/vitest-extended": "~5.0.90",
45
+ "@xyo-network/archivist-memory": "~5.3.5",
46
+ "@xyo-network/archivist-model": "~5.3.5",
47
+ "@xyo-network/boundwitness-builder": "~5.3.5",
48
+ "@xyo-network/boundwitness-model": "~5.3.5",
49
+ "@xyo-network/diviner-abstract": "~5.3.5",
50
+ "@xyo-network/diviner-boundwitness-memory": "~5.3.5",
51
+ "@xyo-network/diviner-boundwitness-model": "~5.3.5",
52
+ "@xyo-network/diviner-hash-lease": "~5.3.5",
53
+ "@xyo-network/diviner-model": "~5.3.5",
54
+ "@xyo-network/id-payload-plugin": "~5.3.5",
55
+ "@xyo-network/module-model": "~5.3.5",
56
+ "@xyo-network/node-memory": "~5.3.5",
57
+ "@xyo-network/payload-model": "~5.3.5",
58
+ "@xyo-network/rebilly-payment-payload-plugin": "~5.3.3",
59
+ "@xyo-network/schema-payload-plugin": "~5.3.5",
60
+ "@xyo-network/sdk-js": "~5.3.5",
61
+ "@xyo-network/sentinel-abstract": "~5.3.5",
62
+ "@xyo-network/sentinel-model": "~5.3.5",
63
+ "@xyo-network/wallet": "~5.3.5",
64
+ "@xyo-network/wallet-model": "~5.3.5",
65
+ "ajv": "~8.18.0",
66
+ "axios": "^1.13.5",
67
67
  "typescript": "~5.9.3",
68
- "vitest": "~4.0.18"
68
+ "vitest": "~4.1.2",
69
+ "zod": "^4.3.6"
70
+ },
71
+ "peerDependencies": {
72
+ "@xylabs/sdk-js": "^5",
73
+ "@xyo-network/archivist-model": "^5",
74
+ "@xyo-network/diviner-abstract": "^5",
75
+ "@xyo-network/diviner-boundwitness-model": "^5",
76
+ "@xyo-network/diviner-hash-lease": "^5",
77
+ "@xyo-network/diviner-model": "^5",
78
+ "@xyo-network/module-model": "^5",
79
+ "@xyo-network/payload-model": "^5",
80
+ "@xyo-network/schema-payload-plugin": "^5",
81
+ "@xyo-network/sdk-js": "^5",
82
+ "ajv": "^8",
83
+ "zod": "^4"
69
84
  },
70
85
  "publishConfig": {
71
86
  "access": "public"
@@ -1,206 +0,0 @@
1
- import { filterAs } from '@xylabs/array'
2
- import { assertEx } from '@xylabs/assert'
3
- import { exists } from '@xylabs/exists'
4
- import { Address, Hash } from '@xylabs/hex'
5
- import { ArchivistInstance, asArchivistInstance } from '@xyo-network/archivist-model'
6
- import { AbstractDiviner } from '@xyo-network/diviner-abstract'
7
- import { BoundWitnessDivinerQueryPayload, BoundWitnessDivinerQuerySchema } from '@xyo-network/diviner-boundwitness-model'
8
- import {
9
- HashLeaseEstimate,
10
- isHashLeaseEstimate,
11
- } from '@xyo-network/diviner-hash-lease'
12
- import {
13
- asDivinerInstance, DivinerInstance, DivinerModuleEventData,
14
- } from '@xyo-network/diviner-model'
15
- import { creatableModule } from '@xyo-network/module-model'
16
- import { PayloadBuilder } from '@xyo-network/payload-builder'
17
- import { Payload } from '@xyo-network/payload-model'
18
- import {
19
- asCondition,
20
- asCoupon,
21
- Condition,
22
- Coupon,
23
- Discount,
24
- EscrowTerms, isCondition, isCoupon,
25
- isEscrowTerms, NO_DISCOUNT, PaymentDiscountDivinerConfigSchema, PaymentDiscountDivinerParams,
26
- } from '@xyo-network/payment-payload-plugins'
27
-
28
- import { applyCoupons, areConditionsFulfilled } from './lib/index.ts'
29
-
30
- const DEFAULT_BOUND_WITNESS_DIVINER_QUERY_PROPS: Readonly<BoundWitnessDivinerQueryPayload> = {
31
- limit: 1,
32
- order: 'desc',
33
- schema: BoundWitnessDivinerQuerySchema,
34
- }
35
-
36
- export type PaymentDiscountDivinerInputType = EscrowTerms | Coupon | HashLeaseEstimate | Payload
37
-
38
- @creatableModule()
39
- export class PaymentDiscountDiviner<
40
- TParams extends PaymentDiscountDivinerParams = PaymentDiscountDivinerParams,
41
- TIn extends PaymentDiscountDivinerInputType = PaymentDiscountDivinerInputType,
42
- TOut extends Discount = Discount,
43
- TEventData extends DivinerModuleEventData<DivinerInstance<TParams, TIn, TOut>, TIn, TOut> = DivinerModuleEventData<
44
- DivinerInstance<TParams, TIn, TOut>,
45
- TIn,
46
- TOut
47
- >,
48
- > extends AbstractDiviner<TParams, TIn, TOut, TEventData> {
49
- static override readonly configSchemas = [PaymentDiscountDivinerConfigSchema]
50
- static override readonly defaultConfigSchema = PaymentDiscountDivinerConfigSchema
51
-
52
- protected get couponAuthorities(): Address[] {
53
- return [...(this.config.couponAuthorities ?? []), ...(this.params.couponAuthorities ?? [])]
54
- }
55
-
56
- protected async divineHandler(payloads: TIn[] = []): Promise<TOut[]> {
57
- const $sources: Hash[] = []
58
-
59
- // Parse terms
60
- const terms = payloads.find(isEscrowTerms) as EscrowTerms | undefined
61
- if (!terms) return [{ ...NO_DISCOUNT, $sources }] as TOut[]
62
- $sources.push(await PayloadBuilder.hash(terms))
63
-
64
- // Parse appraisals
65
- const termsAppraisals = terms?.appraisals
66
- // If the escrow terms do not have appraisals, return no discount
67
- if (!termsAppraisals || termsAppraisals.length === 0) return [{ ...NO_DISCOUNT, $sources }] as TOut[]
68
- const hashMap = await PayloadBuilder.toAllHashMap(payloads) as Record<Hash, Payload>
69
- const appraisals = this.getEscrowAppraisals(terms, hashMap)
70
- // Add the appraisals that were found to the sources
71
- $sources.push(...termsAppraisals)
72
- // If not all appraisals are found, return no discount
73
- if (appraisals.length !== termsAppraisals.length) return [{ ...NO_DISCOUNT, $sources }] as TOut[]
74
-
75
- // Parse coupons
76
- const [coupons, conditions] = await this.getEscrowDiscounts(terms, hashMap)
77
- // Add the coupons that were found to the sources
78
- // TODO: Should we throw if not all coupons are found?
79
- const couponHashes = await PayloadBuilder.hashes(coupons)
80
- $sources.push(...couponHashes)
81
-
82
- const currentCoupons = coupons.filter(this.isCouponCurrent)
83
- const conditionsMetCoupons = (
84
- await Promise.all(currentCoupons.map(async coupon => await areConditionsFulfilled(coupon, conditions, payloads) ? coupon : undefined))).filter(exists)
85
-
86
- const validCoupons = await this.filterToSigned(conditionsMetCoupons)
87
- // TODO: Should we throw if not all coupons are valid?
88
- if (validCoupons.length === 0) return [{ ...NO_DISCOUNT, $sources }] as TOut[]
89
-
90
- // TODO: Call paymentSubtotalDiviner to get the subtotal to centralize the logic
91
- const discount = applyCoupons(appraisals, validCoupons)
92
- return [{ ...discount, $sources }] as TOut[]
93
- }
94
-
95
- /**
96
- * Filters the supplied list of coupons to only those that are signed by
97
- * addresses specified in the couponAuthorities
98
- * @param coupons The list of coupons to filter
99
- * @returns The filtered list of coupons that are signed by the couponAuthorities
100
- */
101
- protected async filterToSigned(coupons: Coupon[]): Promise<Coupon[]> {
102
- const signed: Coupon[] = []
103
- const dataHashMap = await PayloadBuilder.toDataHashMap(coupons)
104
- const boundWitnessDiviner = await this.getDiscountsBoundWitnessDiviner()
105
- const hashes = Object.keys(dataHashMap)
106
- const addresses = this.couponAuthorities
107
- // TODO: Keep an in memory cache of the hashes queried and their results
108
- // to avoid querying the same hash multiple times
109
- await Promise.all(hashes.map((h) => {
110
- const hash = h as Hash
111
- return Promise.all(addresses.map(async (address) => {
112
- const query: BoundWitnessDivinerQueryPayload = {
113
- ...DEFAULT_BOUND_WITNESS_DIVINER_QUERY_PROPS, addresses: [address], payload_hashes: [hash],
114
- }
115
- const result = await boundWitnessDiviner.divine([query])
116
- if (result.length > 0) signed.push(dataHashMap[hash])
117
- }))
118
- }))
119
- return signed
120
- }
121
-
122
- protected async getDiscountsArchivist(): Promise<ArchivistInstance> {
123
- const name = assertEx(this.config.archivist, () => 'Missing archivist in config')
124
- const mod = assertEx(await this.resolve(name), () => `Error resolving archivist: ${name}`)
125
- return assertEx(asArchivistInstance(mod), () => `Resolved module ${mod.address} not a valid Archivist`)
126
- }
127
-
128
- protected async getDiscountsBoundWitnessDiviner(): Promise<DivinerInstance> {
129
- const name = assertEx(this.config.boundWitnessDiviner, () => 'Missing boundWitnessDiviner in config')
130
- const mod = assertEx(await this.resolve(name), () => `Error resolving boundWitnessDiviner: ${name}`)
131
- return assertEx(asDivinerInstance(mod), () => `Resolved module ${mod.address} not a valid Diviner`)
132
- }
133
-
134
- /**
135
- * Finds the appraisals specified by the escrow terms from the supplied payloads
136
- * @param terms The escrow terms
137
- * @param payloads The payloads to search for the appraisals
138
- * @returns The appraisals found in the payloads
139
- */
140
- protected getEscrowAppraisals(terms: EscrowTerms, hashMap: Record<Hash, Payload>): HashLeaseEstimate[] {
141
- const hashes = terms?.appraisals ?? []
142
- if (hashes.length === 0) return []
143
- return hashes.map(hash => hashMap[hash]).filter(exists).filter(isHashLeaseEstimate)
144
- }
145
-
146
- /**
147
- * Finds the discounts specified by the escrow terms from the supplied payloads
148
- * @param terms The escrow terms
149
- * @param hashMap The payloads to search for the discounts
150
- * @returns A tuple containing all the escrow coupons and conditions referenced in those coupons
151
- * that were found in the either the supplied payloads or the archivist
152
- */
153
- protected async getEscrowDiscounts(terms: EscrowTerms, hashMap: Record<Hash, Payload>): Promise<[Coupon[], Condition[]]> {
154
- // Parse discounts
155
- const discountsHashes = terms.discounts ?? []
156
- if (discountsHashes.length === 0) return [[], []]
157
-
158
- // Use the supplied payloads to find the discounts
159
- const discounts: Coupon[] = discountsHashes.map(hash => hashMap[hash]).filter(exists).filter(isCoupon)
160
- const missingDiscounts = discountsHashes.filter(hash => !hashMap[hash])
161
- // If not all discounts are found
162
- if (missingDiscounts.length > 0) {
163
- // Find any remaining from discounts archivist
164
- const discountsArchivist = await this.getDiscountsArchivist()
165
- const payloads = await discountsArchivist.get(missingDiscounts)
166
- discounts.push(...filterAs(payloads, asCoupon))
167
- }
168
- // If not all discounts are found
169
- if (discounts.length !== discountsHashes.length) {
170
- const termsHash = await PayloadBuilder.hash(terms)
171
- const foundHashes = await PayloadBuilder.hashes(discounts)
172
- // Log individual discounts that were not found
173
- for (const hash of discountsHashes) {
174
- if (!foundHashes.includes(hash)) console.warn(`Discount ${hash} not found for terms ${termsHash}`)
175
- }
176
- }
177
-
178
- const conditionsHashes: Hash[] = discounts.flatMap(discount => discount.conditions ?? [])
179
- const conditions: Condition[] = conditionsHashes.map(hash => hashMap[hash]).filter(exists).filter(isCondition)
180
- const missingConditions = conditionsHashes.filter(hash => !hashMap[hash])
181
-
182
- // If not all conditions are found
183
- if (missingConditions.length > 0) {
184
- // Find any remaining from discounts archivist
185
- const discountsArchivist = await this.getDiscountsArchivist()
186
- const payloads = await discountsArchivist.get(missingConditions)
187
- conditions.push(...filterAs(payloads, asCondition))
188
- }
189
- // If not all conditions are found
190
- if (conditions.length !== conditionsHashes.length) {
191
- const termsHash = await PayloadBuilder.hash(terms)
192
- const foundHashes = await PayloadBuilder.hashes(conditions)
193
- // Log individual conditions that were not found
194
- for (const hash of discountsHashes) {
195
- if (!foundHashes.includes(hash)) console.warn(`Coupon condition ${hash} not found for terms ${termsHash}`)
196
- }
197
- }
198
-
199
- return [discounts, conditions]
200
- }
201
-
202
- protected isCouponCurrent(coupon: Coupon): boolean {
203
- const now = Date.now()
204
- return coupon.exp > now && coupon.nbf < now
205
- }
206
- }
@@ -1,2 +0,0 @@
1
- export * from './Diviner.ts'
2
- export * from './lib/index.ts'
@@ -1,96 +0,0 @@
1
- import { assertEx } from '@xylabs/assert'
2
- import { exists } from '@xylabs/exists'
3
- import type { HashLeaseEstimate } from '@xyo-network/diviner-hash-lease'
4
- import type {
5
- AmountFields,
6
- Coupon, Discount, FixedAmountCoupon,
7
- FixedPercentageCoupon,
8
- FixedPriceCoupon,
9
- } from '@xyo-network/payment-payload-plugins'
10
- import {
11
- DiscountSchema,
12
- isFixedAmountCoupon, isFixedPercentageCoupon,
13
- isFixedPriceCoupon,
14
- isStackable,
15
- } from '@xyo-network/payment-payload-plugins'
16
-
17
- export const applyCoupons = (appraisals: HashLeaseEstimate[], coupons: Coupon[]): Discount => {
18
- // Ensure all appraisals and coupons are in USD
19
- const allAppraisalsAreUSD = appraisals.every(appraisal => appraisal.currency === 'USD')
20
- assertEx(allAppraisalsAreUSD, () => 'All appraisals must be in USD')
21
- const allCouponsAreUSD = coupons.map(coupon => (coupon as Partial<AmountFields>)?.currency).filter(exists).every(currency => currency === 'USD')
22
- assertEx(allCouponsAreUSD, () => 'All coupons must be in USD')
23
- const total = appraisals.reduce((acc, appraisal) => acc + appraisal.price, 0)
24
-
25
- // Calculated non-stackable discount coupons
26
- const singularFixedDiscount = Math.max(...coupons
27
- .filter(coupon => isFixedAmountCoupon(coupon) && !isStackable(coupon))
28
- .map(coupon => (coupon as FixedAmountCoupon).amount), 0)
29
- const singularPercentageDiscount = (Math.max(...coupons
30
- .filter(coupon => isFixedPercentageCoupon(coupon) && !isStackable(coupon))
31
- .map(coupon => (coupon as FixedPercentageCoupon).percentage), 0)) * total
32
- const singularFixedPriceDiscount = calculateSingularFixedPriceDiscount(total, appraisals, coupons, false)
33
-
34
- // Calculate stackable discount coupons
35
- // First calculate the total discount from fixed amount coupons
36
- const stackedFixedDiscount = coupons
37
- .filter(coupon => isFixedAmountCoupon(coupon) && isStackable(coupon))
38
- .reduce((acc, coupon) => acc + (coupon as FixedAmountCoupon).amount, 0)
39
- // Then calculate the total discount from percentage coupons and apply
40
- // the percentage discount to the remaining total after fixed discounts
41
- const stackedPercentageDiscount = coupons
42
- .filter(coupon => isFixedPercentageCoupon(coupon) && isStackable(coupon))
43
- .reduce((acc, coupon) => acc + (coupon as FixedPercentageCoupon).percentage, 0) * (total - stackedFixedDiscount)
44
- // Then calculate the total discount from fixed price coupons
45
- const stackedFixedPriceDiscount = calculateSingularFixedPriceDiscount(total, appraisals, coupons, true)
46
-
47
- // Sum all stackable discounts
48
- const stackedDiscount = stackedFixedDiscount + stackedPercentageDiscount + stackedFixedPriceDiscount
49
-
50
- // Find the best coupon(s) to apply
51
- const maxDiscount = Math.max(
52
- singularFixedDiscount,
53
- singularFixedPriceDiscount,
54
- singularPercentageDiscount,
55
- stackedDiscount,
56
- 0,
57
- )
58
-
59
- // Ensure discount is not more than the total
60
- const amount = Math.min(maxDiscount, total)
61
-
62
- // Return single discount payload
63
- return {
64
- amount, schema: DiscountSchema, currency: 'USD',
65
- }
66
- }
67
-
68
- const calculateSingularFixedPriceDiscount = (total: number, appraisals: HashLeaseEstimate[], coupons: Coupon[], stackable = false): number => {
69
- // Find all singular fixed price discounts
70
- const singularFixedPriceDiscounts = coupons
71
- .filter(isFixedPriceCoupon)
72
- .filter(coupon => stackable ? isStackable(coupon) : !isStackable(coupon))
73
- .map(coupon => (coupon as FixedPriceCoupon).amount)
74
- // Ensure all fixed price discounts are positive
75
- .filter(amount => amount > 0)
76
-
77
- // If there are no singular fixed price discounts, return no discount
78
- if (singularFixedPriceDiscounts.length === 0) return 0
79
-
80
- // Find the maximum discount (the lowest fixed price)
81
- const lowestFixedPrice = Math.min(...singularFixedPriceDiscounts)
82
-
83
- // Apply the fixed price to all appraisals to get the reduced prices
84
- const reducedPrices = appraisals.map(appraisal =>
85
- // If the appraisal price is less than the fixed price
86
- Math.min(appraisal.price, lowestFixedPrice))
87
-
88
- // Calculate the reduced total using the reduced prices
89
- const reducedTotal = reducedPrices.reduce((acc, price) => acc + price, 0)
90
-
91
- // Calculate the discount
92
- const discount = total - reducedTotal
93
-
94
- // Return the discount or 0 if the discount would have resulted in a negative value
95
- return Math.max(discount, 0)
96
- }
@@ -1,72 +0,0 @@
1
- import type { Hash } from '@xylabs/hex'
2
- import { PayloadBuilder } from '@xyo-network/payload-builder'
3
- import type { Payload } from '@xyo-network/payload-model'
4
- import type { Condition, Coupon } from '@xyo-network/payment-payload-plugins'
5
- import { isCondition } from '@xyo-network/payment-payload-plugins'
6
- import type { SchemaPayload } from '@xyo-network/schema-payload-plugin'
7
- import { isSchemaPayload } from '@xyo-network/schema-payload-plugin'
8
- import type { ValidateFunction } from 'ajv'
9
- import { Ajv } from 'ajv'
10
-
11
- // TODO: Use our schema cache
12
- const ajv = new Ajv({ strict: false }) // Create the Ajv instance once
13
- const schemaCache = new Map() // Cache to store compiled validators
14
-
15
- /**
16
- * Validates the conditions of a coupon against the provided payloads
17
- * @param coupon The coupon to check
18
- * @param conditions The conditions associated with the coupon
19
- * @param payloads The associated payloads (containing the conditions and data to validate the conditions against)
20
- * @returns True if all conditions are fulfilled, false otherwise
21
- */
22
- export const areConditionsFulfilled = async (coupon: Coupon, conditions: Condition[] = [], payloads: Payload[] = []): Promise<boolean> =>
23
- (await findUnfulfilledConditions(coupon, conditions, payloads)).length === 0
24
-
25
- /**
26
- * Validates the conditions of a coupon against the provided payloads
27
- * @param coupon The coupon to check
28
- * @param conditions The conditions associated with the coupon
29
- * @param payloads The associated payloads (containing the conditions and data to validate the conditions against)
30
- * @returns The unfulfilled condition hashes
31
- */
32
- export const findUnfulfilledConditions = async (coupon: Coupon, conditions: Condition[] = [], payloads: Payload[] = []): Promise<Hash[]> => {
33
- const unfulfilledConditions: Hash[] = []
34
- // If there are no conditions, then they are fulfilled
35
- if (!coupon.conditions || coupon.conditions.length === 0) return unfulfilledConditions
36
- const hashMap = await PayloadBuilder.toAllHashMap([...conditions, ...payloads])
37
- // Find all the conditions
38
- const foundConditions = coupon.conditions.map(hash => hashMap[hash]).filter(isCondition)
39
- // Not all conditions were found
40
- if (foundConditions.length !== coupon.conditions.length) {
41
- const missing = coupon.conditions.filter(hash => !hashMap[hash])
42
- unfulfilledConditions.push(...missing)
43
- return unfulfilledConditions
44
- }
45
-
46
- // Test each condition
47
- for (const hash of coupon.conditions) {
48
- let validator: ValidateFunction
49
-
50
- // Check if the schema is already cached
51
- if (schemaCache.has(hash)) {
52
- validator = schemaCache.get(hash)
53
- } else {
54
- const payload = hashMap[hash]
55
- const definition = isSchemaPayload(payload) ? (payload as SchemaPayload).definition : undefined
56
- if (definition) {
57
- // Compile and cache the validator
58
- validator = ajv.compile(definition)
59
- schemaCache.set(hash, validator)
60
-
61
- // Validate the payload
62
- } else {
63
- unfulfilledConditions.push(hash)
64
- continue
65
- }
66
- }
67
- if (!validator(payloads)) unfulfilledConditions.push(hash)
68
- }
69
-
70
- // All conditions passed
71
- return unfulfilledConditions
72
- }
@@ -1,2 +0,0 @@
1
- export * from './applyCoupons.ts'
2
- export * from './findUnfulfilledConditions.ts'
@@ -1,40 +0,0 @@
1
- import type { Hash } from '@xylabs/hex'
2
- import type { DivinerInstance } from '@xyo-network/diviner-model'
3
- import { PayloadBuilder } from '@xyo-network/payload-builder'
4
- import type { Payload } from '@xyo-network/payload-model'
5
- import type {
6
- Discount, EscrowTerms, Invoice, Payment,
7
- Subtotal, Total,
8
- } from '@xyo-network/payment-payload-plugins'
9
- import {
10
- isDiscount, isSubtotal, isTotal, PaymentSchema,
11
- } from '@xyo-network/payment-payload-plugins'
12
-
13
- /**
14
- * Validates the escrow terms to ensure they are valid for a purchase
15
- * @returns A payment if the terms are valid for a purchase, undefined otherwise
16
- */
17
- export const getInvoiceForEscrow = async (
18
- terms: EscrowTerms,
19
- dataHashMap: Record<Hash, Payload>,
20
- paymentTotalDiviner: DivinerInstance,
21
- ): Promise<Invoice | undefined> => {
22
- const payloads = Object.values(dataHashMap)
23
- const results = await paymentTotalDiviner.divine([terms, ...payloads])
24
- const subtotal = results.find(isSubtotal) as Subtotal | undefined
25
- const discount = results.find(isDiscount) as Discount | undefined
26
- const total = results.find(isTotal) as Total | undefined
27
- if (!subtotal || !total) return undefined
28
- const { amount, currency } = total
29
- if (currency !== 'USD') return undefined
30
- const $sources = await getSources(terms, subtotal, total, discount)
31
- const payment: Payment = {
32
- amount, currency, schema: PaymentSchema, $sources,
33
- }
34
- return discount ? [subtotal, total, payment, discount] : [subtotal, total, payment]
35
- }
36
-
37
- const getSources = async (terms: EscrowTerms, subtotal: Subtotal, total: Total, discount?: Discount): Promise<Hash[]> => {
38
- const sources = discount ? [terms, subtotal, total, discount] : [terms, subtotal, total]
39
- return await Promise.all(sources.map(p => PayloadBuilder.dataHash(p)))
40
- }
@@ -1 +0,0 @@
1
- export * from './getInvoiceForEscrow.ts'
@@ -1,65 +0,0 @@
1
- import { AbstractDiviner } from '@xyo-network/diviner-abstract'
2
- import { HashLeaseEstimate, isHashLeaseEstimate } from '@xyo-network/diviner-hash-lease'
3
- import { DivinerInstance, DivinerModuleEventData } from '@xyo-network/diviner-model'
4
- import { creatableModule } from '@xyo-network/module-model'
5
- import { PayloadBuilder } from '@xyo-network/payload-builder'
6
- import { Payload } from '@xyo-network/payload-model'
7
- import {
8
- EscrowTerms, isEscrowTerms, PaymentSubtotalDivinerConfigSchema, PaymentSubtotalDivinerParams, Subtotal, SubtotalSchema,
9
- } from '@xyo-network/payment-payload-plugins'
10
-
11
- import {
12
- appraisalValidators, termsValidators, ValidEscrowTerms,
13
- } from './lib/index.ts'
14
-
15
- const currency = 'USD'
16
-
17
- /**
18
- * Escrow terms that contain all the valid fields for calculating a subtotal
19
- */
20
- export type PaymentSubtotalDivinerInputType = EscrowTerms | HashLeaseEstimate | Payload
21
-
22
- @creatableModule()
23
- export class PaymentSubtotalDiviner<
24
- TParams extends PaymentSubtotalDivinerParams = PaymentSubtotalDivinerParams,
25
- TIn extends PaymentSubtotalDivinerInputType = PaymentSubtotalDivinerInputType,
26
- TOut extends Subtotal = Subtotal,
27
- TEventData extends DivinerModuleEventData<DivinerInstance<TParams, TIn, TOut>, TIn, TOut> = DivinerModuleEventData<
28
- DivinerInstance<TParams, TIn, TOut>,
29
- TIn,
30
- TOut
31
- >,
32
- > extends AbstractDiviner<TParams, TIn, TOut, TEventData> {
33
- static override readonly configSchemas = [PaymentSubtotalDivinerConfigSchema]
34
- static override readonly defaultConfigSchema = PaymentSubtotalDivinerConfigSchema
35
-
36
- protected async divineHandler(payloads: TIn[] = []): Promise<TOut[]> {
37
- // Find the escrow terms
38
- const terms = payloads.find(isEscrowTerms) as EscrowTerms | undefined
39
- if (!terms) return []
40
-
41
- // Run all terms validations
42
- if (!termsValidators.every(validator => validator(terms))) return []
43
- const validTerms = terms as ValidEscrowTerms
44
-
45
- // Retrieve all appraisals from terms
46
- const hashMap = await PayloadBuilder.toAllHashMap(payloads)
47
- const appraisals = validTerms.appraisals.map(appraisal => hashMap[appraisal]).filter(isHashLeaseEstimate) as unknown as HashLeaseEstimate[]
48
-
49
- // Ensure all appraisals are present
50
- if (appraisals.length !== validTerms.appraisals.length) return []
51
-
52
- // Run all appraisal validations
53
- if (!appraisalValidators.every(validator => validator(appraisals))) return []
54
- const amount = calculateSubtotal(appraisals)
55
- const $sources = [await PayloadBuilder.dataHash(validTerms), ...validTerms.appraisals]
56
- return [{
57
- amount, currency, schema: SubtotalSchema, $sources,
58
- }] as TOut[]
59
- }
60
- }
61
-
62
- // TODO: Add support for other currencies
63
- const calculateSubtotal = (appraisals: HashLeaseEstimate[]): number => {
64
- return appraisals.reduce((sum, appraisal) => sum + appraisal.price, 0)
65
- }
@@ -1 +0,0 @@
1
- export * from './Diviner.ts'
@@ -1,40 +0,0 @@
1
- import type { HashLeaseEstimate } from '@xyo-network/diviner-hash-lease'
2
- import { isIso4217CurrencyCode } from '@xyo-network/payment-payload-plugins'
3
-
4
- import { validateDuration } from './durationValidators.ts'
5
-
6
- const validateAppraisalAmount = (appraisals: HashLeaseEstimate[]): boolean => {
7
- // Ensure all appraisals are numeric
8
- if (appraisals.some(appraisal => typeof appraisal.price !== 'number')) return false
9
- // Ensure all appraisals are positive numbers
10
- return !(appraisals.some(appraisal => appraisal.price < 0))
11
- }
12
-
13
- const validateAppraisalCurrency = (appraisals: HashLeaseEstimate[]): boolean => {
14
- // Only supporting USD for now, the remaining checks are for future-proofing.
15
- if (!appraisals.every(appraisal => appraisal.currency == 'USD')) return false
16
-
17
- // Check every object in the array to ensure they all are in a supported currency.
18
- return (appraisals.every(appraisal => isIso4217CurrencyCode(appraisal.currency)))
19
- }
20
-
21
- const validateAppraisalConsistentCurrency = (appraisals: HashLeaseEstimate[]): boolean => {
22
- // Check if the array is empty or contains only one element, no need to compare.
23
- if (appraisals.length <= 1) return true
24
-
25
- // Get the currency of the first element to compare with others.
26
- const { currency } = appraisals[0]
27
- if (!currency) return false
28
-
29
- // Check every object in the array to ensure they all have the same currency.
30
- return (appraisals.every(item => item.currency === currency))
31
- }
32
-
33
- const validateAppraisalWindow = (appraisals: HashLeaseEstimate[]): boolean => appraisals.every(validateDuration)
34
-
35
- export const appraisalValidators = [
36
- validateAppraisalAmount,
37
- validateAppraisalCurrency,
38
- validateAppraisalConsistentCurrency,
39
- validateAppraisalWindow,
40
- ]
@@ -1,17 +0,0 @@
1
- import type { DurationFields } from '@xyo-network/xns-record-payload-plugins'
2
-
3
- const FIVE_MINUTES = 1000 * 60 * 5
4
-
5
- /**
6
- * Validates that the current time is within the duration window, within a configurable a buffer
7
- * @param value The duration value
8
- * @param windowMs The window in milliseconds to allow for a buffer
9
- * @returns True if the duration is valid, false otherwise
10
- */
11
- export const validateDuration = (value: Partial<DurationFields>, windowMs = FIVE_MINUTES): boolean => {
12
- const now = Date.now()
13
- if (!value.nbf || value.nbf > now) return false
14
- // If already expired (include for a 5 minute buffer to allow for a reasonable
15
- // minimum amount of time for the transaction to be processed)
16
- return !(!value.exp || value.exp - now < windowMs)
17
- }
@@ -1,2 +0,0 @@
1
- export * from './appraisalValidators.ts'
2
- export * from './termsValidators.ts'
@@ -1,17 +0,0 @@
1
- import type { Hash } from '@xylabs/hex'
2
- import type { EscrowTerms } from '@xyo-network/payment-payload-plugins'
3
-
4
- import { validateDuration } from './durationValidators.ts'
5
-
6
- export type ValidEscrowTerms = Required<EscrowTerms>
7
-
8
- const validateTermsAppraisals = (terms: EscrowTerms): terms is Required<EscrowTerms & { appraisals: Hash[] }> => {
9
- if (!terms.appraisals) return false
10
- return terms.appraisals.length > 0
11
- }
12
- const validateTermsWindow = (terms: EscrowTerms): boolean => validateDuration(terms)
13
-
14
- export const termsValidators = [
15
- validateTermsAppraisals,
16
- validateTermsWindow,
17
- ]
@@ -1,68 +0,0 @@
1
- import { assertEx } from '@xylabs/assert'
2
- import { Hash } from '@xylabs/hex'
3
- import { AbstractDiviner } from '@xyo-network/diviner-abstract'
4
- import {
5
- asDivinerInstance, DivinerInstance, DivinerModuleEventData,
6
- } from '@xyo-network/diviner-model'
7
- import { creatableModule } from '@xyo-network/module-model'
8
- import { PayloadBuilder } from '@xyo-network/payload-builder'
9
- import {
10
- Discount,
11
- isDiscount,
12
- isSubtotal,
13
- PaymentTotalDivinerConfigSchema, PaymentTotalDivinerParams, Subtotal, Total, TotalSchema,
14
- } from '@xyo-network/payment-payload-plugins'
15
-
16
- import { PaymentDiscountDiviner, PaymentDiscountDivinerInputType } from '../Discount/index.ts'
17
- import { PaymentSubtotalDiviner, PaymentSubtotalDivinerInputType } from '../Subtotal/index.ts'
18
-
19
- type InputType = PaymentDiscountDivinerInputType | PaymentSubtotalDivinerInputType
20
- type OutputType = Subtotal | Discount | Total
21
-
22
- @creatableModule()
23
- export class PaymentTotalDiviner<
24
- TParams extends PaymentTotalDivinerParams = PaymentTotalDivinerParams,
25
- TIn extends InputType = InputType,
26
- TOut extends OutputType = OutputType,
27
- TEventData extends DivinerModuleEventData<DivinerInstance<TParams, TIn, TOut>, TIn, TOut> = DivinerModuleEventData<
28
- DivinerInstance<TParams, TIn, TOut>,
29
- TIn,
30
- TOut
31
- >,
32
- > extends AbstractDiviner<TParams, TIn, TOut, TEventData> {
33
- static override readonly configSchemas = [PaymentTotalDivinerConfigSchema]
34
- static override readonly defaultConfigSchema: PaymentTotalDivinerConfigSchema = PaymentTotalDivinerConfigSchema
35
-
36
- protected async divineHandler(payloads: TIn[] = []): Promise<TOut[]> {
37
- const subtotalDiviner = await this.getPaymentSubtotalDiviner()
38
- const subtotalResult = await subtotalDiviner.divine(payloads)
39
- const subtotal = subtotalResult.find(isSubtotal)
40
- if (!subtotal) return []
41
- const discountDiviner = await this.getPaymentDiscountsDiviner()
42
- const discountResult = await discountDiviner.divine(payloads)
43
- const discount = discountResult.find(isDiscount)
44
- if (!discount) return []
45
- const { currency: subtotalCurrency } = subtotal
46
- const { currency: discountCurrency } = discount
47
- assertEx(subtotalCurrency === discountCurrency, () => `Subtotal currency ${subtotalCurrency} does not match discount currency ${discountCurrency}`)
48
- const amount = Math.max(0, subtotal.amount - discount.amount)
49
- const currency = subtotalCurrency
50
- const $sources = [await PayloadBuilder.dataHash(subtotal), await PayloadBuilder.dataHash(discount)] as Hash[]
51
- const total: Total = {
52
- amount, currency, $sources, schema: TotalSchema,
53
- }
54
- return [subtotal, discount, total] as TOut[]
55
- }
56
-
57
- protected async getPaymentDiscountsDiviner(): Promise<PaymentDiscountDiviner> {
58
- const name = assertEx(this.config.paymentDiscountDiviner, () => 'Missing paymentDiscountDiviner in config')
59
- const mod = assertEx(await this.resolve(name), () => `Error resolving paymentDiscountDiviner: ${name}`)
60
- return assertEx(asDivinerInstance(mod), () => `Resolved module ${mod.address} not a valid Diviner`) as PaymentDiscountDiviner
61
- }
62
-
63
- protected async getPaymentSubtotalDiviner(): Promise<PaymentSubtotalDiviner> {
64
- const name = assertEx(this.config.paymentSubtotalDiviner, () => 'Missing paymentSubtotalDiviner in config')
65
- const mod = assertEx(await this.resolve(name), () => `Error resolving paymentSubtotalDiviner: ${name}`)
66
- return assertEx(asDivinerInstance(mod), () => `Resolved module ${mod.address} not a valid Diviner`) as PaymentSubtotalDiviner
67
- }
68
- }
@@ -1 +0,0 @@
1
- export * from './Diviner.ts'
package/src/index.ts DELETED
@@ -1,4 +0,0 @@
1
- export * from './Discount/index.ts'
2
- export * from './Invoice/index.ts'
3
- export * from './Subtotal/index.ts'
4
- export * from './Total/index.ts'