Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/strategies #53

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions docs/guides/core/node.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,14 @@ const txBuilder = new TxBuilderLucidV3(
// Do your swap like normal.
const result = await txBuilder.swap({ ...args });
```

### Query Providers

To access a QueryProvider, use this:

```ts
import { QueryProviderSundaeSwap } from "@sundaeswap/core";
const queryProvider = new QueryProviderSundaeSwap("preview");
const ident = "...uniqueIdent...";
const result = await queryProvider.findPoolData({ ident });
```
10 changes: 10 additions & 0 deletions packages/core/src/@types/configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ export interface IZapConfigArgs extends IOrderConfigArgs {
swapSlippage?: number;
}

/**
* The arguments configuration for building a valid Strategy.
*/
export interface IStrategyConfigArgs extends IOrderConfigArgs {
suppliedAssets: AssetAmount<IAssetAmountMetadata>[];
orderAddresses: TOrderAddresses;
ownerPublicKey: string;
ownerAddress?: string;
}

/**
* The arguments configuration for building a valid Withdraw.
*/
Expand Down
67 changes: 67 additions & 0 deletions packages/core/src/Configs/StrategyConfig.class.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { AssetAmount, IAssetAmountMetadata } from "@sundaeswap/asset";

import {
IPoolData,
IStrategyConfigArgs,
TOrderAddresses,
} from "../@types/index.js";
import { Config } from "../Abstracts/Config.abstract.class.js";
import { OrderConfig } from "../Abstracts/OrderConfig.abstract.class.js";

/**
* The main config class for building valid arguments for listing a strategy order.
*/
export class StrategyConfig extends OrderConfig<IStrategyConfigArgs> {
suppliedAssets?: AssetAmount<IAssetAmountMetadata>[];

ownerPublicKey?: string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the ownerPublicKey the authorization key? if so, lets avoid the word owner;

instead, lets use the term executorPublicKey, to emphasize that it can (and usually will be) different from the owner.


constructor(args?: IStrategyConfigArgs) {
super();

args && this.setFromObject(args);
}

setSuppliedAssets(assets: AssetAmount<IAssetAmountMetadata>[]) {
this.suppliedAssets = assets;
return this;
}

setOwnerPublicKey(publicKey: string) {
this.ownerPublicKey = publicKey;
return this;
}

buildArgs(): IStrategyConfigArgs {
this.validate();

return {
pool: this.pool as IPoolData,
orderAddresses: this.orderAddresses as TOrderAddresses,
ownerPublicKey: this.ownerPublicKey as string,
suppliedAssets: this
.suppliedAssets as AssetAmount<IAssetAmountMetadata>[],
referralFee: this.referralFee,
};
}

setFromObject({
orderAddresses,
suppliedAssets,
referralFee,
}: IStrategyConfigArgs): void {
this.setOrderAddresses(orderAddresses);
this.setSuppliedAssets(suppliedAssets);
referralFee && this.setReferralFee(referralFee);
}

validate(): never | void {
super.validate();

if (!this.suppliedAssets) {
throw new Error(
"You did not provided funding for this listed strategy! Make sure you supply the necessary assets with .setSuppliedAssets()"
);
}
}
}
40 changes: 40 additions & 0 deletions packages/core/src/DatumBuilders/DatumBuilder.Lucid.V3.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ export interface IDatumBuilderBaseV3Args {
scooperFee: bigint;
}

/**
* The arguments from building a strategy transaction against
* a V3 pool contract.
*/
export interface IDatumBuilderStrategyV3Args extends IDatumBuilderBaseV3Args {
ownerPublicKey: string;
}

/**
* The arguments from building a swap transaction against
* a V3 pool contract.
Expand Down Expand Up @@ -283,6 +291,38 @@ export class DatumBuilderLucidV3 implements DatumBuilder {
};
}

buildStrategyDatum({
destinationAddress,
ident,
ownerAddress,
ownerPublicKey,
scooperFee,
}: IDatumBuilderStrategyV3Args): TDatumResult<V3Types.TOrderDatum> {
const strategyDatum: V3Types.TOrderDatum = {
destination: this.buildDestinationAddresses(destinationAddress).schema,
extension: Data.void(),
order: {
Strategy: {
auth: {
Signature: {
bytes: ownerPublicKey,
},
},
},
},
owner: this.buildOwnerDatum(ownerAddress ?? destinationAddress.address)
.schema,
poolIdent: this.buildPoolIdent(ident),
scooperFee: scooperFee,
};
const inline = Data.to(strategyDatum, V3Types.OrderDatum);
return {
hash: LucidHelper.inlineDatumToHash(inline),
inline,
schema: strategyDatum,
};
}

/**
* Creates a redeemer datum for minting a new pool. This is attached to the new assets that
* creating a new pool mints on the blockchain. See {@link Lucid.TxBuilderLucidV3} for more
Expand Down
11 changes: 10 additions & 1 deletion packages/core/src/DatumBuilders/contracts/contracts.v3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,15 @@ export type TSingletonValue = Data.Static<typeof SingletonValueSchema>;
export const SingletonValue =
SingletonValueSchema as unknown as TSingletonValue;

export const StrategyAuthorizationSchema = Data.Enum([
Data.Object({ Signature: Data.Object({ bytes: Data.Bytes() }) }),
Data.Object({ Script: Data.Object({ bytes: Data.Bytes() }) }),
]);

export const StrategySchema = Data.Object({
auth: StrategyAuthorizationSchema,
});

export const SwapSchema = Data.Object({
offer: SingletonValueSchema,
minReceived: SingletonValueSchema,
Expand All @@ -108,7 +117,7 @@ export const DonationSchema = Data.Object({
});

export const OrderSchema = Data.Enum([
Data.Object({ Strategies: Data.Nullable(Data.Literal("TODO")) }),
Data.Object({ Strategy: StrategySchema }),
Data.Object({ Swap: SwapSchema }),
Data.Object({ Deposit: DepositSchema }),
Data.Object({ Withdrawal: WithdrawalSchema }),
Expand Down
46 changes: 46 additions & 0 deletions packages/core/src/TxBuilders/TxBuilder.Lucid.V3.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type {
IDepositConfigArgs,
IMintV3PoolConfigArgs,
IOrderRouteSwapArgs,
IStrategyConfigArgs,
ISundaeProtocolParamsFull,
ISundaeProtocolReference,
ISundaeProtocolValidatorFull,
Expand All @@ -34,6 +35,7 @@ import { TxBuilder } from "../Abstracts/TxBuilder.abstract.class.js";
import { CancelConfig } from "../Configs/CancelConfig.class.js";
import { DepositConfig } from "../Configs/DepositConfig.class.js";
import { MintV3PoolConfig } from "../Configs/MintV3PoolConfig.class.js";
import { StrategyConfig } from "../Configs/StrategyConfig.class.js";
import { SwapConfig } from "../Configs/SwapConfig.class.js";
import { WithdrawConfig } from "../Configs/WithdrawConfig.class.js";
import { ZapConfig } from "../Configs/ZapConfig.class.js";
Expand Down Expand Up @@ -1145,6 +1147,50 @@ export class TxBuilderLucidV3 extends TxBuilder {
return sortedUtxos;
}

async strategy(args: IStrategyConfigArgs) {
// The difference between orderAddresses and ownerAddress is:
// orderAddresses tell you where the result is going next (possibly chained).
// the ownerAddress tells you who should always be able to cancel the order at any step.

const {
pool,
orderAddresses,
suppliedAssets,
ownerAddress,
ownerPublicKey,
referralFee,
} = new StrategyConfig(args).buildArgs();

const { inline } = this.datumBuilder.buildStrategyDatum({
ident: pool.ident,
destinationAddress: orderAddresses.DestinationAddress,
ownerPublicKey: args.ownerPublicKey,
scooperFee: await this.getMaxScooperFeeAmount(),
});

const tx = this.newTxInstance(referralFee);

const payment = SundaeUtils.accumulateSuppliedAssets({
scooperFee: await this.getMaxScooperFeeAmount(),
suppliedAssets,
});

tx.payToContract(
// This might need to be a different script address, not sure.
await this.generateScriptAddress(
"order.spend",
orderAddresses.DestinationAddress.address
),
{ inline },
payment
);

return this.completeTx({
tx,
datum: inline,
});
}

private async completeTx({
tx,
datum,
Expand Down
Loading