feat: add ability to customize readonlyCallExecutor

This commit is contained in:
Kyle Fang
2023-04-24 11:02:32 +08:00
parent 688a091ad8
commit c61ca39bae
5 changed files with 79 additions and 40 deletions

View File

@@ -5,14 +5,27 @@ import { getRoute } from './helpers/RouteHelper';
import { getYAmountFromXAmount } from './helpers/RateHelper';
import { runSpot, TxToBroadCast } from './helpers/SwapHelper';
import { findCurrencyByNativeAddress } from './utils/currencyUtils';
import {
defaultReadonlyCallExecutor,
ReadonlyCallExecutor,
} from './utils/readonlyCallExecutor';
export class AlexSDK {
constructor(
readonly readonlyCallExecutor: ReadonlyCallExecutor = defaultReadonlyCallExecutor
) {}
getFeeRate(from: Currency, to: Currency): Promise<bigint> {
return getLiquidityProviderFee(from, to, AMMSwapPool.ammTokens);
return getLiquidityProviderFee(
from,
to,
AMMSwapPool.ammTokens,
this.readonlyCallExecutor
);
}
getRouter(from: Currency, to: Currency): Promise<Currency[]> {
return getRoute(from, to, AMMSwapPool.ammTokens);
return getRoute(from, to, AMMSwapPool.ammTokens, this.readonlyCallExecutor);
}
getAmountTo(
@@ -20,7 +33,13 @@ export class AlexSDK {
fromAmount: bigint,
to: Currency
): Promise<bigint> {
return getYAmountFromXAmount(from, to, fromAmount, AMMSwapPool.ammTokens);
return getYAmountFromXAmount(
from,
to,
fromAmount,
AMMSwapPool.ammTokens,
this.readonlyCallExecutor
);
}
runSwap(

View File

@@ -1,14 +1,19 @@
import { AMMSwapPool } from '../utils/ammPool';
import { unwrapResponse } from 'clarity-codegen';
import { readonlyCall } from '../utils/readonlyCallExecutor';
import { Currency } from '../currency';
import { AlexSDK } from '../alexSDK';
import {
ReadonlyCallExecutor,
readonlyCallWith,
} from '../utils/readonlyCallExecutor';
export async function getLiquidityProviderFee(
tokenX: Currency,
tokenY: Currency,
ammPools: AMMSwapPool.PoolTokens[]
ammPools: AMMSwapPool.PoolTokens[],
readonlyCallExecutor: ReadonlyCallExecutor
): Promise<bigint> {
const readonlyCall = readonlyCallWith(readonlyCallExecutor);
const ammRoute = AMMSwapPool.getRoute(tokenX, tokenY, ammPools);
if (ammRoute.length === 0) {
const reachableInAmm = AMMSwapPool.reachableInAMM(tokenX, tokenY, ammPools);

View File

@@ -1,6 +1,9 @@
import { AMMSwapPool } from '../utils/ammPool';
import { unwrapResponse } from 'clarity-codegen';
import { readonlyCall } from '../utils/readonlyCallExecutor';
import {
ReadonlyCallExecutor,
readonlyCallWith,
} from '../utils/readonlyCallExecutor';
import { Currency } from '../currency';
import { AlexSDK } from '../alexSDK';
@@ -8,8 +11,10 @@ export const getYAmountFromXAmount = async (
tokenX: Currency,
tokenY: Currency,
fromAmount: bigint,
ammPools: AMMSwapPool.PoolTokens[]
ammPools: AMMSwapPool.PoolTokens[],
readonlyCallExecutor: ReadonlyCallExecutor
): Promise<bigint> => {
const readonlyCall = readonlyCallWith(readonlyCallExecutor);
const ammRoute = AMMSwapPool.getRoute(tokenX, tokenY, ammPools);
if (ammRoute.length === 0) {
const reachableInAMM = AMMSwapPool.reachableInAMM(tokenX, tokenY, ammPools);

View File

@@ -1,14 +1,19 @@
import { AMMSwapPool } from '../utils/ammPool';
import { unwrapResponse } from 'clarity-codegen';
import { readonlyCall } from '../utils/readonlyCallExecutor';
import {
ReadonlyCallExecutor,
readonlyCallWith,
} from '../utils/readonlyCallExecutor';
import { Currency } from '../currency';
import { AlexSDK } from '../alexSDK';
export async function getRoute(
from: Currency,
to: Currency,
pools: AMMSwapPool.PoolTokens[]
pools: AMMSwapPool.PoolTokens[],
readonlyCallExecutor: ReadonlyCallExecutor
): Promise<Currency[]> {
const readonlyCall = readonlyCallWith(readonlyCallExecutor);
const ammRoute = AMMSwapPool.getRoute(from, to, pools);
if (ammRoute.length > 0) {
return [from, ...ammRoute.map((a) => a.neighbour)];

View File

@@ -11,14 +11,16 @@ import { ReadOnlyFunctionOptions } from '@stacks/transactions/src/builders';
type Contracts = typeof AlexContracts;
type ReadonlyCallExecutor = (
export type ReadonlyCallExecutor = (
options: Pick<
ReadOnlyFunctionOptions,
'functionArgs' | 'functionName' | 'contractName' | 'contractAddress'
>
) => Promise<ClarityValue>;
const defaultReadonlyCallExecutor: ReadonlyCallExecutor = async (options) => {
export const defaultReadonlyCallExecutor: ReadonlyCallExecutor = async (
options
) => {
return callReadOnlyFunction({
...options,
senderAddress: CONTRACT_DEPLOYER,
@@ -28,32 +30,35 @@ const defaultReadonlyCallExecutor: ReadonlyCallExecutor = async (options) => {
});
};
export async function readonlyCall<
T extends keyof Contracts,
F extends keyof Contracts[T],
Descriptor extends Contracts[T][F]
>(
contractName: T,
functionName: F,
args: Descriptor extends ReadonlyFunctionDescriptor
? ParameterObjOfDescriptor<Descriptor>
: never
): Promise<
Descriptor extends ReadonlyFunctionDescriptor
? ReturnTypeOfDescriptor<Descriptor>
: never
> {
const functionDescriptor = AlexContracts[contractName][
functionName
] as any as ReadonlyFunctionDescriptor;
const clarityArgs = functionDescriptor.input.map((arg) =>
arg.type.encode(args[arg.name])
);
const result = await defaultReadonlyCallExecutor({
contractName,
functionName: String(functionName),
functionArgs: clarityArgs,
contractAddress: CONTRACT_DEPLOYER,
});
return functionDescriptor.output.decode(result);
}
export const readonlyCallWith = (executor: ReadonlyCallExecutor) => {
async function readonlyCall<
T extends keyof Contracts,
F extends keyof Contracts[T],
Descriptor extends Contracts[T][F]
>(
contractName: T,
functionName: F,
args: Descriptor extends ReadonlyFunctionDescriptor
? ParameterObjOfDescriptor<Descriptor>
: never
): Promise<
Descriptor extends ReadonlyFunctionDescriptor
? ReturnTypeOfDescriptor<Descriptor>
: never
> {
const functionDescriptor = AlexContracts[contractName][
functionName
] as any as ReadonlyFunctionDescriptor;
const clarityArgs = functionDescriptor.input.map((arg) =>
arg.type.encode(args[arg.name])
);
const result = await executor({
contractName,
functionName: String(functionName),
functionArgs: clarityArgs,
contractAddress: CONTRACT_DEPLOYER,
});
return functionDescriptor.output.decode(result);
}
return readonlyCall;
};