saucer-swap-plugin 0.1.0 → 0.2.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 +10 -0
- package/dist/config.js +1 -1
- package/dist/errors.js +10 -0
- package/dist/saucer-swap-v2-parameter-normaliser.js +1 -1
- package/dist/service/saucer-swap-rest-pools-service.js +1 -1
- package/dist/service/saucer-swap-v2-config-service.js +1 -1
- package/dist/tools/get-swap-quote-v2.js +45 -41
- package/dist/tools/swap-v2.js +99 -45
- package/dist/utils/token-allowance.js +23 -0
- package/dist/utils/token-association.js +4 -0
- package/dist/utils.js +2 -2
- package/package.json +10 -3
- package/dist/service/type.js +0 -1
- package/dist/service/utils.js +0 -19
- package/dist/utils/hedera-mirrornode-utils.js +0 -1
package/README.md
CHANGED
|
@@ -15,6 +15,16 @@ A plugin for the Hedera Agent Kit that enables SaucerSwap V2 DeFi operations on
|
|
|
15
15
|
npm install saucer-swap-plugin
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
+
## Prerequisites
|
|
19
|
+
|
|
20
|
+
Before using this plugin, you need to set up the following environment variables:
|
|
21
|
+
|
|
22
|
+
- `SAUCERSWAP_API_KEY` - API key for SaucerSwap REST API access
|
|
23
|
+
- `ACCOUNT_ID` - Your Hedera account ID
|
|
24
|
+
- `PRIVATE_KEY` - Your Hedera account private key (ECDSA format)
|
|
25
|
+
|
|
26
|
+
See [SETUP.md](./SETUP.md) for detailed setup instructions.
|
|
27
|
+
|
|
18
28
|
## Usage
|
|
19
29
|
|
|
20
30
|
### With Hedera Agent Kit
|
package/dist/config.js
CHANGED
package/dist/errors.js
CHANGED
|
@@ -47,3 +47,13 @@ export class ConfigurationError extends SaucerSwapError {
|
|
|
47
47
|
Object.setPrototypeOf(this, ConfigurationError.prototype);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
+
export class TokenNotAssociatedError extends SaucerSwapError {
|
|
51
|
+
constructor(accountId, tokenId, signerAccountId) {
|
|
52
|
+
const signerHint = signerAccountId
|
|
53
|
+
? ` Cannot auto-associate because the recipient differs from the signer (${signerAccountId}). Have the recipient associate the token first.`
|
|
54
|
+
: ' Have the recipient associate the token first.';
|
|
55
|
+
super(`Recipient ${accountId} does not have token ${tokenId} associated.${signerHint}`, 'TOKEN_NOT_ASSOCIATED');
|
|
56
|
+
this.name = 'TokenNotAssociatedError';
|
|
57
|
+
Object.setPrototypeOf(this, TokenNotAssociatedError.prototype);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// write a config service to get the config from the config file
|
|
2
2
|
import { saucerSwapConfig } from "../config";
|
|
3
|
-
import { ContractId, TokenId } from "@
|
|
3
|
+
import { ContractId, TokenId } from "@hiero-ledger/sdk";
|
|
4
4
|
export class SaucerSwapV2ConfigService {
|
|
5
5
|
saucerSwapConfig;
|
|
6
6
|
ledgerId;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PromptGenerator, getMirrornodeService } from "hedera-agent-kit";
|
|
1
|
+
import { BaseTool, PromptGenerator, getMirrornodeService, untypedQueryOutputParser, } from "@hashgraph/hedera-agent-kit";
|
|
2
2
|
import { getSwapQuoteV2Parameters } from "../saucer-swap.zod";
|
|
3
3
|
import { SaucerSwapV2QueryServiceImpl } from "../service/saucer-swap-v2-query-service-impl";
|
|
4
4
|
import SaucerSwapV2ParameterNormaliser from "../saucer-swap-v2-parameter-normaliser";
|
|
@@ -9,36 +9,54 @@ const getSwapQuoteV2Prompt = (context = {}) => {
|
|
|
9
9
|
const contextSnippet = PromptGenerator.getContextSnippet(context);
|
|
10
10
|
const usageInstructions = PromptGenerator.getParameterUsageInstructions();
|
|
11
11
|
return `
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
12
|
+
${contextSnippet}
|
|
13
|
+
|
|
14
|
+
This tool will get a quote for swapping from tokenIn to tokenOut. Provide either optional.amountIn (exact-in) or optional.amountOut (exact-out).
|
|
15
|
+
|
|
16
|
+
Parameters:
|
|
17
|
+
- tokenIn (str, required): The input token address.
|
|
18
|
+
- tokenOut (str, required): The output token address.
|
|
19
|
+
- amountIn (number, required): The amount of input tokens to swap.
|
|
20
|
+
${usageInstructions}
|
|
21
|
+
|
|
22
|
+
Example: "Get quote for swapping 1000000000000000000 amountIn from 0x1234567890abcdef1234567890abcdef12345678 tokenIn to 0xabcdef1234567890abcdef1234567890abcdef12345678 tokenOut"
|
|
23
|
+
`;
|
|
24
24
|
};
|
|
25
|
-
const postProcess = (quote, tokenAmountInBaseUnit, params) => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
25
|
+
const postProcess = (quote, tokenAmountInBaseUnit, params) => `Swapping ${tokenAmountInBaseUnit} token: ${params.tokenIn} to token: ${params.tokenOut} will result in ${quote} token: ${params.tokenOut}, the rate used is ${quote / tokenAmountInBaseUnit}`;
|
|
26
|
+
export const GET_SWAP_QUOTE_V2_TOOL = "get_swap_quote_v2_tool";
|
|
27
|
+
export class GetSwapQuoteV2Tool extends BaseTool {
|
|
28
|
+
method = GET_SWAP_QUOTE_V2_TOOL;
|
|
29
|
+
name = "Get Quote (SaucerSwap V2)";
|
|
30
|
+
description;
|
|
31
|
+
parameters;
|
|
32
|
+
outputParser = untypedQueryOutputParser;
|
|
33
|
+
constructor(context) {
|
|
34
|
+
super();
|
|
35
|
+
this.description = getSwapQuoteV2Prompt(context);
|
|
36
|
+
this.parameters = getSwapQuoteV2Parameters();
|
|
37
|
+
}
|
|
38
|
+
async normalizeParams(params, context, client) {
|
|
39
|
+
const config = new SaucerSwapV2ConfigService(client.ledgerId);
|
|
40
|
+
const api = new SaucerSwapApiServiceImpl(client.ledgerId, config.getSaucerSwapApiKey());
|
|
41
|
+
return await SaucerSwapV2ParameterNormaliser.normaliseGetSwapQuoteV2Params(params, context, api);
|
|
42
|
+
}
|
|
43
|
+
async coreAction(normalisedParams, context, client) {
|
|
44
|
+
const mirrorNode = getMirrornodeService(context.mirrornodeService, client.ledgerId);
|
|
45
|
+
const config = new SaucerSwapV2ConfigService(client.ledgerId);
|
|
46
|
+
const queryService = new SaucerSwapV2QueryServiceImpl(client.ledgerId, mirrorNode, config);
|
|
47
|
+
const quote = await queryService.getSwapQuote(normalisedParams.tokenIn, normalisedParams.tokenOut, normalisedParams.amountIn, normalisedParams.poolFeesInHexFormat.toLowerCase());
|
|
36
48
|
return {
|
|
37
49
|
raw: { quote },
|
|
38
50
|
humanMessage: postProcess(quote, normalisedParams.amountIn, normalisedParams),
|
|
39
51
|
};
|
|
40
52
|
}
|
|
41
|
-
|
|
53
|
+
async shouldSecondaryAction(_coreActionResult, _context) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
async secondaryAction(_request, _client, _context) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
async handleError(error, _context) {
|
|
42
60
|
const desc = 'Failed to get quote';
|
|
43
61
|
let message;
|
|
44
62
|
if (error instanceof SaucerSwapError) {
|
|
@@ -53,20 +71,6 @@ const getSwapQuoteV2 = async (client, context, params) => {
|
|
|
53
71
|
console.error('[get_quote_tool]', message, error);
|
|
54
72
|
return { raw: { error: message }, humanMessage: message };
|
|
55
73
|
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const tool = (context) => ({
|
|
59
|
-
method: GET_SWAP_QUOTE_V2_TOOL,
|
|
60
|
-
name: "Get Quote (SaucerSwap V2)",
|
|
61
|
-
description: getSwapQuoteV2Prompt(context),
|
|
62
|
-
parameters: getSwapQuoteV2Parameters(),
|
|
63
|
-
execute: getSwapQuoteV2,
|
|
64
|
-
outputParser: (rawOutput) => {
|
|
65
|
-
const json = JSON.parse(rawOutput);
|
|
66
|
-
return {
|
|
67
|
-
raw: json,
|
|
68
|
-
humanMessage: json.quote,
|
|
69
|
-
};
|
|
70
|
-
},
|
|
71
|
-
});
|
|
74
|
+
}
|
|
75
|
+
const tool = (context) => new GetSwapQuoteV2Tool(context);
|
|
72
76
|
export default tool;
|
package/dist/tools/swap-v2.js
CHANGED
|
@@ -1,40 +1,108 @@
|
|
|
1
1
|
import SaucerSwapV2ParameterNormaliser from "../saucer-swap-v2-parameter-normaliser";
|
|
2
2
|
import { swapV2Parameters } from "../saucer-swap.zod";
|
|
3
|
-
import { getMirrornodeService, handleTransaction, HederaBuilder, PromptGenerator } from "hedera-agent-kit";
|
|
4
|
-
import { Status } from "@
|
|
3
|
+
import { AccountResolver, AgentMode, BaseTool, getMirrornodeService, handleTransaction, HederaBuilder, HederaParameterNormaliser, PromptGenerator, transactionToolOutputParser, } from "@hashgraph/hedera-agent-kit";
|
|
4
|
+
import { Status } from "@hiero-ledger/sdk";
|
|
5
5
|
import { SaucerSwapV2ConfigService } from "../service/saucer-swap-v2-config-service";
|
|
6
6
|
import { SaucerSwapApiServiceImpl } from "../service/saucer-swap-rest-pools-service";
|
|
7
|
-
import { SaucerSwapError } from "../errors";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
import { SaucerSwapError, TokenNotAssociatedError } from "../errors";
|
|
8
|
+
import { getHederaTokenAddress, getHederaTokenEVMAddress, getTokenDecimals, toBaseUnit } from "../utils";
|
|
9
|
+
import { isTokenAssociated } from "../utils/token-association";
|
|
10
|
+
import { ensureTokenAllowance } from "../utils/token-allowance";
|
|
11
|
+
import { PoolFinderService } from "../service/pool-finder-service";
|
|
12
|
+
const swapV2Prompt = (context = {}) => `
|
|
13
|
+
${PromptGenerator.getContextSnippet(context)}
|
|
11
14
|
|
|
12
|
-
|
|
15
|
+
This tool will swap tokens using the SaucerSwap V2 protocol. If the recipient
|
|
16
|
+
has not associated the output token, the tool will associate it first (only
|
|
17
|
+
works when the recipient equals the signing account; otherwise the call fails
|
|
18
|
+
with a clear error and the recipient must associate the token themselves).
|
|
19
|
+
When tokenIn is not native HBAR / WHBAR, the tool also grants an
|
|
20
|
+
AccountAllowance to the SwapRouter contract for amountIn before swapping.
|
|
13
21
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
Parameters:
|
|
23
|
+
- tokenIn (str, required): The input token address
|
|
24
|
+
- tokenOut (str, required): The output token address
|
|
25
|
+
- amountIn (number, required): The amount of input tokens to swap
|
|
26
|
+
- recipientAddress (str, required): The address to receive the output tokens
|
|
27
|
+
`;
|
|
28
|
+
const postProcess = (response) => `Swap successful.\nTransaction ID: ${response.transactionId}`;
|
|
29
|
+
const resolveSignerAccountId = (context, client) => {
|
|
30
|
+
if (context.mode === AgentMode.RETURN_BYTES) {
|
|
31
|
+
return context.accountId;
|
|
32
|
+
}
|
|
33
|
+
return client.operatorAccountId?.toString();
|
|
20
34
|
};
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
35
|
+
const ensureTokenAssociated = async (recipientAccountId, tokenOutHederaId, context, client, mirrorNode) => {
|
|
36
|
+
if (await isTokenAssociated(recipientAccountId, tokenOutHederaId, mirrorNode))
|
|
37
|
+
return;
|
|
38
|
+
const signer = resolveSignerAccountId(context, client);
|
|
39
|
+
if (!signer || signer !== recipientAccountId) {
|
|
40
|
+
throw new TokenNotAssociatedError(recipientAccountId, tokenOutHederaId, signer);
|
|
41
|
+
}
|
|
42
|
+
const associateParams = HederaParameterNormaliser.normaliseAssociateTokenParams({ accountId: recipientAccountId, tokenIds: [tokenOutHederaId] }, context, client);
|
|
43
|
+
const associateTx = HederaBuilder.associateToken(associateParams);
|
|
44
|
+
await handleTransaction(associateTx, client, context, () => `Associated token ${tokenOutHederaId} with account ${recipientAccountId}`);
|
|
26
45
|
};
|
|
27
|
-
const
|
|
28
|
-
|
|
46
|
+
export const SWAP_V2_TOOL = 'swap_v2_tool';
|
|
47
|
+
export class SwapV2Tool extends BaseTool {
|
|
48
|
+
method = SWAP_V2_TOOL;
|
|
49
|
+
name = 'Swap V2';
|
|
50
|
+
description;
|
|
51
|
+
parameters;
|
|
52
|
+
outputParser = transactionToolOutputParser;
|
|
53
|
+
constructor(context) {
|
|
54
|
+
super();
|
|
55
|
+
this.description = swapV2Prompt(context);
|
|
56
|
+
this.parameters = swapV2Parameters();
|
|
57
|
+
}
|
|
58
|
+
async normalizeParams(params, context, client) {
|
|
59
|
+
const mirrorNode = getMirrornodeService(context.mirrornodeService, client.ledgerId);
|
|
60
|
+
const config = new SaucerSwapV2ConfigService(client.ledgerId);
|
|
61
|
+
const api = new SaucerSwapApiServiceImpl(client.ledgerId, config.getSaucerSwapApiKey());
|
|
62
|
+
const recipientAccountId = AccountResolver.resolveAccount(params.recipientAddress, context, client);
|
|
63
|
+
const tokenInHederaId = getHederaTokenAddress(params.tokenIn);
|
|
64
|
+
const tokenOutHederaId = getHederaTokenAddress(params.tokenOut);
|
|
65
|
+
const tokenInEvm = getHederaTokenEVMAddress(params.tokenIn);
|
|
66
|
+
const wrappedHBarEvm = config.getWrappedHBarEvmAddress();
|
|
67
|
+
const isInputWrappedHBAR = tokenInEvm.toLowerCase() === wrappedHBarEvm.toLowerCase();
|
|
68
|
+
let amountInBase;
|
|
69
|
+
let spenderAccountId;
|
|
70
|
+
if (!isInputWrappedHBAR) {
|
|
71
|
+
const pool = await PoolFinderService.findPoolForTokens(tokenInHederaId, tokenOutHederaId, api);
|
|
72
|
+
const decimals = getTokenDecimals(pool, tokenInHederaId);
|
|
73
|
+
amountInBase = toBaseUnit(params.amountIn, decimals).toNumber();
|
|
74
|
+
spenderAccountId = config.getSwapRouterContractId().toString();
|
|
75
|
+
}
|
|
76
|
+
const swapParams = await SaucerSwapV2ParameterNormaliser.normaliseSwapV2Params(params, context, config, api, mirrorNode, client);
|
|
77
|
+
return {
|
|
78
|
+
swapParams,
|
|
79
|
+
prep: {
|
|
80
|
+
recipientAccountId,
|
|
81
|
+
tokenInHederaId,
|
|
82
|
+
tokenOutHederaId,
|
|
83
|
+
amountInBase,
|
|
84
|
+
spenderAccountId,
|
|
85
|
+
isInputWrappedHBAR,
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
async coreAction(normalisedParams, context, client) {
|
|
29
90
|
const mirrorNode = getMirrornodeService(context.mirrornodeService, client.ledgerId);
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
91
|
+
const { swapParams, prep } = normalisedParams;
|
|
92
|
+
await ensureTokenAssociated(prep.recipientAccountId, prep.tokenOutHederaId, context, client, mirrorNode);
|
|
93
|
+
if (!prep.isInputWrappedHBAR) {
|
|
94
|
+
const ownerAccountId = resolveSignerAccountId(context, client);
|
|
95
|
+
if (!ownerAccountId) {
|
|
96
|
+
throw new SaucerSwapError('Cannot resolve owner account for token allowance', 'OWNER_UNRESOLVED');
|
|
97
|
+
}
|
|
98
|
+
await ensureTokenAllowance(ownerAccountId, prep.spenderAccountId, prep.tokenInHederaId, prep.amountInBase, context, client, mirrorNode);
|
|
99
|
+
}
|
|
100
|
+
return HederaBuilder.executeTransaction(swapParams);
|
|
101
|
+
}
|
|
102
|
+
async secondaryAction(transaction, client, context) {
|
|
103
|
+
return await handleTransaction(transaction, client, context, postProcess);
|
|
36
104
|
}
|
|
37
|
-
|
|
105
|
+
async handleError(error, _context) {
|
|
38
106
|
const desc = 'Failed to swap tokens';
|
|
39
107
|
let message;
|
|
40
108
|
if (error instanceof SaucerSwapError) {
|
|
@@ -55,25 +123,11 @@ const swapV2 = async (client, context, params) => {
|
|
|
55
123
|
transactionId: '',
|
|
56
124
|
topicId: null,
|
|
57
125
|
scheduleId: null,
|
|
58
|
-
error: message
|
|
126
|
+
error: message,
|
|
59
127
|
},
|
|
60
|
-
humanMessage: message
|
|
128
|
+
humanMessage: message,
|
|
61
129
|
};
|
|
62
130
|
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const tool = (context) => ({
|
|
66
|
-
method: SWAP_V2_TOOL,
|
|
67
|
-
name: 'Swap V2',
|
|
68
|
-
description: swapV2Prompt(context),
|
|
69
|
-
parameters: swapV2Parameters(),
|
|
70
|
-
execute: swapV2,
|
|
71
|
-
outputParser: (rawOutput) => {
|
|
72
|
-
const json = JSON.parse(rawOutput);
|
|
73
|
-
return {
|
|
74
|
-
raw: json,
|
|
75
|
-
humanMessage: json.transactionId,
|
|
76
|
-
};
|
|
77
|
-
},
|
|
78
|
-
});
|
|
131
|
+
}
|
|
132
|
+
const tool = (context) => new SwapV2Tool(context);
|
|
79
133
|
export default tool;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { HederaBuilder, HederaParameterNormaliser, handleTransaction, } from "@hashgraph/hedera-agent-kit";
|
|
2
|
+
export async function hasSufficientAllowance(ownerAccountId, spenderAccountId, tokenId, amount, mirrorNode) {
|
|
3
|
+
try {
|
|
4
|
+
const { allowances } = await mirrorNode.getTokenAllowances(ownerAccountId, spenderAccountId);
|
|
5
|
+
const existing = allowances.find(a => a.token_id === tokenId);
|
|
6
|
+
return !!existing && existing.amount >= amount;
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export async function ensureTokenAllowance(ownerAccountId, spenderAccountId, tokenId, amount, context, client, mirrorNode) {
|
|
13
|
+
if (await hasSufficientAllowance(ownerAccountId, spenderAccountId, tokenId, amount, mirrorNode)) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const approveParams = await HederaParameterNormaliser.normaliseApproveTokenAllowance({
|
|
17
|
+
ownerAccountId,
|
|
18
|
+
spenderAccountId,
|
|
19
|
+
tokenApprovals: [{ tokenId, amount }],
|
|
20
|
+
}, context, client, mirrorNode);
|
|
21
|
+
const approveTx = HederaBuilder.approveTokenAllowance(approveParams);
|
|
22
|
+
await handleTransaction(approveTx, client, context, () => `Approved ${amount} of token ${tokenId} for spender ${spenderAccountId}`);
|
|
23
|
+
}
|
package/dist/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { TokenId } from "@
|
|
1
|
+
import { TokenId } from "@hiero-ledger/sdk";
|
|
2
2
|
import BigNumber from 'bignumber.js';
|
|
3
|
-
import { AccountResolver } from "hedera-agent-kit";
|
|
3
|
+
import { AccountResolver } from "@hashgraph/hedera-agent-kit";
|
|
4
4
|
/**
|
|
5
5
|
* Handles response formatting for both autonomous and manual modes
|
|
6
6
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "saucer-swap-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "SaucerSwap plugin for Hedera Agent Kit",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -25,10 +25,13 @@
|
|
|
25
25
|
"author": "",
|
|
26
26
|
"license": "MIT",
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"hedera-agent-kit": "^3.5.2",
|
|
29
28
|
"tsup": "^8.5.0",
|
|
30
29
|
"zod": "^3.0.0"
|
|
31
30
|
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"@hashgraph/hedera-agent-kit": "^4.0.0",
|
|
33
|
+
"@hiero-ledger/sdk": "^2.82.0"
|
|
34
|
+
},
|
|
32
35
|
"devDependencies": {
|
|
33
36
|
"@types/node": "^20.0.0",
|
|
34
37
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
@@ -41,5 +44,9 @@
|
|
|
41
44
|
"files": [
|
|
42
45
|
"dist/**/*",
|
|
43
46
|
"README.md"
|
|
44
|
-
]
|
|
47
|
+
],
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "https://github.com/saucerswaplabs/hedera-agent-kit-saucer-swap-plugin"
|
|
51
|
+
}
|
|
45
52
|
}
|
package/dist/service/type.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/service/utils.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export function hexToUint8Array(hex) {
|
|
2
|
-
const cleanHex = hex.startsWith('0x') ? hex.slice(2) : hex;
|
|
3
|
-
if (cleanHex.length % 2 !== 0) {
|
|
4
|
-
throw new Error('Invalid hex string length');
|
|
5
|
-
}
|
|
6
|
-
const array = new Uint8Array(cleanHex.length / 2);
|
|
7
|
-
for (let i = 0; i < array.length; i++) {
|
|
8
|
-
array[i] = parseInt(cleanHex.substr(i * 2, 2), 16);
|
|
9
|
-
}
|
|
10
|
-
return array;
|
|
11
|
-
}
|
|
12
|
-
export function buildEncodedPath(inputToken, hexFee, outputToken) {
|
|
13
|
-
const clean = (s) => s.startsWith('0x') ? s.slice(2) : s;
|
|
14
|
-
const pathParts = [];
|
|
15
|
-
pathParts.push(clean(inputToken));
|
|
16
|
-
pathParts.push(clean(hexFee));
|
|
17
|
-
pathParts.push(clean(outputToken));
|
|
18
|
-
return hexToUint8Array(pathParts.join(''));
|
|
19
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|