Skip to content

Vyfi

VyFi DEX Module.

AtoB dataclass

Bases: PlutusData

A to B swap direction.

Source code in src/charli3_dendrite/dexs/amm/vyfi.py
83
84
85
86
87
88
@dataclass
class AtoB(PlutusData):
    """A to B swap direction."""

    CONSTR_ID = 3
    min_receive: int

BtoA dataclass

Bases: PlutusData

B to A swap direction.

Source code in src/charli3_dendrite/dexs/amm/vyfi.py
91
92
93
94
95
96
@dataclass
class BtoA(PlutusData):
    """B to A swap direction."""

    CONSTR_ID = 4
    min_receive: int

Deposit dataclass

Bases: PlutusData

Deposit assets into the pool.

Source code in src/charli3_dendrite/dexs/amm/vyfi.py
51
52
53
54
55
56
@dataclass
class Deposit(PlutusData):
    """Deposit assets into the pool."""

    CONSTR_ID = 0
    min_lp_receive: int

LPFlushA dataclass

Bases: PlutusData

Flush LP tokens from A.

Source code in src/charli3_dendrite/dexs/amm/vyfi.py
76
77
78
79
80
@dataclass
class LPFlushA(PlutusData):
    """Flush LP tokens from A."""

    CONSTR_ID = 2

VyFiCPPState

Bases: AbstractConstantProductPoolState

VyFi CPP state.

Source code in src/charli3_dendrite/dexs/amm/vyfi.py
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
class VyFiCPPState(AbstractConstantProductPoolState):
    """VyFi CPP state."""

    _batcher = Assets(lovelace=1900000)
    _deposit = Assets(lovelace=2000000)
    _pools: ClassVar[dict[str, VyFiPoolDefinition] | None] = None
    _pools_refresh: ClassVar[float] = time.time()
    lp_fee: int = 0
    bar_fee: int = 0

    @classmethod
    def dex(cls) -> str:
        return "VyFi"

    @classmethod
    @property
    def pools(cls) -> dict[str, VyFiPoolDefinition]:
        """Get the pools."""
        if cls._pools is None or (time.time() - cls._pools_refresh) > 3600:
            cls._pools = {}
            for p in requests.get("https://api.vyfi.io/lp?networkId=1&v2=true").json():
                p["json"] = json.loads(p["json"])
                cls._pools[
                    p["json"]["mainNFT"]["currencySymbol"]
                ] = VyFiPoolDefinition.model_validate(p)
            cls._pools_refresh = time.time()

        return cls._pools

    @classmethod
    def order_selector(cls) -> list[str]:
        return [p.orderValidatorUtxoAddress for p in cls.pools.values()]

    @classmethod
    def pool_selector(cls) -> PoolSelector:
        return PoolSelector(
            addresses=[pool.poolValidatorUtxoAddress for pool in cls.pools.values()],
        )

    @property
    def swap_forward(self) -> bool:
        return False

    @property
    def stake_address(self) -> Address:
        return Address.from_primitive(
            VyFiCPPState.pools[self.pool_id].orderValidatorUtxoAddress,
        )

    @classmethod
    def order_datum_class(self) -> type[VyFiOrderDatum]:
        return VyFiOrderDatum

    @classmethod
    def pool_datum_class(cls) -> type[VyFiPoolDatum]:
        return VyFiPoolDatum

    @property
    def pool_id(self) -> str:
        """A unique identifier for the pool."""
        return self.pool_nft.unit()

    @property
    def volume_fee(self) -> int:
        return self.lp_fee + self.bar_fee

    @classmethod
    def extract_pool_nft(cls, values: dict[str, Any]) -> Optional[Assets]:
        """Extract the dex nft from the UTXO.

        Some DEXs put a DEX nft into the pool UTXO.

        This function checks to see if the DEX nft is in the UTXO if the DEX policy is
        defined.

        If the dex nft is in the values, this value is skipped because it is assumed
        that this utxo has already been parsed.

        Args:
            values: The pool UTXO inputs.

        Returns:
            Assets: None or the dex nft.
        """
        assets = values["assets"]

        # If the dex nft is in the values, it's been parsed already
        if "pool_nft" in values:
            assert any([p in cls.pools for p in values["pool_nft"]])
            if isinstance(values["pool_nft"], dict):
                pool_nft = Assets(root=values["pool_nft"])
            else:
                pool_nft = values["pool_nft"]

        # Check for the dex nft
        else:
            nfts = [asset for asset, quantity in assets.items() if asset in cls.pools]
            if len(nfts) < 1:
                if len(assets) == 0:
                    raise NoAssetsError(
                        f"{cls.__name__}: No assets supplied.",
                    )
                else:
                    raise NotAPoolError(
                        f"{cls.__name__}: Pool must have one DEX NFT token.",
                    )
            pool_nft = Assets(**{nfts[0]: assets.root.pop(nfts[0])})
            values["pool_nft"] = pool_nft

        values["lp_fee"] = cls.pools[pool_nft.unit()].json_.feesSettings.liqFee
        values["bar_fee"] = cls.pools[pool_nft.unit()].json_.feesSettings.barFee

        return pool_nft

    @classmethod
    def post_init(cls, values):
        super().post_init(values)

        assets = values["assets"]
        datum = VyFiPoolDatum.from_cbor(values["datum_cbor"])

        assets.root[assets.unit(0)] -= datum.token_a_fees
        assets.root[assets.unit(1)] -= datum.token_b_fees

