@midnight-ntwrk/wallet-sdk-capabilities 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/index.cjs +131 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +124 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +39 -0
package/README.md
ADDED
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var zswap = require('@midnight-ntwrk/zswap');
|
|
4
|
+
|
|
5
|
+
class CounterOffer {
|
|
6
|
+
imbalances;
|
|
7
|
+
transactionCostModel;
|
|
8
|
+
feeTokenType;
|
|
9
|
+
inputsRecipe;
|
|
10
|
+
outputsRecipe;
|
|
11
|
+
constructor(imbalances, transactionCostModel, feeTokenType) {
|
|
12
|
+
this.imbalances = imbalances;
|
|
13
|
+
this.transactionCostModel = transactionCostModel;
|
|
14
|
+
this.feeTokenType = feeTokenType;
|
|
15
|
+
this.inputsRecipe = [];
|
|
16
|
+
this.outputsRecipe = [];
|
|
17
|
+
}
|
|
18
|
+
findNonNativeImbalance() {
|
|
19
|
+
for (const [tokenType, value] of this.imbalances) {
|
|
20
|
+
if (tokenType !== this.feeTokenType && value !== 0n) {
|
|
21
|
+
return [tokenType, value];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
findNativeImbalance() {
|
|
27
|
+
const nativeImbalance = this.imbalances.get(this.feeTokenType);
|
|
28
|
+
if (nativeImbalance !== undefined && nativeImbalance !== 0n) {
|
|
29
|
+
return [this.feeTokenType, nativeImbalance];
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
addInput(input) {
|
|
34
|
+
this.inputsRecipe.push(input);
|
|
35
|
+
const imbalance = this.imbalances.get(input.type) || 0n;
|
|
36
|
+
this.imbalances.set(input.type, imbalance + input.value);
|
|
37
|
+
const nativeImbalance = this.imbalances.get(this.feeTokenType) || 0n;
|
|
38
|
+
this.imbalances.set(this.feeTokenType, nativeImbalance - this.transactionCostModel.inputFeeOverhead);
|
|
39
|
+
}
|
|
40
|
+
addOutput(output) {
|
|
41
|
+
const imbalance = this.imbalances.get(output.type) || 0n;
|
|
42
|
+
const subtractFee = output.type === this.feeTokenType ? this.transactionCostModel.outputFeeOverhead : 0n;
|
|
43
|
+
const absoluteCoinValue = output.value < 0n ? -output.value : output.value;
|
|
44
|
+
this.outputsRecipe.push(zswap.createCoinInfo(output.type, absoluteCoinValue - subtractFee));
|
|
45
|
+
this.imbalances.set(output.type, imbalance - absoluteCoinValue);
|
|
46
|
+
if (output.type !== this.feeTokenType) {
|
|
47
|
+
const nativeImbalance = this.imbalances.get(this.feeTokenType) || 0n;
|
|
48
|
+
this.imbalances.set(this.feeTokenType, nativeImbalance - this.transactionCostModel.outputFeeOverhead);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const getBalanceRecipe = (coins, targetImbalances, transactionCostModel, feeTokenType) => {
|
|
54
|
+
const counterOffer = createCounterOffer(coins, targetImbalances, transactionCostModel, feeTokenType);
|
|
55
|
+
return {
|
|
56
|
+
inputs: counterOffer.inputsRecipe,
|
|
57
|
+
outputs: counterOffer.outputsRecipe,
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
const createCounterOffer = (coins, targetImbalances, transactionCostModel, feeTokenType) => {
|
|
61
|
+
// 1. Create an empty offer
|
|
62
|
+
// 2. Calculate total fees to be paid for the unbalanced transaction and the offer
|
|
63
|
+
// 3. Calculate resulting imbalances by merging ones from the unbalanced transaction, the offer and target imbalances
|
|
64
|
+
const counterOffer = new CounterOffer(targetImbalances, transactionCostModel, feeTokenType);
|
|
65
|
+
let imbalance;
|
|
66
|
+
// 4. Verify if target imbalances are met. If they are, create transaction from the offer, merge with the unbalanced transaction, and return
|
|
67
|
+
// 5. Sort token types present in result imbalances in a way, that DUST is left last and select first token type
|
|
68
|
+
while ((imbalance = counterOffer.findNonNativeImbalance())) {
|
|
69
|
+
coins = doBalance(imbalance, coins, counterOffer);
|
|
70
|
+
}
|
|
71
|
+
while ((imbalance = counterOffer.findNativeImbalance())) {
|
|
72
|
+
coins = doBalance(imbalance, coins, counterOffer);
|
|
73
|
+
}
|
|
74
|
+
return counterOffer;
|
|
75
|
+
};
|
|
76
|
+
const doBalance = (imbalance, coins, counterOffer) => {
|
|
77
|
+
const [tokenType, imbalanceAmount] = imbalance;
|
|
78
|
+
// 6a. If the imbalance is positive and greater than the output fee,
|
|
79
|
+
// create an output for self with the amount equal to imbalance
|
|
80
|
+
const shouldAddOutput = (tokenType === counterOffer.feeTokenType &&
|
|
81
|
+
imbalanceAmount >= counterOffer.transactionCostModel.outputFeeOverhead) ||
|
|
82
|
+
(tokenType !== counterOffer.feeTokenType && imbalanceAmount > 0n);
|
|
83
|
+
if (shouldAddOutput) {
|
|
84
|
+
counterOffer.addOutput({ type: tokenType, value: imbalanceAmount });
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
// 6b. If the imbalance is negative, select a single coin of the selected type, and create an input
|
|
88
|
+
const coin = chooseCoin(coins, { type: tokenType});
|
|
89
|
+
if (typeof coin === 'undefined') {
|
|
90
|
+
throw new Error(tokenType);
|
|
91
|
+
}
|
|
92
|
+
counterOffer.addInput(coin);
|
|
93
|
+
coins = coins.filter((c) => c !== coin);
|
|
94
|
+
}
|
|
95
|
+
return coins;
|
|
96
|
+
};
|
|
97
|
+
const chooseCoin = (coins, coinToChoose) => {
|
|
98
|
+
const filteredAndSortedCoins = coins
|
|
99
|
+
.filter((coin) => coin.type === coinToChoose.type)
|
|
100
|
+
.sort((a, b) => Number(a.value - b.value));
|
|
101
|
+
return filteredAndSortedCoins[0] ?? undefined;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const emptyImbalances = new Map();
|
|
105
|
+
const createImbalances = (imbalances) => {
|
|
106
|
+
const mappedImbalances = new Map();
|
|
107
|
+
imbalances.forEach(([tokenType, value]) => {
|
|
108
|
+
if (mappedImbalances.has(tokenType)) {
|
|
109
|
+
mappedImbalances.set(tokenType, mappedImbalances.get(tokenType) + value);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
mappedImbalances.set(tokenType, value);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
return mappedImbalances;
|
|
116
|
+
};
|
|
117
|
+
const mergeImbalances = (a, b) => {
|
|
118
|
+
b.forEach((valueB, tokenType) => {
|
|
119
|
+
const valueA = a.get(tokenType) || 0n;
|
|
120
|
+
a.set(tokenType, valueA + valueB);
|
|
121
|
+
});
|
|
122
|
+
return a;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
exports.CounterOffer = CounterOffer;
|
|
126
|
+
exports.createCounterOffer = createCounterOffer;
|
|
127
|
+
exports.createImbalances = createImbalances;
|
|
128
|
+
exports.emptyImbalances = emptyImbalances;
|
|
129
|
+
exports.getBalanceRecipe = getBalanceRecipe;
|
|
130
|
+
exports.mergeImbalances = mergeImbalances;
|
|
131
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/balancer/CounterOffer.ts","../src/balancer/Balancer.ts","../src/balancer/Imbalances.ts"],"sourcesContent":[null,null,null],"names":["createCoinInfo"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { QualifiedCoinInfo, CoinInfo } from '@midnight-ntwrk/zswap';
|
|
2
|
+
|
|
3
|
+
interface CoinRecipe {
|
|
4
|
+
type: string;
|
|
5
|
+
value: bigint;
|
|
6
|
+
}
|
|
7
|
+
type Imbalance = [string, bigint];
|
|
8
|
+
type Imbalances = Map<string, bigint>;
|
|
9
|
+
declare const emptyImbalances: Imbalances;
|
|
10
|
+
declare const createImbalances: (imbalances: [string, bigint][]) => Imbalances;
|
|
11
|
+
declare const mergeImbalances: (a: Imbalances, b: Imbalances) => Imbalances;
|
|
12
|
+
|
|
13
|
+
interface TransactionCostModel {
|
|
14
|
+
inputFeeOverhead: bigint;
|
|
15
|
+
outputFeeOverhead: bigint;
|
|
16
|
+
}
|
|
17
|
+
declare class CounterOffer {
|
|
18
|
+
readonly imbalances: Imbalances;
|
|
19
|
+
readonly transactionCostModel: TransactionCostModel;
|
|
20
|
+
readonly feeTokenType: string;
|
|
21
|
+
readonly inputsRecipe: QualifiedCoinInfo[];
|
|
22
|
+
readonly outputsRecipe: CoinInfo[];
|
|
23
|
+
constructor(imbalances: Imbalances, transactionCostModel: TransactionCostModel, feeTokenType: string);
|
|
24
|
+
findNonNativeImbalance(): Imbalance | undefined;
|
|
25
|
+
findNativeImbalance(): Imbalance | undefined;
|
|
26
|
+
addInput(input: QualifiedCoinInfo): void;
|
|
27
|
+
addOutput(output: CoinRecipe): void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface BalanceRecipe {
|
|
31
|
+
inputs: QualifiedCoinInfo[];
|
|
32
|
+
outputs: CoinInfo[];
|
|
33
|
+
}
|
|
34
|
+
declare const getBalanceRecipe: (coins: QualifiedCoinInfo[], targetImbalances: Imbalances, transactionCostModel: TransactionCostModel, feeTokenType: string) => BalanceRecipe;
|
|
35
|
+
declare const createCounterOffer: (coins: QualifiedCoinInfo[], targetImbalances: Imbalances, transactionCostModel: TransactionCostModel, feeTokenType: string) => CounterOffer;
|
|
36
|
+
|
|
37
|
+
export { type BalanceRecipe, type CoinRecipe, CounterOffer, type Imbalance, type Imbalances, type TransactionCostModel, createCounterOffer, createImbalances, emptyImbalances, getBalanceRecipe, mergeImbalances };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { createCoinInfo } from '@midnight-ntwrk/zswap';
|
|
2
|
+
|
|
3
|
+
class CounterOffer {
|
|
4
|
+
imbalances;
|
|
5
|
+
transactionCostModel;
|
|
6
|
+
feeTokenType;
|
|
7
|
+
inputsRecipe;
|
|
8
|
+
outputsRecipe;
|
|
9
|
+
constructor(imbalances, transactionCostModel, feeTokenType) {
|
|
10
|
+
this.imbalances = imbalances;
|
|
11
|
+
this.transactionCostModel = transactionCostModel;
|
|
12
|
+
this.feeTokenType = feeTokenType;
|
|
13
|
+
this.inputsRecipe = [];
|
|
14
|
+
this.outputsRecipe = [];
|
|
15
|
+
}
|
|
16
|
+
findNonNativeImbalance() {
|
|
17
|
+
for (const [tokenType, value] of this.imbalances) {
|
|
18
|
+
if (tokenType !== this.feeTokenType && value !== 0n) {
|
|
19
|
+
return [tokenType, value];
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
findNativeImbalance() {
|
|
25
|
+
const nativeImbalance = this.imbalances.get(this.feeTokenType);
|
|
26
|
+
if (nativeImbalance !== undefined && nativeImbalance !== 0n) {
|
|
27
|
+
return [this.feeTokenType, nativeImbalance];
|
|
28
|
+
}
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
addInput(input) {
|
|
32
|
+
this.inputsRecipe.push(input);
|
|
33
|
+
const imbalance = this.imbalances.get(input.type) || 0n;
|
|
34
|
+
this.imbalances.set(input.type, imbalance + input.value);
|
|
35
|
+
const nativeImbalance = this.imbalances.get(this.feeTokenType) || 0n;
|
|
36
|
+
this.imbalances.set(this.feeTokenType, nativeImbalance - this.transactionCostModel.inputFeeOverhead);
|
|
37
|
+
}
|
|
38
|
+
addOutput(output) {
|
|
39
|
+
const imbalance = this.imbalances.get(output.type) || 0n;
|
|
40
|
+
const subtractFee = output.type === this.feeTokenType ? this.transactionCostModel.outputFeeOverhead : 0n;
|
|
41
|
+
const absoluteCoinValue = output.value < 0n ? -output.value : output.value;
|
|
42
|
+
this.outputsRecipe.push(createCoinInfo(output.type, absoluteCoinValue - subtractFee));
|
|
43
|
+
this.imbalances.set(output.type, imbalance - absoluteCoinValue);
|
|
44
|
+
if (output.type !== this.feeTokenType) {
|
|
45
|
+
const nativeImbalance = this.imbalances.get(this.feeTokenType) || 0n;
|
|
46
|
+
this.imbalances.set(this.feeTokenType, nativeImbalance - this.transactionCostModel.outputFeeOverhead);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const getBalanceRecipe = (coins, targetImbalances, transactionCostModel, feeTokenType) => {
|
|
52
|
+
const counterOffer = createCounterOffer(coins, targetImbalances, transactionCostModel, feeTokenType);
|
|
53
|
+
return {
|
|
54
|
+
inputs: counterOffer.inputsRecipe,
|
|
55
|
+
outputs: counterOffer.outputsRecipe,
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
const createCounterOffer = (coins, targetImbalances, transactionCostModel, feeTokenType) => {
|
|
59
|
+
// 1. Create an empty offer
|
|
60
|
+
// 2. Calculate total fees to be paid for the unbalanced transaction and the offer
|
|
61
|
+
// 3. Calculate resulting imbalances by merging ones from the unbalanced transaction, the offer and target imbalances
|
|
62
|
+
const counterOffer = new CounterOffer(targetImbalances, transactionCostModel, feeTokenType);
|
|
63
|
+
let imbalance;
|
|
64
|
+
// 4. Verify if target imbalances are met. If they are, create transaction from the offer, merge with the unbalanced transaction, and return
|
|
65
|
+
// 5. Sort token types present in result imbalances in a way, that DUST is left last and select first token type
|
|
66
|
+
while ((imbalance = counterOffer.findNonNativeImbalance())) {
|
|
67
|
+
coins = doBalance(imbalance, coins, counterOffer);
|
|
68
|
+
}
|
|
69
|
+
while ((imbalance = counterOffer.findNativeImbalance())) {
|
|
70
|
+
coins = doBalance(imbalance, coins, counterOffer);
|
|
71
|
+
}
|
|
72
|
+
return counterOffer;
|
|
73
|
+
};
|
|
74
|
+
const doBalance = (imbalance, coins, counterOffer) => {
|
|
75
|
+
const [tokenType, imbalanceAmount] = imbalance;
|
|
76
|
+
// 6a. If the imbalance is positive and greater than the output fee,
|
|
77
|
+
// create an output for self with the amount equal to imbalance
|
|
78
|
+
const shouldAddOutput = (tokenType === counterOffer.feeTokenType &&
|
|
79
|
+
imbalanceAmount >= counterOffer.transactionCostModel.outputFeeOverhead) ||
|
|
80
|
+
(tokenType !== counterOffer.feeTokenType && imbalanceAmount > 0n);
|
|
81
|
+
if (shouldAddOutput) {
|
|
82
|
+
counterOffer.addOutput({ type: tokenType, value: imbalanceAmount });
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
// 6b. If the imbalance is negative, select a single coin of the selected type, and create an input
|
|
86
|
+
const coin = chooseCoin(coins, { type: tokenType});
|
|
87
|
+
if (typeof coin === 'undefined') {
|
|
88
|
+
throw new Error(tokenType);
|
|
89
|
+
}
|
|
90
|
+
counterOffer.addInput(coin);
|
|
91
|
+
coins = coins.filter((c) => c !== coin);
|
|
92
|
+
}
|
|
93
|
+
return coins;
|
|
94
|
+
};
|
|
95
|
+
const chooseCoin = (coins, coinToChoose) => {
|
|
96
|
+
const filteredAndSortedCoins = coins
|
|
97
|
+
.filter((coin) => coin.type === coinToChoose.type)
|
|
98
|
+
.sort((a, b) => Number(a.value - b.value));
|
|
99
|
+
return filteredAndSortedCoins[0] ?? undefined;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const emptyImbalances = new Map();
|
|
103
|
+
const createImbalances = (imbalances) => {
|
|
104
|
+
const mappedImbalances = new Map();
|
|
105
|
+
imbalances.forEach(([tokenType, value]) => {
|
|
106
|
+
if (mappedImbalances.has(tokenType)) {
|
|
107
|
+
mappedImbalances.set(tokenType, mappedImbalances.get(tokenType) + value);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
mappedImbalances.set(tokenType, value);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
return mappedImbalances;
|
|
114
|
+
};
|
|
115
|
+
const mergeImbalances = (a, b) => {
|
|
116
|
+
b.forEach((valueB, tokenType) => {
|
|
117
|
+
const valueA = a.get(tokenType) || 0n;
|
|
118
|
+
a.set(tokenType, valueA + valueB);
|
|
119
|
+
});
|
|
120
|
+
return a;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export { CounterOffer, createCounterOffer, createImbalances, emptyImbalances, getBalanceRecipe, mergeImbalances };
|
|
124
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../src/balancer/CounterOffer.ts","../src/balancer/Balancer.ts","../src/balancer/Imbalances.ts"],"sourcesContent":[null,null,null],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@midnight-ntwrk/wallet-sdk-capabilities",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.cjs",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"author": "IOHK",
|
|
9
|
+
"license": "Apache-2.0",
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"registry": "https://npm.pkg.github.com/"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/midnight-ntwrk/artifacts.git"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist/"
|
|
19
|
+
],
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"import": "./dist/index.mjs",
|
|
23
|
+
"require": "./dist/index.cjs",
|
|
24
|
+
"types": "./dist/index.d.ts"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"@midnight-ntwrk/zswap": "^3.0.6"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@midnight-ntwrk/zswap": "^3.0.6"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"typecheck": "tsc -b ./tsconfig.json --noEmit",
|
|
35
|
+
"test": "NODE_OPTIONS='--experimental-vm-modules' jest --silent=false",
|
|
36
|
+
"lint": "eslint",
|
|
37
|
+
"dist:prebuild": "rollup -c ./rollup.config.mjs"
|
|
38
|
+
}
|
|
39
|
+
}
|