danogo-clmm 0.0.15 → 0.1.2
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 +64 -124
- package/dist/sdk.d.mts +85 -25
- package/dist/sdk.d.ts +85 -25
- package/dist/sdk.js +1 -1
- package/dist/sdk.mjs +1 -1
- package/package.json +16 -11
package/README.md
CHANGED
|
@@ -8,16 +8,19 @@ An SDK to calculate and execute swaps on the Danogo liquidity platform on the Ca
|
|
|
8
8
|
npm install danogo-clmm
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Prerequisites
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
This SDK requires:
|
|
14
|
+
- Node.js 18+
|
|
15
|
+
- `@evolution-sdk/evolution` for wallet management and transaction building
|
|
16
|
+
- A Kupmios provider for blockchain data
|
|
17
|
+
- An Ogmios instance for transaction submission
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
## Usage
|
|
16
20
|
|
|
17
21
|
### Initialization
|
|
18
22
|
|
|
19
|
-
Initialize the SDK
|
|
20
|
-
|
|
23
|
+
Initialize the SDK.
|
|
21
24
|
```typescript
|
|
22
25
|
import DanogoSwap from "danogo-clmm";
|
|
23
26
|
|
|
@@ -26,137 +29,61 @@ const sdk = new DanogoSwap();
|
|
|
26
29
|
|
|
27
30
|
### 1. Calculate Swap Output (Quote)
|
|
28
31
|
|
|
29
|
-
Calculate the expected output of a swap without submitting a transaction.
|
|
32
|
+
Calculate the expected output of a swap without submitting a transaction. You can swap through one or more pools to get better price execution.
|
|
30
33
|
|
|
34
|
+
#### Examples
|
|
31
35
|
```typescript
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const lucid = await Lucid(
|
|
39
|
-
new Kupmios("kupo_url", "ogmios_url"),
|
|
40
|
-
"Preprod"
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
const quoteRequest = {
|
|
44
|
-
poolOutRef: {
|
|
45
|
-
txHash:
|
|
46
|
-
"your_tx_hash",
|
|
47
|
-
outputIndex: 0, // your index
|
|
48
|
-
},
|
|
49
|
-
stakingOutRef: {
|
|
50
|
-
txHash:
|
|
51
|
-
"your_tx_hash",
|
|
52
|
-
outputIndex: 1, // your index
|
|
53
|
-
},
|
|
54
|
-
protocolConfigOutRef: {
|
|
55
|
-
txHash:
|
|
56
|
-
"your_tx_hash",
|
|
57
|
-
outputIndex: 0, // your index
|
|
36
|
+
const quote = await sdk.calculateSwapOut(client, {
|
|
37
|
+
pools: [
|
|
38
|
+
{
|
|
39
|
+
poolOutRef: pool1OutRef,
|
|
40
|
+
deltaAmount: 500_000n,
|
|
41
|
+
stakingOutRef: staking1OutRef // required if pool contains ADA and swap for the first time in an epoch
|
|
58
42
|
},
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
console.error("Calculation failed", error);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
43
|
+
{
|
|
44
|
+
poolOutRef: pool2OutRef,
|
|
45
|
+
deltaAmount: 500_000n,
|
|
46
|
+
stakingOutRef: staking2OutRef // required if pool contains ADA and swap for the first time in an epoch
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
});
|
|
69
50
|
```
|
|
70
51
|
|
|
71
52
|
### 2. Submit Swap Transaction
|
|
72
53
|
|
|
73
|
-
Build and submit a swap transaction
|
|
54
|
+
Build and submit a swap transaction across one or more pools.
|
|
74
55
|
|
|
56
|
+
#### Examples
|
|
75
57
|
```typescript
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const lucid = await Lucid(
|
|
84
|
-
new Kupmios("kupo_url", "ogmios_url"),
|
|
85
|
-
"Preprod"
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
// 2. Select wallet
|
|
89
|
-
lucid.selectWallet.fromSeed("your seed phrase");
|
|
90
|
-
|
|
91
|
-
const swapRequest = {
|
|
92
|
-
poolOutRef: {
|
|
93
|
-
txHash:
|
|
94
|
-
"your_tx_hash",
|
|
95
|
-
outputIndex: 0, // your index
|
|
96
|
-
},
|
|
97
|
-
poolScriptOutRef: {
|
|
98
|
-
txHash:
|
|
99
|
-
"your_tx_hash",
|
|
100
|
-
outputIndex: 0, // your index
|
|
101
|
-
},
|
|
102
|
-
protocolConfigOutRef: {
|
|
103
|
-
txHash:
|
|
104
|
-
"your_tx_hash",
|
|
105
|
-
outputIndex: 0, // your index
|
|
106
|
-
},
|
|
107
|
-
stakingOutRef: {
|
|
108
|
-
txHash:
|
|
109
|
-
"your_tx_hash",
|
|
110
|
-
outputIndex: 1, // your index
|
|
58
|
+
const txHash = await sdk.submitSwap(client, {
|
|
59
|
+
pools: [
|
|
60
|
+
{
|
|
61
|
+
poolOutRef: pool1OutRef,
|
|
62
|
+
deltaAmount: 500_000n,
|
|
63
|
+
minOutChangeAmount: 450_000n,
|
|
64
|
+
stakingOutRef: staking1OutRef // required if pool contains ADA and swap for the first time in an epoch
|
|
111
65
|
},
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
}
|
|
66
|
+
{
|
|
67
|
+
poolOutRef: pool2OutRef,
|
|
68
|
+
deltaAmount: 500_000n,
|
|
69
|
+
minOutChangeAmount: 450_000n,
|
|
70
|
+
stakingOutRef: staking2OutRef // required if pool contains ADA and swap for the first time in an epoch
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
protocolConfigOutRef: protocolConfigRef
|
|
74
|
+
});
|
|
123
75
|
```
|
|
124
76
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
`lucid-evolution` currently raises an error during transaction evaluation.
|
|
128
|
-
|
|
129
|
-
This package **only supports the Kupmios provider**.
|
|
130
|
-
|
|
131
|
-
### Required Patch
|
|
132
|
-
|
|
133
|
-
Modify the following files:
|
|
77
|
+
> `protocolConfigOutRef` is optional and defaults to the SDK's internal constants. In rare cases where the protocol configuration has updated but the SDK has not yet been updated, you can manually provide the latest `protocolConfigOutRef` in your request. Refer to `src/constants.ts` for the constants.
|
|
134
78
|
|
|
135
|
-
|
|
136
|
-
- `node_modules/@lucid-evolution/provider/dist/index.cjs`
|
|
137
|
-
|
|
138
|
-
In the `evaluateTx` method, comment out the `additionalUtxo` line:
|
|
139
|
-
|
|
140
|
-
```javascript
|
|
141
|
-
const data = {
|
|
142
|
-
jsonrpc: "2.0",
|
|
143
|
-
method: "evaluateTransaction",
|
|
144
|
-
params: {
|
|
145
|
-
transaction: { cbor: tx },
|
|
146
|
-
// Comment out the line below:
|
|
147
|
-
// additionalUtxo: toOgmiosUTxOs(additionalUTxOs)
|
|
148
|
-
},
|
|
149
|
-
id: null
|
|
150
|
-
};
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
### 3. Get Pool Info from Ogmios Transaction
|
|
79
|
+
### 4. Get Pool Info from Ogmios Transaction
|
|
154
80
|
|
|
155
81
|
Extract pool data directly from an Ogmios transaction object.
|
|
156
82
|
|
|
157
83
|
```typescript
|
|
158
84
|
import DanogoSwap from "danogo-clmm";
|
|
159
|
-
import {
|
|
85
|
+
import { createChainSynchronizationClient, createInteractionContext } from "@cardano-ogmios/client";
|
|
86
|
+
import { Point } from "@cardano-ogmios/schema";
|
|
160
87
|
|
|
161
88
|
const sdk = new DanogoSwap();
|
|
162
89
|
|
|
@@ -165,9 +92,8 @@ async function main() {
|
|
|
165
92
|
console.error,
|
|
166
93
|
() => console.log("closed"),
|
|
167
94
|
{
|
|
168
|
-
// example with demeter
|
|
169
95
|
connection: {
|
|
170
|
-
host: "
|
|
96
|
+
host: "your_ogmios_host",
|
|
171
97
|
port: 443,
|
|
172
98
|
tls: true
|
|
173
99
|
},
|
|
@@ -178,16 +104,16 @@ async function main() {
|
|
|
178
104
|
rollForward: async ({ block }, requestNext) => {
|
|
179
105
|
if ("transactions" in block) {
|
|
180
106
|
for (const tx of block.transactions!) {
|
|
181
|
-
const
|
|
182
|
-
|
|
107
|
+
const networkId = 0; // 0 for Preprod, 1 for Mainnet
|
|
108
|
+
const pools = sdk.getPoolsFromOgmiosTx(tx, networkId);
|
|
109
|
+
// your logic with pools
|
|
183
110
|
}
|
|
184
111
|
}
|
|
185
|
-
|
|
186
112
|
requestNext();
|
|
187
113
|
},
|
|
188
114
|
|
|
189
115
|
rollBackward: async ({ point }, requestNext) => {
|
|
190
|
-
//
|
|
116
|
+
// handle rollbacks
|
|
191
117
|
requestNext();
|
|
192
118
|
},
|
|
193
119
|
});
|
|
@@ -199,4 +125,18 @@ async function main() {
|
|
|
199
125
|
|
|
200
126
|
await client.resume([checkpoint]);
|
|
201
127
|
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### ⚠️ TypeScript Compatibility Note
|
|
131
|
+
|
|
132
|
+
The dependency `@evolution-sdk/evolution` currently ships with some TypeScript type definitions that may cause compilation errors in strict projects.
|
|
133
|
+
|
|
134
|
+
If you encounter type errors originating from `node_modules/@evolution-sdk/evolution`, you can safely enable the following option in your `tsconfig.json`:
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"compilerOptions": {
|
|
139
|
+
"skipLibCheck": true
|
|
140
|
+
}
|
|
141
|
+
}
|
|
202
142
|
```
|
package/dist/sdk.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TransactionInput, SigningClient } from '@evolution-sdk/evolution';
|
|
2
2
|
import { Transaction } from '@cardano-ogmios/schema';
|
|
3
3
|
|
|
4
4
|
interface PoolDatum {
|
|
@@ -51,44 +51,92 @@ interface ConcentratedPool {
|
|
|
51
51
|
totalSwapFee: bigint;
|
|
52
52
|
}
|
|
53
53
|
interface SwapRequest {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
pools: {
|
|
55
|
+
poolOutRef: TransactionInput.TransactionInput;
|
|
56
|
+
deltaAmount: bigint;
|
|
57
|
+
minOutChangeAmount: bigint;
|
|
58
|
+
stakingOutRef?: TransactionInput.TransactionInput;
|
|
59
|
+
}[];
|
|
60
|
+
protocolConfigOutRef?: TransactionInput.TransactionInput;
|
|
60
61
|
}
|
|
61
62
|
interface QuoteSwapRequest {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
pools: {
|
|
64
|
+
poolOutRef: TransactionInput.TransactionInput;
|
|
65
|
+
deltaAmount: bigint;
|
|
66
|
+
stakingOutRef?: TransactionInput.TransactionInput;
|
|
67
|
+
}[];
|
|
68
|
+
protocolConfigOutRef?: TransactionInput.TransactionInput;
|
|
66
69
|
}
|
|
67
70
|
|
|
68
71
|
declare class DanogoSwap {
|
|
69
72
|
constructor();
|
|
70
73
|
/**
|
|
71
|
-
* Calculates the expected output amount for a swap
|
|
74
|
+
* Calculates the expected output amount for a swap across multiple liquidity pools.
|
|
72
75
|
*
|
|
73
|
-
* This function retrieves the latest pool
|
|
74
|
-
* to estimate the swap outcome
|
|
76
|
+
* This function retrieves the latest pool states from the blockchain and performs routing
|
|
77
|
+
* calculations to estimate the best swap outcome across multiple pools.
|
|
75
78
|
*
|
|
76
|
-
* @param
|
|
79
|
+
* @param client An initialized SigningClient instance used to query the blockchain.
|
|
77
80
|
* @param request The quote request object containing pool references and the swap amount.
|
|
78
|
-
* - `
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
81
|
+
* - `pools`: Array of pool objects with poolOutRef, deltaAmount, and optional stakingOutRef
|
|
82
|
+
* - `protocolConfigOutRef`: Reference to the protocol configuration UTxO
|
|
83
|
+
* @returns A promise that resolves to a `bigint` representing the estimated total output token amount.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* const quote = await sdk.calculateSwapOut(client, {
|
|
88
|
+
* pools: [
|
|
89
|
+
* {
|
|
90
|
+
* poolOutRef: pool1OutRef,
|
|
91
|
+
* deltaAmount: 500_000n, // 0.5 ADA to pool 1
|
|
92
|
+
* stakingOutRef: staking1OutRef
|
|
93
|
+
* },
|
|
94
|
+
* {
|
|
95
|
+
* poolOutRef: pool2OutRef,
|
|
96
|
+
* deltaAmount: 500_000n, // 0.5 ADA to pool 2
|
|
97
|
+
* stakingOutRef: staking2OutRef
|
|
98
|
+
* }
|
|
99
|
+
* ],
|
|
100
|
+
* protocolConfigOutRef: protocolConfigRef
|
|
101
|
+
* });
|
|
102
|
+
* ```
|
|
82
103
|
*/
|
|
83
|
-
calculateSwapOut(
|
|
104
|
+
calculateSwapOut(client: SigningClient, request: QuoteSwapRequest): Promise<bigint[]>;
|
|
84
105
|
/**
|
|
85
106
|
* Builds and submits a swap transaction to the network.
|
|
86
107
|
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
108
|
+
* This method performs a swap across one or more liquidity pools in a single transaction,
|
|
109
|
+
* potentially splitting the input amount across multiple pools for better price execution.
|
|
110
|
+
*
|
|
111
|
+
* @param client An initialized SigningClient instance with a connected wallet.
|
|
112
|
+
* @param request The swap request object containing pool references, swap amount, and minimum output.
|
|
113
|
+
* - `pools`: Array of pool objects with poolOutRef, deltaAmount, and optional stakingOutRef
|
|
114
|
+
* - `minOutChangeAmount`: Minimum acceptable output amount (slippage protection)
|
|
115
|
+
* - `protocolConfigOutRef`: Reference to the protocol configuration UTxO
|
|
89
116
|
* @returns A promise that resolves to the transaction hash.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* const txHash = await sdk.submitSwap(client, {
|
|
121
|
+
* pools: [
|
|
122
|
+
* {
|
|
123
|
+
* poolOutRef: pool1OutRef,
|
|
124
|
+
* deltaAmount: 500_000n, // 0.5 ADA to pool 1
|
|
125
|
+
* stakingOutRef: staking1OutRef
|
|
126
|
+
* },
|
|
127
|
+
* {
|
|
128
|
+
* poolOutRef: pool2OutRef,
|
|
129
|
+
* deltaAmount: 500_000n, // 0.5 ADA to pool 2
|
|
130
|
+
* stakingOutRef: staking2OutRef
|
|
131
|
+
* }
|
|
132
|
+
* ],
|
|
133
|
+
* poolScriptOutRef: poolScriptRef,
|
|
134
|
+
* minOutChangeAmount: 900_000n, // Minimum 0.9 tokens out
|
|
135
|
+
* protocolConfigOutRef: protocolConfigRef
|
|
136
|
+
* });
|
|
137
|
+
* ```
|
|
90
138
|
*/
|
|
91
|
-
submitSwap(
|
|
139
|
+
submitSwap(client: SigningClient, request: SwapRequest): Promise<string>;
|
|
92
140
|
/**
|
|
93
141
|
* Extracts concentrated liquidity pool data from a given Ogmios transaction.
|
|
94
142
|
*
|
|
@@ -99,7 +147,19 @@ declare class DanogoSwap {
|
|
|
99
147
|
* @param tx The transaction object conforming to the Ogmios schema.
|
|
100
148
|
* @returns An array of `ConcentratedPool` objects found in the transaction outputs.
|
|
101
149
|
*/
|
|
102
|
-
getPoolsFromOgmiosTx(tx: Transaction,
|
|
150
|
+
getPoolsFromOgmiosTx(tx: Transaction, networkId: number, poolScriptHash?: string): ConcentratedPool[];
|
|
151
|
+
/**
|
|
152
|
+
* Helper function to get the balance of a specific token from user UTXOs
|
|
153
|
+
*/
|
|
154
|
+
private getUserTokenBalance;
|
|
155
|
+
/**
|
|
156
|
+
* Helper function to build delta assets for pool updates
|
|
157
|
+
*/
|
|
158
|
+
private buildDeltaAssets;
|
|
159
|
+
/**
|
|
160
|
+
* Helper function to handle staking rewards for ADA pools
|
|
161
|
+
*/
|
|
162
|
+
private getStakingRewards;
|
|
103
163
|
}
|
|
104
164
|
|
|
105
|
-
export { type ConcentratedPool, type PoolDatum, type SwapRequest, DanogoSwap as default };
|
|
165
|
+
export { type ConcentratedPool, type PoolDatum, type QuoteSwapRequest, type SwapRequest, DanogoSwap as default };
|
package/dist/sdk.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TransactionInput, SigningClient } from '@evolution-sdk/evolution';
|
|
2
2
|
import { Transaction } from '@cardano-ogmios/schema';
|
|
3
3
|
|
|
4
4
|
interface PoolDatum {
|
|
@@ -51,44 +51,92 @@ interface ConcentratedPool {
|
|
|
51
51
|
totalSwapFee: bigint;
|
|
52
52
|
}
|
|
53
53
|
interface SwapRequest {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
pools: {
|
|
55
|
+
poolOutRef: TransactionInput.TransactionInput;
|
|
56
|
+
deltaAmount: bigint;
|
|
57
|
+
minOutChangeAmount: bigint;
|
|
58
|
+
stakingOutRef?: TransactionInput.TransactionInput;
|
|
59
|
+
}[];
|
|
60
|
+
protocolConfigOutRef?: TransactionInput.TransactionInput;
|
|
60
61
|
}
|
|
61
62
|
interface QuoteSwapRequest {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
pools: {
|
|
64
|
+
poolOutRef: TransactionInput.TransactionInput;
|
|
65
|
+
deltaAmount: bigint;
|
|
66
|
+
stakingOutRef?: TransactionInput.TransactionInput;
|
|
67
|
+
}[];
|
|
68
|
+
protocolConfigOutRef?: TransactionInput.TransactionInput;
|
|
66
69
|
}
|
|
67
70
|
|
|
68
71
|
declare class DanogoSwap {
|
|
69
72
|
constructor();
|
|
70
73
|
/**
|
|
71
|
-
* Calculates the expected output amount for a swap
|
|
74
|
+
* Calculates the expected output amount for a swap across multiple liquidity pools.
|
|
72
75
|
*
|
|
73
|
-
* This function retrieves the latest pool
|
|
74
|
-
* to estimate the swap outcome
|
|
76
|
+
* This function retrieves the latest pool states from the blockchain and performs routing
|
|
77
|
+
* calculations to estimate the best swap outcome across multiple pools.
|
|
75
78
|
*
|
|
76
|
-
* @param
|
|
79
|
+
* @param client An initialized SigningClient instance used to query the blockchain.
|
|
77
80
|
* @param request The quote request object containing pool references and the swap amount.
|
|
78
|
-
* - `
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
81
|
+
* - `pools`: Array of pool objects with poolOutRef, deltaAmount, and optional stakingOutRef
|
|
82
|
+
* - `protocolConfigOutRef`: Reference to the protocol configuration UTxO
|
|
83
|
+
* @returns A promise that resolves to a `bigint` representing the estimated total output token amount.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* const quote = await sdk.calculateSwapOut(client, {
|
|
88
|
+
* pools: [
|
|
89
|
+
* {
|
|
90
|
+
* poolOutRef: pool1OutRef,
|
|
91
|
+
* deltaAmount: 500_000n, // 0.5 ADA to pool 1
|
|
92
|
+
* stakingOutRef: staking1OutRef
|
|
93
|
+
* },
|
|
94
|
+
* {
|
|
95
|
+
* poolOutRef: pool2OutRef,
|
|
96
|
+
* deltaAmount: 500_000n, // 0.5 ADA to pool 2
|
|
97
|
+
* stakingOutRef: staking2OutRef
|
|
98
|
+
* }
|
|
99
|
+
* ],
|
|
100
|
+
* protocolConfigOutRef: protocolConfigRef
|
|
101
|
+
* });
|
|
102
|
+
* ```
|
|
82
103
|
*/
|
|
83
|
-
calculateSwapOut(
|
|
104
|
+
calculateSwapOut(client: SigningClient, request: QuoteSwapRequest): Promise<bigint[]>;
|
|
84
105
|
/**
|
|
85
106
|
* Builds and submits a swap transaction to the network.
|
|
86
107
|
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
108
|
+
* This method performs a swap across one or more liquidity pools in a single transaction,
|
|
109
|
+
* potentially splitting the input amount across multiple pools for better price execution.
|
|
110
|
+
*
|
|
111
|
+
* @param client An initialized SigningClient instance with a connected wallet.
|
|
112
|
+
* @param request The swap request object containing pool references, swap amount, and minimum output.
|
|
113
|
+
* - `pools`: Array of pool objects with poolOutRef, deltaAmount, and optional stakingOutRef
|
|
114
|
+
* - `minOutChangeAmount`: Minimum acceptable output amount (slippage protection)
|
|
115
|
+
* - `protocolConfigOutRef`: Reference to the protocol configuration UTxO
|
|
89
116
|
* @returns A promise that resolves to the transaction hash.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* const txHash = await sdk.submitSwap(client, {
|
|
121
|
+
* pools: [
|
|
122
|
+
* {
|
|
123
|
+
* poolOutRef: pool1OutRef,
|
|
124
|
+
* deltaAmount: 500_000n, // 0.5 ADA to pool 1
|
|
125
|
+
* stakingOutRef: staking1OutRef
|
|
126
|
+
* },
|
|
127
|
+
* {
|
|
128
|
+
* poolOutRef: pool2OutRef,
|
|
129
|
+
* deltaAmount: 500_000n, // 0.5 ADA to pool 2
|
|
130
|
+
* stakingOutRef: staking2OutRef
|
|
131
|
+
* }
|
|
132
|
+
* ],
|
|
133
|
+
* poolScriptOutRef: poolScriptRef,
|
|
134
|
+
* minOutChangeAmount: 900_000n, // Minimum 0.9 tokens out
|
|
135
|
+
* protocolConfigOutRef: protocolConfigRef
|
|
136
|
+
* });
|
|
137
|
+
* ```
|
|
90
138
|
*/
|
|
91
|
-
submitSwap(
|
|
139
|
+
submitSwap(client: SigningClient, request: SwapRequest): Promise<string>;
|
|
92
140
|
/**
|
|
93
141
|
* Extracts concentrated liquidity pool data from a given Ogmios transaction.
|
|
94
142
|
*
|
|
@@ -99,7 +147,19 @@ declare class DanogoSwap {
|
|
|
99
147
|
* @param tx The transaction object conforming to the Ogmios schema.
|
|
100
148
|
* @returns An array of `ConcentratedPool` objects found in the transaction outputs.
|
|
101
149
|
*/
|
|
102
|
-
getPoolsFromOgmiosTx(tx: Transaction,
|
|
150
|
+
getPoolsFromOgmiosTx(tx: Transaction, networkId: number, poolScriptHash?: string): ConcentratedPool[];
|
|
151
|
+
/**
|
|
152
|
+
* Helper function to get the balance of a specific token from user UTXOs
|
|
153
|
+
*/
|
|
154
|
+
private getUserTokenBalance;
|
|
155
|
+
/**
|
|
156
|
+
* Helper function to build delta assets for pool updates
|
|
157
|
+
*/
|
|
158
|
+
private buildDeltaAssets;
|
|
159
|
+
/**
|
|
160
|
+
* Helper function to handle staking rewards for ADA pools
|
|
161
|
+
*/
|
|
162
|
+
private getStakingRewards;
|
|
103
163
|
}
|
|
104
164
|
|
|
105
|
-
export { type ConcentratedPool, type PoolDatum, type SwapRequest, DanogoSwap as default };
|
|
165
|
+
export { type ConcentratedPool, type PoolDatum, type QuoteSwapRequest, type SwapRequest, DanogoSwap as default };
|
package/dist/sdk.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var K=Object.create;var k=Object.defineProperty;var Z=Object.getOwnPropertyDescriptor;var tt=Object.getOwnPropertyNames;var et=Object.getPrototypeOf,nt=Object.prototype.hasOwnProperty;var ot=(n,e)=>{for(var t in e)k(n,t,{get:e[t],enumerable:!0})},X=(n,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of tt(e))!nt.call(n,r)&&r!==t&&k(n,r,{get:()=>e[r],enumerable:!(o=Z(e,r))||o.enumerable});return n};var rt=(n,e,t)=>(t=n!=null?K(et(n)):{},X(e||!n||!n.__esModule?k(t,"default",{value:n,enumerable:!0}):t,n)),it=n=>X(k({},"__esModule",{value:!0}),n);var lt={};ot(lt,{default:()=>ct});module.exports=it(lt);var O=require("@lucid-evolution/lucid");function D(n,e){let o=(n>=0n?n:n+(1n<<256n)).toString(16);o.length%2&&(o="0"+o);let r=o.length/2;if(r>e)throw new Error(`Number ${n} requires ${r} bytes, but target length is ${e}.`);let i=new Uint8Array(e),s=e-r;for(let g=0;g<r;g++)i[g+s]=parseInt(o.slice(g*2,g*2+2),16);return i}var S=(n,e,t,o)=>{try{return{kind:"selected",inputs:n,makeRedeemer:i=>{let s=3n,g=D(o?t:i[0],1),c=D(i[0],1),p=D(s,1),f=D(0n,1),w=D(e[0],32),d=g.length+p.length+c.length+f.length+w.length,l=new Uint8Array(d),a=0;return l.set(g,a),a+=g.length,l.set(p,a),a+=p.length,l.set(c,a),a+=c.length,l.set(f,a),a+=f.length,l.set(w,a),"5824"+Buffer.from(l).toString("hex")}}}catch(r){throw console.error("Error creating pool redeemer:",r),r}};var m=require("@lucid-evolution/lucid");var Y=require("@lucid-evolution/lucid");function M(n,e,t){return Y.Data.to(n,e,t)}var x=rt(require("cbor")),W=n=>{let e=m.Data.Tuple([m.Data.Bytes(),m.Data.Bytes()]),t=m.Data.Tuple([m.Data.Integer(),m.Data.Integer()],{hasConstr:!0}),o=m.Data.Tuple([e,e,m.Data.Integer(),m.Data.Integer(),m.Data.Integer(),m.Data.Integer(),t,t,m.Data.Integer(),m.Data.Integer(),m.Data.Integer(),m.Data.Integer()],{hasConstr:!0}),r=$(n.tokenX),i=$(n.tokenY),s=[r,i,BigInt(n.lpFeeRate),BigInt(n.platformFeeX),BigInt(n.platformFeeY),BigInt(n.totalSwapFee),[BigInt(n.sqrtLowerPriceNum),BigInt(n.sqrtLowerPriceDen)],[BigInt(n.sqrtUpperPriceNum),BigInt(n.sqrtUpperPriceDen)],BigInt(n.minXChange),BigInt(n.minYChange),BigInt(n.circulatingLPToken),BigInt(n.lastWithdrawEpoch)];return M(s,o)};var $=n=>{if(!n)return["",""];try{if(n.includes(".")){let o=n.split(".");return o.length===2?[o[0],o[1]]:[n,""]}let e=n.slice(0,56),t=n.slice(56);return[e,t]}catch(e){throw console.error(`Error parsing token ID "${n}":`,e),new Error(`Failed to parse token ID: ${n}`)}},v=n=>{let e=x.decodeFirstSync(Buffer.from(n,"hex")),t=e instanceof x.Tagged?e.value:e;if(!Array.isArray(t))throw new Error("Invalid datum structure: expected array of fields");let o=i=>{let s=i instanceof x.Tagged?i.value:i;if(Array.isArray(s)&&s.length===2){let g=s[0].toString("hex"),c=s[1].toString("hex");return g+c}throw new Error("Invalid AssetClass structure")},r=i=>{let s=i instanceof x.Tagged?i.value:i;if(Array.isArray(s)&&s.length===2)return{num:s[0],den:s[1]};throw new Error("Invalid Ratio structure")};return{tokenX:o(t[0]),tokenY:o(t[1]),lpFeeRate:Number(t[2]),platformFeeX:t[3].toString(),platformFeeY:t[4].toString(),totalSwapFee:t[5].toString(),sqrtLowerPriceNum:r(t[6]).num,sqrtLowerPriceDen:r(t[6]).den,sqrtUpperPriceNum:r(t[7]).num,sqrtUpperPriceDen:r(t[7]).den,minXChange:t[8].toString(),minYChange:t[9].toString(),circulatingLPToken:t[10].toString(),lastWithdrawEpoch:Number(t[11])}},U=n=>{let e=x.decodeFirstSync(Buffer.from(n,"hex")),t=e instanceof x.Tagged?e.value:e;if(!Array.isArray(t))throw new Error("Invalid datum structure: expected array of fields");return{platformFeeRate:t[0].toString(),swapFee:t[1].toString()}};var j=n=>{if(!n||Object.keys(n).length===0)return[];let e=[];for(let[t,o]of Object.entries(n)){if(t==="ada")continue;let r=[];for(let[i,s]of Object.entries(o))r.push({name:i,value:s});e.push({policyId:t,assets:r})}return e};var Q=(n,e)=>{let t=432e6,o=1647899091e3,r=328;return e!=="Mainnet"&&(t=18e5),Math.floor((n-o)/t)+r};function N(n,e,t,o,r=0n,i){let s=o<0n?-o:o,g=t.tokenX===""?3000000n+BigInt(t.totalSwapFee):0n,c=BigInt(n)-BigInt(t.platformFeeX)+r-g,p=BigInt(e)-BigInt(t.platformFeeY),f=st(c,p,[BigInt(t.sqrtLowerPriceNum),BigInt(t.sqrtLowerPriceDen)],[BigInt(t.sqrtUpperPriceNum),BigInt(t.sqrtUpperPriceDen)]),w=G(f[0]*BigInt(t.sqrtUpperPriceDen),f[1]*BigInt(t.sqrtUpperPriceNum))+c,d=G(f[0]*BigInt(t.sqrtLowerPriceNum),f[1]*BigInt(t.sqrtLowerPriceDen))+p;return o>0n?_(s,w,d,p,BigInt(t.lpFeeRate),i):_(s,d,w,c,BigInt(t.lpFeeRate),i)}var _=(n,e,t,o,r,i)=>{let s=10000n,c=n*r/s*BigInt(i)/10000n,p=s-r,f=e*s+n*p,w=e*t,l=(t*f-w*s)/f;if(l>o)throw new Error("pool out exceeded");return[l,c]},st=(n,e,t,o)=>{let r=t[1]*o[1],i=t[0]*o[0],s=(e*r-n*i)*(e*r-n*i),g=4n*n*e*t[1]*t[1]*o[0]*o[0],c=at(s+g),p=e*r+n*i+c,f=2n*(o[0]*t[1]-o[1]*t[0]);return[p,f]};function at(n){if(n<0n)throw new Error("Square root of negative number");if(n<2n)return n;let e=n,t=e+n/e>>1n;for(;t<e;)e=t,t=e+n/e>>1n;return e}function G(n,e){if(e===0n)throw new Error("Division by zero");let t=n/e;return n%e===0n||n<0n!=e<0n?t:t+1n}function V(n,e){let o=[...e].sort((r,i)=>r.txHash===i.txHash?r.outputIndex-i.outputIndex:r.txHash<i.txHash?-1:1).findIndex(r=>r.txHash===n.txHash&&r.outputIndex===n.outputIndex);if(o===-1)throw new Error("Protocol config out ref not found in reference inputs");return BigInt(o)}var L=class{constructor(){}async calculateSwapOut(e,t){if(!e||!e.wallet())throw new Error("Please connect a wallet first.");let o=(await e.utxosByOutRef([{txHash:t.poolOutRef.txHash,outputIndex:t.poolOutRef.outputIndex}]))[0],r=null;if(t.stakingOutRef&&(r=(await e.utxosByOutRef([{txHash:t.stakingOutRef.txHash,outputIndex:t.stakingOutRef.outputIndex}]))[0]),!o.datum)throw new Error("Pool input UTxO does not contain a datum.");let i=(await e.utxosByOutRef([{txHash:t.protocolConfigOutRef.txHash,outputIndex:t.protocolConfigOutRef.outputIndex}]))[0];if(!i.datum)throw new Error("Protocol config UTxO does not contain a datum.");let s=U(i.datum),g=v(o.datum),c=g.tokenX||"lovelace",p=g.tokenY,f=o.assets.lovelace,w=u=>{if(u==="lovelace")return f;for(let[A,h]of Object.entries(o.assets))if(A===u)return h;return 0n},d=0n,l="";if(c=="lovelace"){l=(0,O.validatorToRewardAddress)(e.config().network,r.scriptRef);try{d=(await e.delegationAt(l)).rewards}catch{d=0n}}let[a,b]=N(w(c),w(p),g,t.deltaAmount,d,s.platformFeeRate);return a}async submitSwap(e,t){if(!e||!e.wallet())throw new Error("Please connect a wallet first.");let o=(await e.utxosByOutRef([{txHash:t.poolOutRef.txHash,outputIndex:t.poolOutRef.outputIndex}]))[0],r=(await e.utxosByOutRef([{txHash:t.poolScriptOutRef.txHash,outputIndex:t.poolScriptOutRef.outputIndex}]))[0],i=null;if(t.stakingOutRef&&(i=(await e.utxosByOutRef([{txHash:t.stakingOutRef.txHash,outputIndex:t.stakingOutRef.outputIndex}]))[0]),!o.datum)throw new Error("Pool input UTxO does not contain a datum.");let s=(await e.utxosByOutRef([{txHash:t.protocolConfigOutRef.txHash,outputIndex:t.protocolConfigOutRef.outputIndex}]))[0];if(!s.datum)throw new Error("Protocol config UTxO does not contain a datum.");let g=U(s.datum),c=v(o.datum),p=c.tokenX||"lovelace",f=c.tokenY,w=o.assets.lovelace,d=R=>{if(R==="lovelace")return w;for(let[E,J]of Object.entries(o.assets))if(E===R)return J;return 0n},l=t.deltaAmount,a=l>0?p:f,b=l>0?f:p,u=e.newTx(),h=(await e.wallet().getUtxos()).reduce((R,E)=>R+(E.assets[a]||0n),0n),F=l<0n?-l:l;if(h<F)throw new Error(`Insufficient ${a} balance. Required: ${F}, Available: ${h}`);u=u.readFrom([r,s]),i&&(u=u.readFrom([i]));let B=0n,T="";if(p=="lovelace"){T=(0,O.validatorToRewardAddress)(e.config().network,i.scriptRef);try{B=(await e.delegationAt(T)).rewards}catch{B=0n}}let[P,y]=N(d(p),d(f),c,l,B,g.platformFeeRate);if(P<t.minOutChangeAmount)throw new Error(`Slippage too high. Expected at least ${t.minOutChangeAmount} but got ${P}`);let q=Q(Date.now(),e.config().network),z=W({...c,platformFeeX:BigInt(c.platformFeeX)+(a===(c.tokenX||"lovelace")?y:0n),platformFeeY:BigInt(c.platformFeeY)+(a===c.tokenY?y:0n),lastWithdrawEpoch:q,totalSwapFee:BigInt(c.totalSwapFee)+BigInt(g.swapFee)}),I={...o.assets};I[a]=I[a]+(l>0n?l:-l),I[b]=BigInt(I[b])-BigInt(P),I.lovelace=BigInt(I.lovelace)+BigInt(g.swapFee),u=u.pay.ToAddressWithData(o.address,{kind:"inline",value:z},I),u=u.attachMetadata(674,{msg:["Danogo Liquidity Pair: Swap"]});let H=[r,s];i&&H.push(i);let C=V(s,H);return u=u.collectFrom([o],S([o],[l],C,!1)),u=u.withdraw((0,O.validatorToRewardAddress)(e.config().network,r.scriptRef),0n,S([o],[l],C,!0)),p==="lovelace"&&q>c.lastWithdrawEpoch&&(u=u.withdraw(T,B,S([o],[l],C,!1))),u=u.validFrom(Date.now()-12e4).validTo(Date.now()+24e4).setMinFee(17000n).addSigner(await e.wallet().address()),await(await(await u.complete({localUPLCEval:!1})).sign.withWallet().complete()).submit()}getPoolsFromOgmiosTx(e,t){let o=[];return e.outputs.forEach((r,i)=>{let s=r.value,g=s[t];if(g&&r.datum){for(let[c,p]of Object.entries(g))if(p===1n){let f=t+c,w=`${e.id}#${i}`,d=s.ada.lovelace,l=j(s),a=v(r.datum),b=a.tokenX,u=a.tokenY,A=h=>{if(h==="lovelace"||h==="")return d;let F=h.slice(0,56),B=h.slice(56),P=l.find(y=>y.policyId===F)?.assets.find(y=>y.name===B);return P?P.value:0n};o.push({outRef:w,address:r.address,coin:d,multiAssets:l,validityNft:f,tokenA:b,tokenAReserve:A(b),tokenB:u,tokenBReserve:A(u),lpFeeRate:a.lpFeeRate,priceLowerNum:a.sqrtLowerPriceNum,priceLowerDen:a.sqrtLowerPriceDen,priceUpperNum:a.sqrtUpperPriceNum,priceUpperDen:a.sqrtUpperPriceDen,platformFeeA:a.platformFeeX,platformFeeB:a.platformFeeY,minAChange:a.minXChange,minBChange:a.minYChange,lpTokenTotalSupply:a.circulatingLPToken,lastWithdrawEpoch:a.lastWithdrawEpoch,totalSwapFee:a.totalSwapFee})}}}),o}},ct=L;
|
|
1
|
+
var G=Object.defineProperty;var ut=Object.getOwnPropertyDescriptor;var lt=Object.getOwnPropertyNames;var pt=Object.prototype.hasOwnProperty;var mt=(n,t)=>{for(var e in t)G(n,e,{get:t[e],enumerable:!0})},ft=(n,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of lt(t))!pt.call(n,o)&&o!==e&&G(n,o,{get:()=>t[o],enumerable:!(r=ut(t,o))||r.enumerable});return n};var dt=n=>ft(G({},"__esModule",{value:!0}),n);var Bt={};mt(Bt,{default:()=>Rt});module.exports=dt(Bt);var z=require("@evolution-sdk/evolution"),Y=require("@evolution-sdk/evolution/ScriptHash"),b=require("@evolution-sdk/evolution/Assets");function C(n,t){let r=(n>=0n?n:n+(1n<<256n)).toString(16);r.length%2&&(r="0"+r);let o=r.length/2;if(o>t)throw new Error(`Number ${n} requires ${o} bytes, but target length is ${t}.`);let i=new Uint8Array(t),s=t-o;for(let a=0;a<o;a++)i[a+s]=parseInt(r.slice(a*2,a*2+2),16);return i}var v=(n,t,e,r)=>{try{let o=(i,s)=>{let a=3n,f=C(n?i:r,1),l=C(a,1),p=t.map((A,y)=>{let R=s.find(h=>h.utxo.transactionId===A.transactionId&&h.utxo.index===A.index);if(!R)throw new Error(`Pool UTxO at ${y} not found in indexedInputs`);if(e[y]===void 0)throw new Error(`deltaAmount for poolOutIdx ${y} is undefined`);let w=C(BigInt(R.index),1),O=C(BigInt(y),1),g=C(e[y],32);return{poolInBytes:w,poolOutBytes:O,amountBytes:g}}),I=2+34*p.length,u=new Uint8Array(I),d=0;u.set(f,d),d+=f.length,u.set(l,d),d+=l.length;for(let A of p)u.set(A.poolInBytes,d),d+=A.poolInBytes.length,u.set(A.poolOutBytes,d),d+=A.poolOutBytes.length,u.set(A.amountBytes,d),d+=A.amountBytes.length;return u};return{all:i=>{if(!i.length)throw new Error("swapTokensRedeemer batch all called with empty indexedInputs");let s=null;if(n&&(s=i.find(a=>a.utxo.transactionId===n.transactionId&&a.utxo.index===n.index),!s))throw new Error("Target pool UTxO is not found in poolInUTxOs");return o(s?.index,i)},inputs:t}}catch(o){throw console.error("Error creating pool redeemer:",o),o}};var B=require("@evolution-sdk/evolution"),tt=require("@evolution-sdk/evolution/InlineDatum");var L=require("@evolution-sdk/evolution"),x="lovelace",J=432e6,gt="64d111b957e7d7848ffdde5149aa77fa4090a7fa1ad0ac108067900614848501#0",wt="d8b69fc53637bcfadbc4469083f706bc293f4d9d2296646c5ca167bb",At="2cafd7c92f7093e5229af274be83dea660b0590b4174bbed79ba662b44fbd1ee#0",K=18e5,It="2e19cca74e3badcab26aef7574aa1885ba97228a254ca227ba2f79f2b75fd136#0",xt="04041c3c6ba87b33f2c9eb7f7dbeae3b26003c3e199d438bb99932a2",yt="3775af36f485f9c97101ee5b9b360c34f0f8e12186bc9060f358b7fc8ce468a4#0",H=n=>n===1?{poolScriptOutRef:q(gt),poolScriptHash:wt,protocolScriptOutRef:q(At)}:{poolScriptOutRef:q(It),poolScriptHash:xt,protocolScriptOutRef:q(yt)},q=n=>{if(!n)return;let[t,e]=n.split("#");return new L.TransactionInput.TransactionInput({transactionId:L.TransactionHash.fromHex(t),index:BigInt(e)})};var et=n=>{let t=[new Uint8Array(Buffer.from(n.tokenX.slice(0,56),"hex")),new Uint8Array(Buffer.from(n.tokenX.slice(57),"hex"))],e=[new Uint8Array(Buffer.from(n.tokenY.slice(0,56),"hex")),new Uint8Array(Buffer.from(n.tokenY.slice(57),"hex"))],r=B.Data.constr(0n,[n.sqrtLowerPriceNum,n.sqrtLowerPriceDen]),o=B.Data.constr(0n,[n.sqrtUpperPriceNum,n.sqrtUpperPriceDen]),i=B.Data.constr(0n,[t,e,BigInt(n.lpFeeRate),n.platformFeeX,n.platformFeeY,n.totalSwapFee,r,o,n.minXChange,n.minYChange,n.circulatingLPToken,BigInt(n.lastWithdrawEpoch)]);return new tt.InlineDatum({data:i})};var X=n=>{let t;if(typeof n=="string")t=B.CBOR.fromCBORHex(n);else{let i=n.data,s=B.Data.toCBORHex(i);t=B.CBOR.fromCBORHex(s)}let e=t._tag==="Tag"?t.value:t;if(!Array.isArray(e))throw new Error("Invalid datum structure: expected array of fields");let r=i=>{let s=i._tag==="Tag"?i.value:i;if(Array.isArray(s)&&s.length===2){let a=s[0]instanceof Uint8Array?s[0]:new Uint8Array(s[0]),f=s[1]instanceof Uint8Array?s[1]:new Uint8Array(s[1]),l=Buffer.from(a).toString("hex"),p=Buffer.from(f).toString("hex");return l===""&&p===""?x:l+"."+p}throw new Error("Invalid AssetClass structure")},o=i=>{let s=i._tag==="Tag"?i.value:i;if(Array.isArray(s)&&s.length===2)return{num:BigInt(s[0]),den:BigInt(s[1])};throw new Error("Invalid Ratio structure")};return{tokenX:r(e[0]),tokenY:r(e[1]),lpFeeRate:Number(e[2]),platformFeeX:BigInt(e[3]),platformFeeY:BigInt(e[4]),totalSwapFee:BigInt(e[5]),sqrtLowerPriceNum:o(e[6]).num,sqrtLowerPriceDen:o(e[6]).den,sqrtUpperPriceNum:o(e[7]).num,sqrtUpperPriceDen:o(e[7]).den,minXChange:BigInt(e[8]),minYChange:BigInt(e[9]),circulatingLPToken:BigInt(e[10]),lastWithdrawEpoch:Number(e[11])}},j=n=>{let t,e=B.Data.toCBORHex(n.data);t=B.CBOR.fromCBORHex(e);let r=t._tag==="Tag"?t.value:t;if(!Array.isArray(r))throw new Error("Invalid datum structure: expected array of fields");return{platformFeeRate:BigInt(r[0]),swapFee:BigInt(r[1])}};var k=require("@evolution-sdk/evolution");function F(n){if(n===x)return{unit:x};let t=n.indexOf("."),e=t===-1?n:n.slice(0,t),r=t===-1?"":n.slice(t+1),o=k.Bytes.fromHex(e),i=new k.PolicyId.PolicyId({hash:o}),s=r?k.Bytes.fromHex(r):new Uint8Array(0),a=new k.AssetName.AssetName({bytes:s});return{policyId:i,assetName:a,unit:n}}var nt=n=>{if(!n||Object.keys(n).length===0)return[];let t=[];for(let[e,r]of Object.entries(n)){if(e==="ada")continue;let o=[];for(let[i,s]of Object.entries(r))o.push({name:i,value:s});t.push({policyId:e,assets:o})}return t};var it=(n,t)=>{let e=J,r=1647899091e3,o=328;return t!==1&&(e=K),Math.floor((n-r)/e)+o};function bt(n,t,e,r,o=0n,i){let s=r<0n?-r:r,a=e.tokenX===x?3000000n+BigInt(e.totalSwapFee):0n,f=BigInt(n)-BigInt(e.platformFeeX)+o-a,l=BigInt(t)-BigInt(e.platformFeeY),p=ht(f,l,[BigInt(e.sqrtLowerPriceNum),BigInt(e.sqrtLowerPriceDen)],[BigInt(e.sqrtUpperPriceNum),BigInt(e.sqrtUpperPriceDen)]),I=rt(p[0]*BigInt(e.sqrtUpperPriceDen),p[1]*BigInt(e.sqrtUpperPriceNum))+f,u=rt(p[0]*BigInt(e.sqrtLowerPriceNum),p[1]*BigInt(e.sqrtLowerPriceDen))+l;return r>0n?ot(s,I,u,l,BigInt(e.lpFeeRate),i):ot(s,u,I,f,BigInt(e.lpFeeRate),i)}var ot=(n,t,e,r,o,i)=>{let s=10000n,f=n*o/s*BigInt(i)/10000n,l=s-o,p=t*s+n*l,I=t*e,d=(e*p-I*s)/p;if(d>r)throw new Error("pool out exceeded");return[d,f]},ht=(n,t,e,r)=>{let o=e[1]*r[1],i=e[0]*r[0],s=(t*o-n*i)*(t*o-n*i),a=4n*n*t*e[1]*e[1]*r[0]*r[0],f=Pt(s+a),l=t*o+n*i+f,p=2n*(r[0]*e[1]-r[1]*e[0]);return[l,p]};function Pt(n){if(n<0n)throw new Error("Square root of negative number");if(n<2n)return n;let t=n,e=t+n/t>>1n;for(;e<t;)t=e,e=t+n/t>>1n;return t}function rt(n,t){if(t===0n)throw new Error("Division by zero");let e=n/t;return n%t===0n||n<0n!=t<0n?e:e+1n}function st(n,t){let r=[...t].sort((o,i)=>o.transactionId===i.transactionId?o.index<i.index?-1:1:o.transactionId<i.transactionId?-1:1).findIndex(o=>o.transactionId===n.transactionId&&o.index===n.index);if(r===-1)throw new Error("Protocol config out ref not found in reference inputs");return BigInt(r)}function V(n,t,e){let r=[];for(let o=0;o<n.length;o++){let i=n[o],s=t[o];if(s===0n)continue;let[a,f]=bt(i.tokenAAmount,i.tokenBAmount,i.datum,s,i.rewardAmount||0n,e);r.push({poolIndex:o,deltaAmount:s,outputAmount:a,platformFee:f})}return r}var Q=class{constructor(){}async calculateSwapOut(t,e){if(!t||!t.address)throw new Error("Please connect a wallet first.");let r=(await t.address()).networkId,o=await Promise.all(e.pools.map(u=>t.getUtxosByOutRef([u.poolOutRef]))),i=H(r),s=e.protocolConfigOutRef??i.protocolScriptOutRef,a=(await t.getUtxosByOutRef([s]))[0];if(!a.datumOption)throw new Error("Protocol config UTxO does not contain a datum.");let f=j(a.datumOption),l=await Promise.all(e.pools.map(async(u,d)=>{let A=o[d][0];if(!A.datumOption)throw new Error(`Pool input UTxO ${d} does not contain a datum.`);let y=X(A.datumOption),R=F(y.tokenX),w=F(y.tokenY),O=A.assets.lovelace,g=D=>D.unit===x?O:(0,b.quantityOf)(A.assets,D.policyId,D.assetName),h=null;u.stakingOutRef&&(h=(await t.getUtxosByOutRef([u.stakingOutRef]))[0]);let{rewardAmount:U}=await this.getStakingRewards(t,r,h,R);return{tokenAAmount:g(R),tokenBAmount:g(w),datum:y,rewardAmount:U}})),p=e.pools.map(u=>u.deltaAmount);return V(l,p,f.platformFeeRate).map(u=>u.outputAmount)}async submitSwap(t,e){if(!t||!t.address)throw new Error("Please connect a wallet first.");let r=(await t.address()).networkId,o=await Promise.all(e.pools.map(async c=>(await t.getUtxosByOutRef([c.poolOutRef]))[0])),i=H(r),s=i.poolScriptOutRef,a=e.protocolConfigOutRef??i.protocolScriptOutRef,f=(await t.getUtxosByOutRef([s]))[0],l=(await t.getUtxosByOutRef([a]))[0];if(!l.datumOption)throw new Error("Protocol config UTxO does not contain a datum.");let p=j(l.datumOption),I=[],u=[];for(let c=0;c<e.pools.length;c++){let m=e.pools[c],P=o[c];if(!P.datumOption)throw new Error(`Pool input UTxO ${c} does not contain a datum.`);let T=X(P.datumOption),E=F(T.tokenX),S=F(T.tokenY),$=P.assets.lovelace,_=W=>W.unit===x?$:(0,b.quantityOf)(P.assets,W.policyId,W.assetName),N=null;m.stakingOutRef&&(N=(await t.getUtxosByOutRef([m.stakingOutRef]))[0]),u.push(N);let{rewardAmount:ct}=await this.getStakingRewards(t,r,N,E);I.push({tokenAAmount:_(E),tokenBAmount:_(S),datum:T,rewardAmount:ct,utxo:P,tokenA:E,tokenB:S})}let d=e.pools.map(c=>c.deltaAmount),A=V(I,d,p.platformFeeRate);A.forEach((c,m)=>{let P=e.pools[m].minOutChangeAmount;if(c.outputAmount<P)throw new Error(`Expected swap output at least ${P} but got ${c.outputAmount}`)});let y=A.reduce((c,m)=>c+m.deltaAmount,0n),R=e.pools.find(c=>c.deltaAmount!==0n);if(!R)throw new Error("At least one pool must have a non-zero delta amount");let w=R.deltaAmount>0?I[0].tokenA:I[0].tokenB,O=await this.getUserTokenBalance(t,w);if(O<y)throw new Error(`Insufficient ${w.unit} balance. Required: ${y}, Available: ${O}`);let g=t.newTx(),h=[l];h.push(f),u.forEach(c=>{c&&h.push(c)}),g=g.readFrom({referenceInputs:h});let U=it(Date.now(),r),D=st(l,h);g=g.withdraw({stakeCredential:(0,Y.fromScript)(f.scriptRef),amount:0n,redeemer:v(null,o,d,D)});for(let c=0;c<I.length;c++){let m=I[c],P=A.find(N=>N.poolIndex===c);if(!P)continue;let T=P.deltaAmount,E=P.platformFee,S=et({...m.datum,platformFeeX:BigInt(m.datum.platformFeeX)+(T>0?E:0n),platformFeeY:BigInt(m.datum.platformFeeY)+(T<0?E:0n),lastWithdrawEpoch:U,totalSwapFee:BigInt(m.datum.totalSwapFee)+BigInt(p.swapFee)}),$=this.buildDeltaAssets(T>0?m.tokenA:m.tokenB,T>0?m.tokenB:m.tokenA,T,BigInt(P.outputAmount),BigInt(p.swapFee)),_=(0,b.merge)(m.utxo.assets,$);if(g=g.payToAddress({address:m.utxo.address,assets:_,datum:S}),g=g.collectFrom({inputs:[m.utxo],redeemer:v(m.utxo,o,d,D)}),m.tokenA.unit===x&&U>m.datum.lastWithdrawEpoch&&u[c]){let{stakingRewardAddress:N}=await this.getStakingRewards(t,r,u[c],m.tokenA);N&&(g=g.withdraw({stakeCredential:(0,Y.fromScript)(u[c].scriptRef),amount:m.rewardAmount||0n,redeemer:v(m.utxo,o,d,D)}))}}return g=g.attachMetadata({label:674n,metadata:new Map([["msg",["Danogo Multi-Pool Swap"]]])}),g.setValidity({from:BigInt(Date.now()-12e4),to:BigInt(Date.now()+24e4)}),(await(await(await g.build({scriptDataFormat:"array"})).sign()).submit()).toString()}getPoolsFromOgmiosTx(t,e,r){let o=H(e),i=r??o.poolScriptHash;if(!i)throw new Error("Pool script hash is required but not provided or not found for this network.");let s=[];return t.outputs.forEach((a,f)=>{let l=a.value,p=l[i];if(p&&a.datum){for(let[I,u]of Object.entries(p))if(u===1n){let d=r+I,A=`${t.id}#${f}`,y=l.ada.lovelace,R=nt(l),w=X(a.datum),O=w.tokenX,g=w.tokenY,h=U=>{if(U===x)return y;let D=U.slice(0,56),Z=U.slice(56),M=R.find(c=>c.policyId===D)?.assets.find(c=>c.name===Z);return M?M.value:0n};s.push({outRef:A,address:a.address,coin:y,multiAssets:R,validityNft:d,tokenA:O,tokenAReserve:h(O),tokenB:g,tokenBReserve:h(g),lpFeeRate:w.lpFeeRate,priceLowerNum:w.sqrtLowerPriceNum,priceLowerDen:w.sqrtLowerPriceDen,priceUpperNum:w.sqrtUpperPriceNum,priceUpperDen:w.sqrtUpperPriceDen,platformFeeA:w.platformFeeX,platformFeeB:w.platformFeeY,minAChange:w.minXChange,minBChange:w.minYChange,lpTokenTotalSupply:w.circulatingLPToken,lastWithdrawEpoch:w.lastWithdrawEpoch,totalSwapFee:w.totalSwapFee})}}}),s}async getUserTokenBalance(t,e){return(await t.getWalletUtxos()).reduce((o,i)=>o+(e.unit===x?i.assets.lovelace:(0,b.quantityOf)(i.assets,e.policyId,e.assetName)||0n),0n)}buildDeltaAssets(t,e,r,o,i){let s=r>0n?r:-r,a;if(t.unit===x?a=(0,b.fromLovelace)(s+i):a=(0,b.fromAsset)(t.policyId,t.assetName,s,i),e.unit===x)a=(0,b.subtractLovelace)(a,o);else{let f=(0,b.fromAsset)(e.policyId,e.assetName,-o);a=(0,b.merge)(a,f)}return a}async getStakingRewards(t,e,r,o){if(o.unit!==x)return{rewardAmount:0n};let i=new z.RewardAccount.RewardAccount({networkId:e,stakeCredential:(0,Y.fromScript)(r.scriptRef)}),s=z.RewardAccount.toBech32(i);return{rewardAmount:(await t.getDelegation(s)).rewards,stakingRewardAddress:s}}},Rt=Q;
|
package/dist/sdk.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{validatorToRewardAddress as U}from"@lucid-evolution/lucid";function D(n,e){let o=(n>=0n?n:n+(1n<<256n)).toString(16);o.length%2&&(o="0"+o);let r=o.length/2;if(r>e)throw new Error(`Number ${n} requires ${r} bytes, but target length is ${e}.`);let i=new Uint8Array(e),s=e-r;for(let g=0;g<r;g++)i[g+s]=parseInt(o.slice(g*2,g*2+2),16);return i}var k=(n,e,t,o)=>{try{return{kind:"selected",inputs:n,makeRedeemer:i=>{let s=3n,g=D(o?t:i[0],1),c=D(i[0],1),p=D(s,1),f=D(0n,1),w=D(e[0],32),m=g.length+p.length+c.length+f.length+w.length,l=new Uint8Array(m),a=0;return l.set(g,a),a+=g.length,l.set(p,a),a+=p.length,l.set(c,a),a+=c.length,l.set(f,a),a+=f.length,l.set(w,a),"5824"+Buffer.from(l).toString("hex")}}}catch(r){throw console.error("Error creating pool redeemer:",r),r}};import{Data as d}from"@lucid-evolution/lucid";import{Data as V}from"@lucid-evolution/lucid";function H(n,e,t){return V.to(n,e,t)}import*as x from"cbor";var Y=n=>{let e=d.Tuple([d.Bytes(),d.Bytes()]),t=d.Tuple([d.Integer(),d.Integer()],{hasConstr:!0}),o=d.Tuple([e,e,d.Integer(),d.Integer(),d.Integer(),d.Integer(),t,t,d.Integer(),d.Integer(),d.Integer(),d.Integer()],{hasConstr:!0}),r=X(n.tokenX),i=X(n.tokenY),s=[r,i,BigInt(n.lpFeeRate),BigInt(n.platformFeeX),BigInt(n.platformFeeY),BigInt(n.totalSwapFee),[BigInt(n.sqrtLowerPriceNum),BigInt(n.sqrtLowerPriceDen)],[BigInt(n.sqrtUpperPriceNum),BigInt(n.sqrtUpperPriceDen)],BigInt(n.minXChange),BigInt(n.minYChange),BigInt(n.circulatingLPToken),BigInt(n.lastWithdrawEpoch)];return H(s,o)};var X=n=>{if(!n)return["",""];try{if(n.includes(".")){let o=n.split(".");return o.length===2?[o[0],o[1]]:[n,""]}let e=n.slice(0,56),t=n.slice(56);return[e,t]}catch(e){throw console.error(`Error parsing token ID "${n}":`,e),new Error(`Failed to parse token ID: ${n}`)}},S=n=>{let e=x.decodeFirstSync(Buffer.from(n,"hex")),t=e instanceof x.Tagged?e.value:e;if(!Array.isArray(t))throw new Error("Invalid datum structure: expected array of fields");let o=i=>{let s=i instanceof x.Tagged?i.value:i;if(Array.isArray(s)&&s.length===2){let g=s[0].toString("hex"),c=s[1].toString("hex");return g+c}throw new Error("Invalid AssetClass structure")},r=i=>{let s=i instanceof x.Tagged?i.value:i;if(Array.isArray(s)&&s.length===2)return{num:s[0],den:s[1]};throw new Error("Invalid Ratio structure")};return{tokenX:o(t[0]),tokenY:o(t[1]),lpFeeRate:Number(t[2]),platformFeeX:t[3].toString(),platformFeeY:t[4].toString(),totalSwapFee:t[5].toString(),sqrtLowerPriceNum:r(t[6]).num,sqrtLowerPriceDen:r(t[6]).den,sqrtUpperPriceNum:r(t[7]).num,sqrtUpperPriceDen:r(t[7]).den,minXChange:t[8].toString(),minYChange:t[9].toString(),circulatingLPToken:t[10].toString(),lastWithdrawEpoch:Number(t[11])}},C=n=>{let e=x.decodeFirstSync(Buffer.from(n,"hex")),t=e instanceof x.Tagged?e.value:e;if(!Array.isArray(t))throw new Error("Invalid datum structure: expected array of fields");return{platformFeeRate:t[0].toString(),swapFee:t[1].toString()}};var M=n=>{if(!n||Object.keys(n).length===0)return[];let e=[];for(let[t,o]of Object.entries(n)){if(t==="ada")continue;let r=[];for(let[i,s]of Object.entries(o))r.push({name:i,value:s});e.push({policyId:t,assets:r})}return e};var j=(n,e)=>{let t=432e6,o=1647899091e3,r=328;return e!=="Mainnet"&&(t=18e5),Math.floor((n-o)/t)+r};function E(n,e,t,o,r=0n,i){let s=o<0n?-o:o,g=t.tokenX===""?3000000n+BigInt(t.totalSwapFee):0n,c=BigInt(n)-BigInt(t.platformFeeX)+r-g,p=BigInt(e)-BigInt(t.platformFeeY),f=z(c,p,[BigInt(t.sqrtLowerPriceNum),BigInt(t.sqrtLowerPriceDen)],[BigInt(t.sqrtUpperPriceNum),BigInt(t.sqrtUpperPriceDen)]),w=W(f[0]*BigInt(t.sqrtUpperPriceDen),f[1]*BigInt(t.sqrtUpperPriceNum))+c,m=W(f[0]*BigInt(t.sqrtLowerPriceNum),f[1]*BigInt(t.sqrtLowerPriceDen))+p;return o>0n?$(s,w,m,p,BigInt(t.lpFeeRate),i):$(s,m,w,c,BigInt(t.lpFeeRate),i)}var $=(n,e,t,o,r,i)=>{let s=10000n,c=n*r/s*BigInt(i)/10000n,p=s-r,f=e*s+n*p,w=e*t,l=(t*f-w*s)/f;if(l>o)throw new Error("pool out exceeded");return[l,c]},z=(n,e,t,o)=>{let r=t[1]*o[1],i=t[0]*o[0],s=(e*r-n*i)*(e*r-n*i),g=4n*n*e*t[1]*t[1]*o[0]*o[0],c=J(s+g),p=e*r+n*i+c,f=2n*(o[0]*t[1]-o[1]*t[0]);return[p,f]};function J(n){if(n<0n)throw new Error("Square root of negative number");if(n<2n)return n;let e=n,t=e+n/e>>1n;for(;t<e;)e=t,t=e+n/e>>1n;return e}function W(n,e){if(e===0n)throw new Error("Division by zero");let t=n/e;return n%e===0n||n<0n!=e<0n?t:t+1n}function _(n,e){let o=[...e].sort((r,i)=>r.txHash===i.txHash?r.outputIndex-i.outputIndex:r.txHash<i.txHash?-1:1).findIndex(r=>r.txHash===n.txHash&&r.outputIndex===n.outputIndex);if(o===-1)throw new Error("Protocol config out ref not found in reference inputs");return BigInt(o)}var N=class{constructor(){}async calculateSwapOut(e,t){if(!e||!e.wallet())throw new Error("Please connect a wallet first.");let o=(await e.utxosByOutRef([{txHash:t.poolOutRef.txHash,outputIndex:t.poolOutRef.outputIndex}]))[0],r=null;if(t.stakingOutRef&&(r=(await e.utxosByOutRef([{txHash:t.stakingOutRef.txHash,outputIndex:t.stakingOutRef.outputIndex}]))[0]),!o.datum)throw new Error("Pool input UTxO does not contain a datum.");let i=(await e.utxosByOutRef([{txHash:t.protocolConfigOutRef.txHash,outputIndex:t.protocolConfigOutRef.outputIndex}]))[0];if(!i.datum)throw new Error("Protocol config UTxO does not contain a datum.");let s=C(i.datum),g=S(o.datum),c=g.tokenX||"lovelace",p=g.tokenY,f=o.assets.lovelace,w=u=>{if(u==="lovelace")return f;for(let[A,h]of Object.entries(o.assets))if(A===u)return h;return 0n},m=0n,l="";if(c=="lovelace"){l=U(e.config().network,r.scriptRef);try{m=(await e.delegationAt(l)).rewards}catch{m=0n}}let[a,b]=E(w(c),w(p),g,t.deltaAmount,m,s.platformFeeRate);return a}async submitSwap(e,t){if(!e||!e.wallet())throw new Error("Please connect a wallet first.");let o=(await e.utxosByOutRef([{txHash:t.poolOutRef.txHash,outputIndex:t.poolOutRef.outputIndex}]))[0],r=(await e.utxosByOutRef([{txHash:t.poolScriptOutRef.txHash,outputIndex:t.poolScriptOutRef.outputIndex}]))[0],i=null;if(t.stakingOutRef&&(i=(await e.utxosByOutRef([{txHash:t.stakingOutRef.txHash,outputIndex:t.stakingOutRef.outputIndex}]))[0]),!o.datum)throw new Error("Pool input UTxO does not contain a datum.");let s=(await e.utxosByOutRef([{txHash:t.protocolConfigOutRef.txHash,outputIndex:t.protocolConfigOutRef.outputIndex}]))[0];if(!s.datum)throw new Error("Protocol config UTxO does not contain a datum.");let g=C(s.datum),c=S(o.datum),p=c.tokenX||"lovelace",f=c.tokenY,w=o.assets.lovelace,m=R=>{if(R==="lovelace")return w;for(let[O,Q]of Object.entries(o.assets))if(O===R)return Q;return 0n},l=t.deltaAmount,a=l>0?p:f,b=l>0?f:p,u=e.newTx(),h=(await e.wallet().getUtxos()).reduce((R,O)=>R+(O.assets[a]||0n),0n),F=l<0n?-l:l;if(h<F)throw new Error(`Insufficient ${a} balance. Required: ${F}, Available: ${h}`);u=u.readFrom([r,s]),i&&(u=u.readFrom([i]));let B=0n,T="";if(p=="lovelace"){T=U(e.config().network,i.scriptRef);try{B=(await e.delegationAt(T)).rewards}catch{B=0n}}let[P,y]=E(m(p),m(f),c,l,B,g.platformFeeRate);if(P<t.minOutChangeAmount)throw new Error(`Slippage too high. Expected at least ${t.minOutChangeAmount} but got ${P}`);let L=j(Date.now(),e.config().network),G=Y({...c,platformFeeX:BigInt(c.platformFeeX)+(a===(c.tokenX||"lovelace")?y:0n),platformFeeY:BigInt(c.platformFeeY)+(a===c.tokenY?y:0n),lastWithdrawEpoch:L,totalSwapFee:BigInt(c.totalSwapFee)+BigInt(g.swapFee)}),I={...o.assets};I[a]=I[a]+(l>0n?l:-l),I[b]=BigInt(I[b])-BigInt(P),I.lovelace=BigInt(I.lovelace)+BigInt(g.swapFee),u=u.pay.ToAddressWithData(o.address,{kind:"inline",value:G},I),u=u.attachMetadata(674,{msg:["Danogo Liquidity Pair: Swap"]});let q=[r,s];i&&q.push(i);let v=_(s,q);return u=u.collectFrom([o],k([o],[l],v,!1)),u=u.withdraw(U(e.config().network,r.scriptRef),0n,k([o],[l],v,!0)),p==="lovelace"&&L>c.lastWithdrawEpoch&&(u=u.withdraw(T,B,k([o],[l],v,!1))),u=u.validFrom(Date.now()-12e4).validTo(Date.now()+24e4).setMinFee(17000n).addSigner(await e.wallet().address()),await(await(await u.complete({localUPLCEval:!1})).sign.withWallet().complete()).submit()}getPoolsFromOgmiosTx(e,t){let o=[];return e.outputs.forEach((r,i)=>{let s=r.value,g=s[t];if(g&&r.datum){for(let[c,p]of Object.entries(g))if(p===1n){let f=t+c,w=`${e.id}#${i}`,m=s.ada.lovelace,l=M(s),a=S(r.datum),b=a.tokenX,u=a.tokenY,A=h=>{if(h==="lovelace"||h==="")return m;let F=h.slice(0,56),B=h.slice(56),P=l.find(y=>y.policyId===F)?.assets.find(y=>y.name===B);return P?P.value:0n};o.push({outRef:w,address:r.address,coin:m,multiAssets:l,validityNft:f,tokenA:b,tokenAReserve:A(b),tokenB:u,tokenBReserve:A(u),lpFeeRate:a.lpFeeRate,priceLowerNum:a.sqrtLowerPriceNum,priceLowerDen:a.sqrtLowerPriceDen,priceUpperNum:a.sqrtUpperPriceNum,priceUpperDen:a.sqrtUpperPriceDen,platformFeeA:a.platformFeeX,platformFeeB:a.platformFeeY,minAChange:a.minXChange,minBChange:a.minYChange,lpTokenTotalSupply:a.circulatingLPToken,lastWithdrawEpoch:a.lastWithdrawEpoch,totalSwapFee:a.totalSwapFee})}}}),o}},ht=N;export{ht as default};
|
|
1
|
+
import{RewardAccount as rt}from"@evolution-sdk/evolution";import{fromScript as W}from"@evolution-sdk/evolution/ScriptHash";import{fromAsset as it,merge as st,quantityOf as G,fromLovelace as Pt,subtractLovelace as Rt}from"@evolution-sdk/evolution/Assets";function N(n,e){let o=(n>=0n?n:n+(1n<<256n)).toString(16);o.length%2&&(o="0"+o);let r=o.length/2;if(r>e)throw new Error(`Number ${n} requires ${r} bytes, but target length is ${e}.`);let i=new Uint8Array(e),s=e-r;for(let a=0;a<r;a++)i[a+s]=parseInt(o.slice(a*2,a*2+2),16);return i}var S=(n,e,t,o)=>{try{let r=(i,s)=>{let a=3n,f=N(n?i:o,1),l=N(a,1),p=e.map((A,y)=>{let P=s.find(b=>b.utxo.transactionId===A.transactionId&&b.utxo.index===A.index);if(!P)throw new Error(`Pool UTxO at ${y} not found in indexedInputs`);if(t[y]===void 0)throw new Error(`deltaAmount for poolOutIdx ${y} is undefined`);let w=N(BigInt(P.index),1),R=N(BigInt(y),1),g=N(t[y],32);return{poolInBytes:w,poolOutBytes:R,amountBytes:g}}),I=2+34*p.length,u=new Uint8Array(I),d=0;u.set(f,d),d+=f.length,u.set(l,d),d+=l.length;for(let A of p)u.set(A.poolInBytes,d),d+=A.poolInBytes.length,u.set(A.poolOutBytes,d),d+=A.poolOutBytes.length,u.set(A.amountBytes,d),d+=A.amountBytes.length;return u};return{all:i=>{if(!i.length)throw new Error("swapTokensRedeemer batch all called with empty indexedInputs");let s=null;if(n&&(s=i.find(a=>a.utxo.transactionId===n.transactionId&&a.utxo.index===n.index),!s))throw new Error("Target pool UTxO is not found in poolInUTxOs");return r(s?.index,i)},inputs:e}}catch(r){throw console.error("Error creating pool redeemer:",r),r}};import{Data as k,CBOR as Y}from"@evolution-sdk/evolution";import{InlineDatum as At}from"@evolution-sdk/evolution/InlineDatum";import{TransactionHash as ut,TransactionInput as lt}from"@evolution-sdk/evolution";var x="lovelace",z=432e6,pt="64d111b957e7d7848ffdde5149aa77fa4090a7fa1ad0ac108067900614848501#0",mt="d8b69fc53637bcfadbc4469083f706bc293f4d9d2296646c5ca167bb",ft="2cafd7c92f7093e5229af274be83dea660b0590b4174bbed79ba662b44fbd1ee#0",Q=18e5,dt="2e19cca74e3badcab26aef7574aa1885ba97228a254ca227ba2f79f2b75fd136#0",gt="04041c3c6ba87b33f2c9eb7f7dbeae3b26003c3e199d438bb99932a2",wt="3775af36f485f9c97101ee5b9b360c34f0f8e12186bc9060f358b7fc8ce468a4#0",v=n=>n===1?{poolScriptOutRef:_(pt),poolScriptHash:mt,protocolScriptOutRef:_(ft)}:{poolScriptOutRef:_(dt),poolScriptHash:gt,protocolScriptOutRef:_(wt)},_=n=>{if(!n)return;let[e,t]=n.split("#");return new lt.TransactionInput({transactionId:ut.fromHex(e),index:BigInt(t)})};var Z=n=>{let e=[new Uint8Array(Buffer.from(n.tokenX.slice(0,56),"hex")),new Uint8Array(Buffer.from(n.tokenX.slice(57),"hex"))],t=[new Uint8Array(Buffer.from(n.tokenY.slice(0,56),"hex")),new Uint8Array(Buffer.from(n.tokenY.slice(57),"hex"))],o=k.constr(0n,[n.sqrtLowerPriceNum,n.sqrtLowerPriceDen]),r=k.constr(0n,[n.sqrtUpperPriceNum,n.sqrtUpperPriceDen]),i=k.constr(0n,[e,t,BigInt(n.lpFeeRate),n.platformFeeX,n.platformFeeY,n.totalSwapFee,o,r,n.minXChange,n.minYChange,n.circulatingLPToken,BigInt(n.lastWithdrawEpoch)]);return new At({data:i})};var q=n=>{let e;if(typeof n=="string")e=Y.fromCBORHex(n);else{let i=n.data,s=k.toCBORHex(i);e=Y.fromCBORHex(s)}let t=e._tag==="Tag"?e.value:e;if(!Array.isArray(t))throw new Error("Invalid datum structure: expected array of fields");let o=i=>{let s=i._tag==="Tag"?i.value:i;if(Array.isArray(s)&&s.length===2){let a=s[0]instanceof Uint8Array?s[0]:new Uint8Array(s[0]),f=s[1]instanceof Uint8Array?s[1]:new Uint8Array(s[1]),l=Buffer.from(a).toString("hex"),p=Buffer.from(f).toString("hex");return l===""&&p===""?x:l+"."+p}throw new Error("Invalid AssetClass structure")},r=i=>{let s=i._tag==="Tag"?i.value:i;if(Array.isArray(s)&&s.length===2)return{num:BigInt(s[0]),den:BigInt(s[1])};throw new Error("Invalid Ratio structure")};return{tokenX:o(t[0]),tokenY:o(t[1]),lpFeeRate:Number(t[2]),platformFeeX:BigInt(t[3]),platformFeeY:BigInt(t[4]),totalSwapFee:BigInt(t[5]),sqrtLowerPriceNum:r(t[6]).num,sqrtLowerPriceDen:r(t[6]).den,sqrtUpperPriceNum:r(t[7]).num,sqrtUpperPriceDen:r(t[7]).den,minXChange:BigInt(t[8]),minYChange:BigInt(t[9]),circulatingLPToken:BigInt(t[10]),lastWithdrawEpoch:Number(t[11])}},M=n=>{let e,t=k.toCBORHex(n.data);e=Y.fromCBORHex(t);let o=e._tag==="Tag"?e.value:e;if(!Array.isArray(o))throw new Error("Invalid datum structure: expected array of fields");return{platformFeeRate:BigInt(o[0]),swapFee:BigInt(o[1])}};import{AssetName as It,Bytes as J,PolicyId as xt}from"@evolution-sdk/evolution";function E(n){if(n===x)return{unit:x};let e=n.indexOf("."),t=e===-1?n:n.slice(0,e),o=e===-1?"":n.slice(e+1),r=J.fromHex(t),i=new xt.PolicyId({hash:r}),s=o?J.fromHex(o):new Uint8Array(0),a=new It.AssetName({bytes:s});return{policyId:i,assetName:a,unit:n}}var K=n=>{if(!n||Object.keys(n).length===0)return[];let e=[];for(let[t,o]of Object.entries(n)){if(t==="ada")continue;let r=[];for(let[i,s]of Object.entries(o))r.push({name:i,value:s});e.push({policyId:t,assets:r})}return e};var nt=(n,e)=>{let t=z,o=1647899091e3,r=328;return e!==1&&(t=Q),Math.floor((n-o)/t)+r};function yt(n,e,t,o,r=0n,i){let s=o<0n?-o:o,a=t.tokenX===x?3000000n+BigInt(t.totalSwapFee):0n,f=BigInt(n)-BigInt(t.platformFeeX)+r-a,l=BigInt(e)-BigInt(t.platformFeeY),p=bt(f,l,[BigInt(t.sqrtLowerPriceNum),BigInt(t.sqrtLowerPriceDen)],[BigInt(t.sqrtUpperPriceNum),BigInt(t.sqrtUpperPriceDen)]),I=et(p[0]*BigInt(t.sqrtUpperPriceDen),p[1]*BigInt(t.sqrtUpperPriceNum))+f,u=et(p[0]*BigInt(t.sqrtLowerPriceNum),p[1]*BigInt(t.sqrtLowerPriceDen))+l;return o>0n?tt(s,I,u,l,BigInt(t.lpFeeRate),i):tt(s,u,I,f,BigInt(t.lpFeeRate),i)}var tt=(n,e,t,o,r,i)=>{let s=10000n,f=n*r/s*BigInt(i)/10000n,l=s-r,p=e*s+n*l,I=e*t,d=(t*p-I*s)/p;if(d>o)throw new Error("pool out exceeded");return[d,f]},bt=(n,e,t,o)=>{let r=t[1]*o[1],i=t[0]*o[0],s=(e*r-n*i)*(e*r-n*i),a=4n*n*e*t[1]*t[1]*o[0]*o[0],f=ht(s+a),l=e*r+n*i+f,p=2n*(o[0]*t[1]-o[1]*t[0]);return[l,p]};function ht(n){if(n<0n)throw new Error("Square root of negative number");if(n<2n)return n;let e=n,t=e+n/e>>1n;for(;t<e;)e=t,t=e+n/e>>1n;return e}function et(n,e){if(e===0n)throw new Error("Division by zero");let t=n/e;return n%e===0n||n<0n!=e<0n?t:t+1n}function ot(n,e){let o=[...e].sort((r,i)=>r.transactionId===i.transactionId?r.index<i.index?-1:1:r.transactionId<i.transactionId?-1:1).findIndex(r=>r.transactionId===n.transactionId&&r.index===n.index);if(o===-1)throw new Error("Protocol config out ref not found in reference inputs");return BigInt(o)}function $(n,e,t){let o=[];for(let r=0;r<n.length;r++){let i=n[r],s=e[r];if(s===0n)continue;let[a,f]=yt(i.tokenAAmount,i.tokenBAmount,i.datum,s,i.rewardAmount||0n,t);o.push({poolIndex:r,deltaAmount:s,outputAmount:a,platformFee:f})}return o}var j=class{constructor(){}async calculateSwapOut(e,t){if(!e||!e.address)throw new Error("Please connect a wallet first.");let o=(await e.address()).networkId,r=await Promise.all(t.pools.map(u=>e.getUtxosByOutRef([u.poolOutRef]))),i=v(o),s=t.protocolConfigOutRef??i.protocolScriptOutRef,a=(await e.getUtxosByOutRef([s]))[0];if(!a.datumOption)throw new Error("Protocol config UTxO does not contain a datum.");let f=M(a.datumOption),l=await Promise.all(t.pools.map(async(u,d)=>{let A=r[d][0];if(!A.datumOption)throw new Error(`Pool input UTxO ${d} does not contain a datum.`);let y=q(A.datumOption),P=E(y.tokenX),w=E(y.tokenY),R=A.assets.lovelace,g=B=>B.unit===x?R:G(A.assets,B.policyId,B.assetName),b=null;u.stakingOutRef&&(b=(await e.getUtxosByOutRef([u.stakingOutRef]))[0]);let{rewardAmount:D}=await this.getStakingRewards(e,o,b,P);return{tokenAAmount:g(P),tokenBAmount:g(w),datum:y,rewardAmount:D}})),p=t.pools.map(u=>u.deltaAmount);return $(l,p,f.platformFeeRate).map(u=>u.outputAmount)}async submitSwap(e,t){if(!e||!e.address)throw new Error("Please connect a wallet first.");let o=(await e.address()).networkId,r=await Promise.all(t.pools.map(async c=>(await e.getUtxosByOutRef([c.poolOutRef]))[0])),i=v(o),s=i.poolScriptOutRef,a=t.protocolConfigOutRef??i.protocolScriptOutRef,f=(await e.getUtxosByOutRef([s]))[0],l=(await e.getUtxosByOutRef([a]))[0];if(!l.datumOption)throw new Error("Protocol config UTxO does not contain a datum.");let p=M(l.datumOption),I=[],u=[];for(let c=0;c<t.pools.length;c++){let m=t.pools[c],h=r[c];if(!h.datumOption)throw new Error(`Pool input UTxO ${c} does not contain a datum.`);let O=q(h.datumOption),U=E(O.tokenX),C=E(O.tokenY),H=h.assets.lovelace,F=X=>X.unit===x?H:G(h.assets,X.policyId,X.assetName),T=null;m.stakingOutRef&&(T=(await e.getUtxosByOutRef([m.stakingOutRef]))[0]),u.push(T);let{rewardAmount:ct}=await this.getStakingRewards(e,o,T,U);I.push({tokenAAmount:F(U),tokenBAmount:F(C),datum:O,rewardAmount:ct,utxo:h,tokenA:U,tokenB:C})}let d=t.pools.map(c=>c.deltaAmount),A=$(I,d,p.platformFeeRate);A.forEach((c,m)=>{let h=t.pools[m].minOutChangeAmount;if(c.outputAmount<h)throw new Error(`Expected swap output at least ${h} but got ${c.outputAmount}`)});let y=A.reduce((c,m)=>c+m.deltaAmount,0n),P=t.pools.find(c=>c.deltaAmount!==0n);if(!P)throw new Error("At least one pool must have a non-zero delta amount");let w=P.deltaAmount>0?I[0].tokenA:I[0].tokenB,R=await this.getUserTokenBalance(e,w);if(R<y)throw new Error(`Insufficient ${w.unit} balance. Required: ${y}, Available: ${R}`);let g=e.newTx(),b=[l];b.push(f),u.forEach(c=>{c&&b.push(c)}),g=g.readFrom({referenceInputs:b});let D=nt(Date.now(),o),B=ot(l,b);g=g.withdraw({stakeCredential:W(f.scriptRef),amount:0n,redeemer:S(null,r,d,B)});for(let c=0;c<I.length;c++){let m=I[c],h=A.find(T=>T.poolIndex===c);if(!h)continue;let O=h.deltaAmount,U=h.platformFee,C=Z({...m.datum,platformFeeX:BigInt(m.datum.platformFeeX)+(O>0?U:0n),platformFeeY:BigInt(m.datum.platformFeeY)+(O<0?U:0n),lastWithdrawEpoch:D,totalSwapFee:BigInt(m.datum.totalSwapFee)+BigInt(p.swapFee)}),H=this.buildDeltaAssets(O>0?m.tokenA:m.tokenB,O>0?m.tokenB:m.tokenA,O,BigInt(h.outputAmount),BigInt(p.swapFee)),F=st(m.utxo.assets,H);if(g=g.payToAddress({address:m.utxo.address,assets:F,datum:C}),g=g.collectFrom({inputs:[m.utxo],redeemer:S(m.utxo,r,d,B)}),m.tokenA.unit===x&&D>m.datum.lastWithdrawEpoch&&u[c]){let{stakingRewardAddress:T}=await this.getStakingRewards(e,o,u[c],m.tokenA);T&&(g=g.withdraw({stakeCredential:W(u[c].scriptRef),amount:m.rewardAmount||0n,redeemer:S(m.utxo,r,d,B)}))}}return g=g.attachMetadata({label:674n,metadata:new Map([["msg",["Danogo Multi-Pool Swap"]]])}),g.setValidity({from:BigInt(Date.now()-12e4),to:BigInt(Date.now()+24e4)}),(await(await(await g.build({scriptDataFormat:"array"})).sign()).submit()).toString()}getPoolsFromOgmiosTx(e,t,o){let r=v(t),i=o??r.poolScriptHash;if(!i)throw new Error("Pool script hash is required but not provided or not found for this network.");let s=[];return e.outputs.forEach((a,f)=>{let l=a.value,p=l[i];if(p&&a.datum){for(let[I,u]of Object.entries(p))if(u===1n){let d=o+I,A=`${e.id}#${f}`,y=l.ada.lovelace,P=K(l),w=q(a.datum),R=w.tokenX,g=w.tokenY,b=D=>{if(D===x)return y;let B=D.slice(0,56),V=D.slice(56),L=P.find(c=>c.policyId===B)?.assets.find(c=>c.name===V);return L?L.value:0n};s.push({outRef:A,address:a.address,coin:y,multiAssets:P,validityNft:d,tokenA:R,tokenAReserve:b(R),tokenB:g,tokenBReserve:b(g),lpFeeRate:w.lpFeeRate,priceLowerNum:w.sqrtLowerPriceNum,priceLowerDen:w.sqrtLowerPriceDen,priceUpperNum:w.sqrtUpperPriceNum,priceUpperDen:w.sqrtUpperPriceDen,platformFeeA:w.platformFeeX,platformFeeB:w.platformFeeY,minAChange:w.minXChange,minBChange:w.minYChange,lpTokenTotalSupply:w.circulatingLPToken,lastWithdrawEpoch:w.lastWithdrawEpoch,totalSwapFee:w.totalSwapFee})}}}),s}async getUserTokenBalance(e,t){return(await e.getWalletUtxos()).reduce((r,i)=>r+(t.unit===x?i.assets.lovelace:G(i.assets,t.policyId,t.assetName)||0n),0n)}buildDeltaAssets(e,t,o,r,i){let s=o>0n?o:-o,a;if(e.unit===x?a=Pt(s+i):a=it(e.policyId,e.assetName,s,i),t.unit===x)a=Rt(a,r);else{let f=it(t.policyId,t.assetName,-r);a=st(a,f)}return a}async getStakingRewards(e,t,o,r){if(r.unit!==x)return{rewardAmount:0n};let i=new rt.RewardAccount({networkId:t,stakeCredential:W(o.scriptRef)}),s=rt.toBech32(i);return{rewardAmount:(await e.getDelegation(s)).rewards,stakingRewardAddress:s}}},Qt=j;export{Qt as default};
|
package/package.json
CHANGED
|
@@ -1,22 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "danogo-clmm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "An SDK to calculate and execute swaps on the Danogo liquidity platform.",
|
|
5
5
|
"main": "./dist/sdk.js",
|
|
6
6
|
"module": "./dist/sdk.mjs",
|
|
7
7
|
"types": "./dist/sdk.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/sdk.mjs",
|
|
11
|
+
"require": "./dist/sdk.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
8
14
|
"files": [
|
|
9
15
|
"dist",
|
|
10
16
|
"README.md"
|
|
11
17
|
],
|
|
12
18
|
"keywords": [
|
|
13
19
|
"cardano",
|
|
14
|
-
"
|
|
20
|
+
"dano-finance",
|
|
15
21
|
"swap",
|
|
16
22
|
"clmm"
|
|
17
23
|
],
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/dano-finance/clmm-sdk"
|
|
27
|
+
},
|
|
18
28
|
"scripts": {
|
|
19
|
-
"start": "tsc && node dist/main.js",
|
|
20
29
|
"build": "tsup src/sdk.ts --format cjs,esm --dts --minify --clean --no-splitting",
|
|
21
30
|
"prepublishOnly": "npm run build"
|
|
22
31
|
},
|
|
@@ -24,16 +33,12 @@
|
|
|
24
33
|
"access": "public"
|
|
25
34
|
},
|
|
26
35
|
"dependencies": {
|
|
27
|
-
"@
|
|
28
|
-
"
|
|
29
|
-
"
|
|
36
|
+
"@cardano-ogmios/client": "^6.14.0",
|
|
37
|
+
"@cardano-ogmios/schema": "^6.14.0",
|
|
38
|
+
"@evolution-sdk/evolution": "^0.3.31"
|
|
30
39
|
},
|
|
31
40
|
"devDependencies": {
|
|
32
41
|
"tsup": "^8.0.0",
|
|
33
|
-
"ts-node": "^10.9.2",
|
|
34
42
|
"typescript": "^5.9.2"
|
|
35
|
-
},
|
|
36
|
-
"peerDependencies": {
|
|
37
|
-
"@lucid-evolution/lucid": "0.4.29"
|
|
38
43
|
}
|
|
39
|
-
}
|
|
44
|
+
}
|