Skip to content

Instantly share code, notes, and snippets.

@satanworker
Created April 7, 2024 14:10
Show Gist options
  • Select an option

  • Save satanworker/7be5914dcd8276197c1cef7297a2f574 to your computer and use it in GitHub Desktop.

Select an option

Save satanworker/7be5914dcd8276197c1cef7297a2f574 to your computer and use it in GitHub Desktop.

Revisions

  1. satanworker created this gist Apr 7, 2024.
    279 changes: 279 additions & 0 deletions dedust.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,279 @@
    // import { Address } from "@ton/core";
    import { JettonsService } from "../../jettons/jettonsService";
    import { WalletService } from "../../wallet/walletService";
    import { PROXY_TON, Web3TransportService } from "../../web3infra/web3TransportService";
    import { zeroTONtopTON } from "../../web3infra/zeroTONtopTON";
    import { Asset, Factory, MAINNET_FACTORY_ADDR, PoolType, VaultNative, ReadinessStatus, JettonRoot, VaultJetton, Pool } from '@dedust/sdk';
    import { Address, OpenedContract, Sender, toNano, TonClient, TonClient4, WalletContractV3R1, WalletContractV4 } from "@ton/ton";
    import { SimulateSwap, Swap } from "../swapService";

    export class Dedust {

    private jettonService: JettonsService;
    private walletService: WalletService
    private web3TransportService: Web3TransportService

    constructor(
    jettonService: JettonsService,
    walletService: WalletService,
    web3TransportService: Web3TransportService,
    ) {
    this.jettonService = jettonService;
    this.walletService = walletService
    this.web3TransportService = web3TransportService
    }


    async simulate({ offerJettonAddress, askJettonAddress, amount }: Omit<SimulateSwap, 'deFi'>): Promise<Omit<SimulateSwap, 'deFi'> & {
    amountOutInNano: bigint
    }> {
    const client = this.web3TransportService.TonClient4;
    const factory = client.open(Factory.createFromAddress(MAINNET_FACTORY_ADDR));
    const getEstimatedSwap = async (offerAddress: string, askAddress: string, isOfferNative: boolean, amountIn: bigint) => {
    const jettonRoot = client.open(JettonRoot.createFromAddress(Address.parse(isOfferNative ? askAddress : offerAddress)));
    const poolAddress = await factory.getPoolAddress({
    poolType: PoolType.VOLATILE,
    assets: [Asset.native(), Asset.jetton(jettonRoot.address)],
    });
    const pool = client.open(Pool.createFromAddress(poolAddress));

    const estimatedSwap = await pool.getEstimatedSwapOut({
    assetIn: isOfferNative ? Asset.native() : Asset.jetton(jettonRoot.address),
    amountIn,
    });

    return {
    offerJettonAddress,
    askJettonAddress,
    amount,
    amountOutInNano: estimatedSwap.amountOut,
    }
    };
    const isOfferNative = zeroTONtopTON(offerJettonAddress) === PROXY_TON;
    const isAskNative = zeroTONtopTON(askJettonAddress) === PROXY_TON;
    const amountIn = BigInt(amount);

    if (isOfferNative || isAskNative) {
    return await getEstimatedSwap(offerJettonAddress, askJettonAddress, isOfferNative, amountIn)
    } else {
    const estimatedOffer = await getEstimatedSwap(offerJettonAddress, askJettonAddress, false, amountIn);
    return await getEstimatedSwap(offerJettonAddress, askJettonAddress, true, estimatedOffer.amountOutInNano)
    }
    }

    async swap({ userId, accountIndex, offerJettonAddress, askJettonAddress, queryId, offerAmount }: Omit<Swap, 'deFi'>) {
    const secretKey = await this.walletService.getTonWalletSecretKey({
    userId,
    accountIndex
    })

    const client = this.web3TransportService.TonClient4
    const wallet = await this.walletService.getTONWallet4({ userId, accountIndex })

    let contractMyWallet = client.open(wallet);
    const sender = contractMyWallet.sender(secretKey);

    const TON = Asset.native();
    const factory = client.open(Factory.createFromAddress(MAINNET_FACTORY_ADDR));
    const tonVault = client.open(await factory.getNativeVault());

    if ((await tonVault.getReadinessStatus()) !== ReadinessStatus.READY) {
    throw new Error('Vault (TON) does not exist.');
    }

    if (zeroTONtopTON(offerJettonAddress) === PROXY_TON) {
    await this.handleTonToJettonSwap({ client, factory, sender, askJettonAddress, offerAmount, TON, tonVault, queryId });
    } else if (zeroTONtopTON(askJettonAddress) === PROXY_TON) {
    await this.handleJettonToTonSwap({ client, factory, contractMyWallet, sender, offerJettonAddress, offerAmount, TON, queryId });
    } else {
    await this.handleJettonToJettonSwap({ client, factory, contractMyWallet, sender, offerJettonAddress, askJettonAddress, offerAmount, TON, queryId });
    }
    }

    async handleTonToJettonSwap({ client, factory, sender, askJettonAddress, offerAmount, TON, tonVault, queryId }: {
    client: TonClient4,
    factory: OpenedContract<Factory>,
    sender: Sender,
    askJettonAddress: string,
    offerAmount: string
    TON: Asset
    tonVault: OpenedContract<VaultNative>,
    queryId: number
    }) {
    console.log('TON > Jetton');
    const JETTON = Asset.jetton(Address.parse(askJettonAddress));
    const TON_JETTON = client.open(await factory.getPool(PoolType.VOLATILE, [TON, JETTON]));
    if ((await TON_JETTON.getReadinessStatus()) !== ReadinessStatus.READY) {
    throw new Error('Pool does not exist.');
    }
    await tonVault.sendSwap(sender, {
    poolAddress: TON_JETTON.address,
    amount: BigInt(offerAmount),
    gasAmount: toNano(JettonsService.defaultTONAmount),
    queryId,
    });
    }

    async handleJettonToTonSwap({ client, factory, contractMyWallet, sender, offerJettonAddress, offerAmount, TON, queryId }: {
    client: TonClient4,
    factory: OpenedContract<Factory>,
    contractMyWallet: OpenedContract<WalletContractV3R1>,
    sender: Sender,
    TON: Asset,
    offerJettonAddress: string,
    offerAmount: string,
    queryId: number
    }) {
    console.log('Jetton > TON');
    const jettonRoot = client.open(JettonRoot.createFromAddress(Address.parse(offerJettonAddress)));
    const jettonWallet = client.open(await jettonRoot.getWallet(contractMyWallet.address));
    const jettonVault = client.open(await factory.getJettonVault(Address.parse(offerJettonAddress)));
    const JETTON = Asset.jetton(Address.parse(offerJettonAddress));
    const JETTON_TON = client.open(await factory.getPool(PoolType.VOLATILE, [JETTON, TON]));
    if ((await JETTON_TON.getReadinessStatus()) !== ReadinessStatus.READY) {
    throw new Error('Pool does not exist.');
    }
    await jettonWallet.sendTransfer(sender, toNano("0.3"), {
    amount: BigInt(offerAmount),
    destination: jettonVault.address,
    responseAddress: contractMyWallet.address,
    forwardAmount: toNano("0.01"),
    queryId,
    forwardPayload: VaultJetton.createSwapPayload({ poolAddress: JETTON_TON.address }),
    });
    }

    async handleJettonToJettonSwap({ client, factory, contractMyWallet, sender, askJettonAddress, offerJettonAddress, offerAmount, TON, queryId }: {
    client: TonClient4,
    factory: OpenedContract<Factory>,
    contractMyWallet: OpenedContract<WalletContractV3R1>,
    sender: Sender,
    askJettonAddress: string,
    offerJettonAddress: string,
    offerAmount: string,
    TON: Asset,
    queryId: number
    }) {
    console.log('Jetton -> Jetton');
    const offerRoot = client.open(JettonRoot.createFromAddress(Address.parse(offerJettonAddress)));
    const offerWallet = client.open(await offerRoot.getWallet(contractMyWallet.address));
    const offerVault = client.open(await factory.getJettonVault(Address.parse(offerJettonAddress)));
    const OFFER_JETTON = Asset.jetton(Address.parse(offerJettonAddress));
    const ASK_JETTON = Asset.jetton(Address.parse(askJettonAddress));
    const TON_JETTON = client.open(await factory.getPool(PoolType.VOLATILE, [TON, OFFER_JETTON]));
    if ((await TON_JETTON.getReadinessStatus()) !== ReadinessStatus.READY) {
    throw new Error('First pool does not exist.');
    }
    const JETTON_TON = client.open(await factory.getPool(PoolType.VOLATILE, [TON, ASK_JETTON]));
    if ((await JETTON_TON.getReadinessStatus()) !== ReadinessStatus.READY) {
    throw new Error('Second pool does not exist.');
    }
    await offerWallet.sendTransfer(sender, toNano("0.3"), {
    amount: BigInt(offerAmount),
    destination: offerVault.address,
    responseAddress: contractMyWallet.address,
    forwardAmount: toNano("0.01"),
    queryId,
    forwardPayload: VaultJetton.createSwapPayload({
    poolAddress: TON_JETTON.address,
    // limit: minimalAmountOut,
    next: {
    poolAddress: JETTON_TON.address,
    },
    }),
    },)
    }

    // async swap(userId: number, accountIndex: number, offerJettonAddress: string, askJettonAddress: string, queryId: string, offerAmount: string) {

    // const client = new TonClient4({
    // endpoint: 'https://mainnet-v4.tonhubapi.com',
    // });
    // let workchain = 0;
    // let keys = await this.walletService.TONKeyPair({ userId, accountIndex })
    // let wallet = WalletContractV3R1.create({ workchain, publicKey: keys.publicKey });
    // let contractMyWallet = client.open(wallet);
    // const sender = contractMyWallet.sender(keys.secretKey);
    // const TON = Asset.native();
    // // ======================================================================
    // const factory = client.open(Factory.createFromAddress(MAINNET_FACTORY_ADDR));
    // const tonVault = client.open(await factory.getNativeVault());
    // // =====================================================================
    // if ((await tonVault.getReadinessStatus()) !== ReadinessStatus.READY) {
    // throw new Error('Vault (TON) does not exist.');
    // }
    // // =====================================================================
    // if (zeroTONtopTON(offerJettonAddress) === PROXY_TON) {
    // console.log('TON > Jettton')
    // const JETTON = Asset.jetton(Address.parse(askJettonAddress));
    // const TON_JETTON = client.open(await factory.getPool(PoolType.VOLATILE, [TON, JETTON]));

    // if ((await TON_JETTON.getReadinessStatus()) !== ReadinessStatus.READY) {
    // throw new Error('Pool (TON, SCALE) does not exist.');
    // }
    // try {
    // await tonVault.sendSwap(sender, {
    // poolAddress: TON_JETTON.address,
    // amount: toNano(offerAmount),
    // gasAmount: toNano("0.25"),
    // });
    // } catch (error) {
    // console.log(error)
    // }
    // } else if (zeroTONtopTON(askJettonAddress) === PROXY_TON) {
    // console.log('Jettton > TON')
    // const jettonRoot = client.open(JettonRoot.createFromAddress(Address.parse(offerJettonAddress)));
    // const jettonWallet = client.open(await jettonRoot.getWallet(contractMyWallet.address));
    // const jettonVault = client.open(await factory.getJettonVault(Address.parse(offerJettonAddress)));
    // const JETTON = Asset.jetton(Address.parse(offerJettonAddress));
    // const JETTON_TON = client.open(await factory.getPool(PoolType.VOLATILE, [JETTON, TON]));
    // if ((await JETTON_TON.getReadinessStatus()) !== ReadinessStatus.READY) {
    // throw new Error('Pool (TON, SCALE) does not exist.');
    // }
    // try {
    // await jettonWallet.sendTransfer(sender, toNano("0.3"), {
    // amount: toNano(offerAmount),
    // destination: jettonVault.address,
    // responseAddress: contractMyWallet.address,
    // forwardAmount: toNano("0.2"),
    // forwardPayload: VaultJetton.createSwapPayload({ poolAddress: JETTON_TON.address }),
    // });
    // } catch (error) {
    // console.log(error)
    // }
    // } else {
    // console.log('Jettton -> Jettton')
    // const offerRoot = client.open(JettonRoot.createFromAddress(Address.parse(offerJettonAddress)));
    // const offerWallet = client.open(await offerRoot.getWallet(contractMyWallet.address));
    // const offerVault = client.open(await factory.getJettonVault(Address.parse(offerJettonAddress)));
    // const OFFER_JETTON = Asset.jetton(Address.parse(offerJettonAddress));
    // const ASK_JETTON = Asset.jetton(Address.parse(askJettonAddress));
    // const TON_JETTON = client.open(await factory.getPool(PoolType.VOLATILE, [TON, OFFER_JETTON]));
    // if ((await TON_JETTON.getReadinessStatus()) !== ReadinessStatus.READY) {
    // throw new Error('Pool (TON, SCALE) does not exist.');
    // }
    // const JETTON_TON = client.open(await factory.getPool(PoolType.VOLATILE, [TON, ASK_JETTON]));
    // if ((await JETTON_TON.getReadinessStatus()) !== ReadinessStatus.READY) {
    // throw new Error('Pool (TON, SCALE) does not exist.');
    // }
    // try {
    // await offerWallet.sendTransfer(sender, toNano("0.3"), {
    // amount: toNano(offerAmount),
    // destination: offerVault.address,
    // responseAddress: contractMyWallet.address,
    // forwardAmount: toNano("0.25"),
    // forwardPayload: VaultJetton.createSwapPayload({
    // poolAddress: TON_JETTON.address,
    // // limit: minimalAmountOut,
    // next: {
    // poolAddress: JETTON_TON.address,
    // },
    // }),
    // },)
    // } catch (error) {
    // console.log(error)
    // }

    // }
    // }
    }