Skip to content

Commit

Permalink
feat: dedust swap added
Browse files Browse the repository at this point in the history
  • Loading branch information
Ho3einWave committed Oct 1, 2024
1 parent 234c513 commit 8e4b187
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 12 deletions.
Binary file modified bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"peerDependencies": {
"@ton/ton": "^15.0.0",
"typescript": "^5.0.0",
"@dedust/sdk": "^0.8.7",
"@ston-fi/sdk": "2.0.0-rc.5"
},
"dependencies": {
Expand Down
162 changes: 150 additions & 12 deletions src/services/swap/swap.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import { address, Cell, SenderArguments, toNano } from '@ton/ton';
import {
Address,
address,
beginCell,
Cell,
OpenedContract,
SenderArguments,
toNano,
} from '@ton/ton';
import {
DEDUST_SWAP,
DEDUST_TRANSFER,
feeWallet,
PTON_V2,
STON_ROUTER_V1,
Expand All @@ -10,19 +20,37 @@ import { Services } from '../../core/services';
import { BestRoute } from '../../types/router';
import { Balance, CustomPayload } from '../../types/swap';
import { DEX, pTON } from '@ston-fi/sdk';
import {
Asset,
Factory,
JettonRoot,
MAINNET_FACTORY_ADDR,
Pool,
PoolType,
ReadinessStatus,
Vault,
VaultJetton,
VaultNative,
} from '@dedust/sdk';
import { sleep } from '@lifeomic/attempt';

export class Swap extends Services {
/**
* swap
*/
public async swap(userWalletAddress: string, bestRoute: BestRoute) {
switch (bestRoute.selected_pool.dex) {
case 'stonfi':
return await this.createStonSwap(userWalletAddress, bestRoute);
case 'dedust':
break;
default:
break;
try {
switch (bestRoute.selected_pool.dex) {
case 'stonfi':
return await this.createStonSwap(userWalletAddress, bestRoute);
case 'dedust':
return await this.createDedustSwap(userWalletAddress, bestRoute);

default:
break;
}
} catch (error) {
console.log(error);
}
}

Expand Down Expand Up @@ -122,13 +150,24 @@ export class Swap extends Services {
: undefined,
});
}
return swapTxParams;
return swapTxParams satisfies SenderArguments;
}

private async createDedustSwap(userWalletAddress: string, bestRoute: BestRoute) {
let [asset0, asset1, asset2] = bestRoute.pool_data.route;
let [jetton0, jetton1, jetton2] = bestRoute.pool_data.route;

let Asset0: Asset;
let Asset1: Asset;
let Asset2: Asset;
let Vault0: OpenedContract<VaultNative> | OpenedContract<VaultJetton>;
let Vault2: OpenedContract<VaultNative> | OpenedContract<VaultJetton>;
let PoolB: OpenedContract<Pool>;
let RequestAddress: Address;
let StoreAddress: Address;

let TxAmount = toNano('0.3');

let jettonData: Balance | undefined;
let swapTxParams: SenderArguments | null = null;
const isMintless = supportedMintlessTokens.includes(bestRoute.selected_pool.token0_address);
if (isMintless) {
jettonData = await this.client.tonapi.getJettonData(
Expand All @@ -139,7 +178,6 @@ export class Swap extends Services {

let customPayload: Cell | undefined;
let stateInit: { code: Cell; data: Cell } | undefined;

if (isMintless && jettonData?.extensions?.includes('custom_payload')) {
const offerJettonCustomPayload = await this.client.tonapi.getCustomPayload(
userWalletAddress,
Expand All @@ -161,5 +199,105 @@ export class Swap extends Services {
data: stateInitCell.loadRef(),
};
}
const factory = this.client.tonClient.open(Factory.createFromAddress(MAINNET_FACTORY_ADDR));
if (jetton0 == 'EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c') {
if (jetton2 && jetton2 !== '') {
throw new Error('This request can not process!');
}

Asset0 = Asset.native();
Vault0 = this.client.tonClient.open(await factory.getNativeVault());
} else {
Asset0 = Asset.jetton(Address.parse(jetton0));
Vault0 = this.client.tonClient.open(
await factory.getJettonVault(Address.parse(jetton0)),
);
}
await sleep(500);
if (jetton1 == 'EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c') {
Asset1 = Asset.native();
} else {
Asset1 = Asset.jetton(Address.parse(jetton1));
}
await sleep(500);
const PoolA = this.client.tonClient.open(
await factory.getPool(PoolType.VOLATILE, [Asset0, Asset1]),
);
if (jetton2 && jetton2 !== '') {
if (jetton2 == 'EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c') {
Asset2 = Asset.native();
} else {
Asset2 = Asset.jetton(Address.parse(jetton2));
}
await sleep(500);

PoolB = this.client.tonClient.open(
await factory.getPool(PoolType.VOLATILE, [Asset1, Asset2]),
);
}

let PAY_LOAD: Cell;
let pay: Cell;
if (jetton0 == 'EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c') {
// @ts-expect-error because dedust doesn't let user to build custom payloads
PAY_LOAD = Vault.packSwapParams({});

StoreAddress = PoolA.address;
RequestAddress = Vault0.address;

TxAmount = BigInt(bestRoute.pool_data.pay) + toNano('0.1');

pay = beginCell()
.storeUint(DEDUST_SWAP, 32)
.storeUint(0, 64)
.storeCoins(BigInt(bestRoute.pool_data.pay))
.storeAddress(StoreAddress)
.storeUint(0, 1)
.storeCoins(0)
.storeMaybeRef(null)
.storeRef(PAY_LOAD)
.endCell();
} else {
const JRoot = this.client.tonClient.open(
JettonRoot.createFromAddress(Address.parse(jetton0)),
);
const JWallet = this.client.tonClient.open(
await JRoot.getWallet(Address.parseRaw(userWalletAddress)),
);

StoreAddress = Vault0.address;
RequestAddress = JWallet.address;

if (jetton2 == '') {
PAY_LOAD = VaultJetton.createSwapPayload({
poolAddress: Address.parse(PoolA.address.toString()),
});
} else {
PAY_LOAD = VaultJetton.createSwapPayload({
poolAddress: Address.parse(PoolA.address.toString()),
limit: BigInt(bestRoute.pool_data.innerMinimumReceive),
next: {
poolAddress: PoolB!.address,
},
});
}

pay = beginCell()
.storeUint(DEDUST_TRANSFER, 32)
.storeUint(0, 64)
.storeCoins(BigInt(bestRoute.pool_data.pay))
.storeAddress(StoreAddress)
.storeAddress(Address.parseRaw(userWalletAddress))
.storeMaybeRef(customPayload ? customPayload : null)
.storeCoins(toNano('0.25'))
.storeMaybeRef(PAY_LOAD)
.endCell();
}
return {
to: RequestAddress,
value: isMintless ? TxAmount + toNano(0.07) : TxAmount,
body: pay,
init: stateInit,
} satisfies SenderArguments;
}
}
12 changes: 12 additions & 0 deletions src/services/swap/swap.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { beforeAll, beforeEach, expect, test } from 'bun:test';
import { MyTonSwapClient } from '../../core/client';
import { toNano } from '@ton/ton';
import { sleep } from 'bun';
let client: MyTonSwapClient;
const userWallet = 'UQAaIQh7jVlOEylI8jM8OI1O-yYGZRqUfJRxuR-K57pskl9I';
const hmstrJetton = 'EQAJ8uWd7EBqsmpSWaRdf_I-8R8-XHwh3gsNKhy-UrdrPcUo';
Expand All @@ -17,3 +18,14 @@ test('it should get data for swap from stonfi', async () => {
expect(swap?.value).not.toBeUndefined();
expect(swap?.value).toBeGreaterThan(toNano(1));
});

test('it should get data for swap from dedust', async () => {
await sleep(1000);
const TON = await client.assets.getExactAsset('TON');
const NOT = await client.assets.getExactAsset('NOT');
const bestRoute = await client.router.findBestRoute(TON!.address, NOT!.address, 1, 1, 'dedust');
const swap = await client.swap.swap(userWallet, bestRoute);
expect(swap).toBeObject();

Check failure on line 28 in src/services/swap/swap.test.ts

View workflow job for this annotation

GitHub Actions / Bun Build

error: expect(received).toBeObject()

Expected value to be an object Received: undefined at /home/runner/work/sdk/sdk/src/services/swap/swap.test.ts:28:18
expect(swap?.value).not.toBeUndefined();
expect(swap?.value).toBeGreaterThan(toNano(1));
});

0 comments on commit 8e4b187

Please sign in to comment.