pool_id: str property

A unique identifier for the pool.

pools: dict[str, VyFiPoolDefinition] classmethod property

Get the pools.

extract_pool_nft(values: dict[str, Any]) -> Optional[Assets] classmethod

Extract the dex nft from the UTXO.

Some DEXs put a DEX nft into the pool UTXO.

This function checks to see if the DEX nft is in the UTXO if the DEX policy is defined.

If the dex nft is in the values, this value is skipped because it is assumed that this utxo has already been parsed.

Parameters:

Name Type Description Default
values dict[str, Any]

The pool UTXO inputs.

required

Returns:

Name Type Description
Assets Optional[Assets]

None or the dex nft.

Source code in src/charli3_dendrite/dexs/amm/vyfi.py
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
@classmethod
def extract_pool_nft(cls, values: dict[str, Any]) -> Optional[Assets]:
    """Extract the dex nft from the UTXO.

    Some DEXs put a DEX nft into the pool UTXO.

    This function checks to see if the DEX nft is in the UTXO if the DEX policy is
    defined.

    If the dex nft is in the values, this value is skipped because it is assumed
    that this utxo has already been parsed.

    Args:
        values: The pool UTXO inputs.

    Returns:
        Assets: None or the dex nft.
    """
    assets = values["assets"]

    # If the dex nft is in the values, it's been parsed already
    if "pool_nft" in values:
        assert any([p in cls.pools for p in values["pool_nft"]])
        if isinstance(values["pool_nft"], dict):
            pool_nft = Assets(root=values["pool_nft"])
        else:
            pool_nft = values["pool_nft"]

    # Check for the dex nft
    else:
        nfts = [asset for asset, quantity in assets.items() if asset in cls.pools]
        if len(nfts) < 1:
            if len(assets) == 0:
                raise NoAssetsError(
                    f"{cls.__name__}: No assets supplied.",
                )
            else:
                raise NotAPoolError(
                    f"{cls.__name__}: Pool must have one DEX NFT token.",
                )
        pool_nft = Assets(**{nfts[0]: assets.root.pop(nfts[0])})
        values["pool_nft"] = pool_nft

    values["lp_fee"] = cls.pools[pool_nft.unit()].json_.feesSettings.liqFee
    values["bar_fee"] = cls.pools[pool_nft.unit()].json_.feesSettings.barFee

    return pool_nft

VyFiFees

Bases: BaseModel

VyFi fees.

Source code in src/charli3_dendrite/dexs/amm/vyfi.py
189
190
191
192
193
194
class VyFiFees(BaseModel):
    """VyFi fees."""

    barFee: int
    processFee: int
    liqFee: int

VyFiOrderDatum dataclass

Bases: OrderDatum

VyFi order datum.

Source code in src/charli3_dendrite/dexs/amm/vyfi.py
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
@dataclass
class VyFiOrderDatum(OrderDatum):
    """VyFi order datum."""

    address: bytes
    order: Union[AtoB, BtoA, Deposit, LPFlushA, Withdraw, ZapInA, ZapInB]

    @classmethod
    def create_datum(
        cls,
        address_source: Address,
        in_assets: Assets,
        out_assets: Assets,
        batcher_fee: Assets,
        deposit: Assets,
        address_target: Address | None = None,
        datum_target: PlutusData | None = None,
    ):
        """Create a new order datum."""
        address_hash = (
            address_source.payment_part.to_primitive()
            + address_source.staking_part.to_primitive()
        )

        merged = in_assets + out_assets
        if in_assets.unit() == merged.unit():
            order = AtoB(min_receive=out_assets.quantity())
        else:
            order = BtoA(min_receive=out_assets.quantity())

        return cls(address=address_hash, order=order)

    def address_source(self) -> Address:
        payment_part = VerificationKeyHash.from_primitive(self.address[:28])
        if len(self.address) == 28:
            staking_part = None
        else:
            staking_part = VerificationKeyHash.from_primitive(self.address[28:56])
        return Address(payment_part=payment_part, staking_part=staking_part)

    def requested_amount(self) -> Assets:
        if isinstance(self.order, BtoA):
            return Assets({"asset_a": self.order.min_receive})
        elif isinstance(self.order, AtoB):
            return Assets({"asset_b": self.order.min_receive})
        elif isinstance(self.order, (ZapInA, ZapInB, Deposit)):
            return Assets({"lp": self.order.min_lp_receive})
        elif isinstance(self.order, Withdraw):
            return Assets(
                {
                    "asset_a": self.order.min_lp_receive.min_amount_a,
                    "asset_b": self.order.min_lp_receive.min_amount_b,
                },
            )

    def order_type(self) -> OrderType | None:
        order_type = None
        if isinstance(self.order, (BtoA, AtoB, ZapInA, ZapInB)):
            order_type = OrderType.swap
        elif isinstance(self.order, Deposit):
            order_type = OrderType.deposit
        elif isinstance(self.order, Withdraw):
            order_type = OrderType.withdraw

        return order_type

create_datum(address_source: Address, in_assets: Assets, out_assets: Assets, batcher_fee: Assets, deposit: Assets, address_target: Address | None = None, datum_target: PlutusData | None = None) classmethod

Create a new order datum.

Source code in src/charli3_dendrite/dexs/amm/vyfi.py
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
@classmethod
def create_datum(
    cls,
    address_source: Address,
    in_assets: Assets,
    out_assets: Assets,
    batcher_fee: Assets,
    deposit: Assets,
    address_target: Address | None = None,
    datum_target: PlutusData | None = None,
):
    """Create a new order datum."""
    address_hash = (
        address_source.payment_part.to_primitive()
        + address_source.staking_part.to_primitive()
    )

    merged = in_assets + out_assets
    if in_assets.unit() == merged.unit():
        order = AtoB(min_receive=out_assets.quantity())
    else:
        order = BtoA(min_receive=out_assets.quantity())

    return cls(address=address_hash, order=order)

VyFiPoolDatum dataclass

Bases: PoolDatum

TODO: Figure out what each of these numbers mean.

Source code in src/charli3_dendrite/dexs/amm/vyfi.py
27
28
29
30
31
32
33
34
35
36
@dataclass
class VyFiPoolDatum(PoolDatum):
    """TODO: Figure out what each of these numbers mean."""

    token_a_fees: int
    token_b_fees: int
    lp_tokens: int

    def pool_pair(self) -> Assets | None:
        return None

VyFiPoolDefinition

Bases: BaseModel

VyFi pool definition.

Source code in src/charli3_dendrite/dexs/amm/vyfi.py
209
210
211
212
213
214
215
216
217
218
class VyFiPoolDefinition(BaseModel):
    """VyFi pool definition."""

    unitsPair: str
    poolValidatorUtxoAddress: str
    lpPolicyId_assetId: str = Field(alias="lpPolicyId-assetId")
    json_: VyFiPoolTokens = Field(alias="json")
    pair: str
    isLive: bool
    orderValidatorUtxoAddress: str

VyFiPoolTokens

Bases: BaseModel

VyFi pool tokens.

Source code in src/charli3_dendrite/dexs/amm/vyfi.py
197
198
199
200
201
202
203
204
205
206
class VyFiPoolTokens(BaseModel):
    """VyFi pool tokens."""

    aAsset: VyFiTokenDefinition
    bAsset: VyFiTokenDefinition
    mainNFT: VyFiTokenDefinition
    operatorToken: VyFiTokenDefinition
    lpTokenName: dict[str, str]
    feesSettings: VyFiFees
    stakeKey: Optional[str]

VyFiTokenDefinition

Bases: BaseModel

VyFi token definition.

Source code in src/charli3_dendrite/dexs/amm/vyfi.py
182
183
184
185
186
class VyFiTokenDefinition(BaseModel):
    """VyFi token definition."""

    tokenName: str
    currencySymbol: str

Withdraw dataclass

Bases: PlutusData

Withdraw assets from the pool.

Source code in src/charli3_dendrite/dexs/amm/vyfi.py
68
69
70
71
72
73
@dataclass
class Withdraw(PlutusData):
    """Withdraw assets from the pool."""

    CONSTR_ID = 1
    min_lp_receive: WithdrawPair

WithdrawPair dataclass

Bases: PlutusData

Withdraw pair of assets.

Source code in src/charli3_dendrite/dexs/amm/vyfi.py
59
60
61
62
63
64
65
@dataclass
class WithdrawPair(PlutusData):
    """Withdraw pair of assets."""

    CONSTR_ID = 0
    min_amount_a: int
    min_amount_b: int

ZapInA dataclass

Bases: PlutusData

Zap in A.

Source code in src/charli3_dendrite/dexs/amm/vyfi.py
 99
100
101
102
103
104
@dataclass
class ZapInA(PlutusData):
    """Zap in A."""

    CONSTR_ID = 5
    min_lp_receive: int

ZapInB dataclass

Bases: PlutusData

Zap in B.

Source code in src/charli3_dendrite/dexs/amm/vyfi.py
107
108
109
110
111
112
@dataclass
class ZapInB(PlutusData):
    """Zap in B."""

    CONSTR_ID = 6
    min_lp_receive: int