veilix-sdk 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -40,7 +40,7 @@ function formatBaseUnits(value, decimals) {
40
40
 
41
41
  // src/idl/veilix-devnet.json
42
42
  var veilix_devnet_default = {
43
- address: "HbatG5gpfs2g3N4gc2Qkfmmeu4zaBEVxzrDdYtWNLyyA",
43
+ address: "Vxi1QK84Akv4yGngjvkWNmEsK7XpsSrpDaPBoiyXGPG",
44
44
  metadata: {
45
45
  name: "veilix",
46
46
  version: "0.2.0",
@@ -641,6 +641,38 @@ var veilix_devnet_default = {
641
641
  {
642
642
  name: "system_program",
643
643
  address: "11111111111111111111111111111111"
644
+ },
645
+ {
646
+ name: "event_authority",
647
+ pda: {
648
+ seeds: [
649
+ {
650
+ kind: "const",
651
+ value: [
652
+ 95,
653
+ 95,
654
+ 101,
655
+ 118,
656
+ 101,
657
+ 110,
658
+ 116,
659
+ 95,
660
+ 97,
661
+ 117,
662
+ 116,
663
+ 104,
664
+ 111,
665
+ 114,
666
+ 105,
667
+ 116,
668
+ 121
669
+ ]
670
+ }
671
+ ]
672
+ }
673
+ },
674
+ {
675
+ name: "program"
644
676
  }
645
677
  ],
646
678
  args: [
@@ -703,6 +735,91 @@ var veilix_devnet_default = {
703
735
  ]
704
736
  }
705
737
  },
738
+ {
739
+ name: "program_data",
740
+ docs: [
741
+ "This program's ProgramData. Only its upgrade authority may initialize the network,",
742
+ "so nobody can claim the config authority between deploy and setup."
743
+ ],
744
+ pda: {
745
+ seeds: [
746
+ {
747
+ kind: "const",
748
+ value: [
749
+ 7,
750
+ 107,
751
+ 64,
752
+ 50,
753
+ 251,
754
+ 172,
755
+ 47,
756
+ 215,
757
+ 89,
758
+ 179,
759
+ 92,
760
+ 125,
761
+ 67,
762
+ 162,
763
+ 96,
764
+ 45,
765
+ 239,
766
+ 91,
767
+ 223,
768
+ 168,
769
+ 251,
770
+ 138,
771
+ 165,
772
+ 133,
773
+ 253,
774
+ 74,
775
+ 152,
776
+ 142,
777
+ 6,
778
+ 85,
779
+ 93,
780
+ 119
781
+ ]
782
+ }
783
+ ],
784
+ program: {
785
+ kind: "const",
786
+ value: [
787
+ 2,
788
+ 168,
789
+ 246,
790
+ 145,
791
+ 78,
792
+ 136,
793
+ 161,
794
+ 176,
795
+ 226,
796
+ 16,
797
+ 21,
798
+ 62,
799
+ 247,
800
+ 99,
801
+ 174,
802
+ 43,
803
+ 0,
804
+ 194,
805
+ 185,
806
+ 61,
807
+ 22,
808
+ 193,
809
+ 36,
810
+ 210,
811
+ 192,
812
+ 83,
813
+ 122,
814
+ 16,
815
+ 4,
816
+ 128,
817
+ 0,
818
+ 0
819
+ ]
820
+ }
821
+ }
822
+ },
706
823
  {
707
824
  name: "system_program",
708
825
  address: "11111111111111111111111111111111"
@@ -1031,6 +1148,31 @@ var veilix_devnet_default = {
1031
1148
  ]
1032
1149
  }
1033
1150
  },
1151
+ {
1152
+ name: "treasury",
1153
+ docs: [
1154
+ "Holds the SOL pool. Funded with its rent-exempt reserve here so that no withdrawal",
1155
+ "can fail for leaving it below that reserve."
1156
+ ],
1157
+ writable: true,
1158
+ pda: {
1159
+ seeds: [
1160
+ {
1161
+ kind: "const",
1162
+ value: [
1163
+ 116,
1164
+ 114,
1165
+ 101,
1166
+ 97,
1167
+ 115,
1168
+ 117,
1169
+ 114,
1170
+ 121
1171
+ ]
1172
+ }
1173
+ ]
1174
+ }
1175
+ },
1034
1176
  {
1035
1177
  name: "system_program",
1036
1178
  address: "11111111111111111111111111111111"
@@ -1439,25 +1581,355 @@ var veilix_devnet_default = {
1439
1581
  value: [
1440
1582
  114,
1441
1583
  101,
1442
- 108,
1443
- 97,
1444
- 121,
1584
+ 108,
1585
+ 97,
1586
+ 121,
1587
+ 101,
1588
+ 114
1589
+ ]
1590
+ },
1591
+ {
1592
+ kind: "account",
1593
+ path: "user"
1594
+ }
1595
+ ]
1596
+ }
1597
+ }
1598
+ ],
1599
+ args: [
1600
+ {
1601
+ name: "worker",
1602
+ type: "pubkey"
1603
+ }
1604
+ ]
1605
+ },
1606
+ {
1607
+ name: "swap",
1608
+ docs: [
1609
+ "Private swap. Remaining accounts: the protocol fee wallets for the input asset (SOL",
1610
+ "accounts or their token accounts, in config order), then the DEX instruction's accounts."
1611
+ ],
1612
+ discriminator: [
1613
+ 248,
1614
+ 198,
1615
+ 158,
1616
+ 145,
1617
+ 225,
1618
+ 117,
1619
+ 135,
1620
+ 200
1621
+ ],
1622
+ accounts: [
1623
+ {
1624
+ name: "relayer",
1625
+ writable: true,
1626
+ signer: true
1627
+ },
1628
+ {
1629
+ name: "relayer_account",
1630
+ writable: true,
1631
+ pda: {
1632
+ seeds: [
1633
+ {
1634
+ kind: "const",
1635
+ value: [
1636
+ 114,
1637
+ 101,
1638
+ 108,
1639
+ 97,
1640
+ 121,
1641
+ 101,
1642
+ 114
1643
+ ]
1644
+ },
1645
+ {
1646
+ kind: "account",
1647
+ path: "relayer_account.owner",
1648
+ account: "RelayerAccount"
1649
+ }
1650
+ ]
1651
+ }
1652
+ },
1653
+ {
1654
+ name: "network_state",
1655
+ pda: {
1656
+ seeds: [
1657
+ {
1658
+ kind: "const",
1659
+ value: [
1660
+ 99,
1661
+ 111,
1662
+ 110,
1663
+ 102,
1664
+ 105,
1665
+ 103
1666
+ ]
1667
+ }
1668
+ ]
1669
+ }
1670
+ },
1671
+ {
1672
+ name: "swap_config",
1673
+ pda: {
1674
+ seeds: [
1675
+ {
1676
+ kind: "const",
1677
+ value: [
1678
+ 115,
1679
+ 119,
1680
+ 97,
1681
+ 112,
1682
+ 95,
1683
+ 99,
1684
+ 111,
1685
+ 110,
1686
+ 102,
1687
+ 105,
1688
+ 103
1689
+ ]
1690
+ }
1691
+ ]
1692
+ }
1693
+ },
1694
+ {
1695
+ name: "tree_in",
1696
+ docs: [
1697
+ "Tree of the asset being spent. The handler checks it is the PDA for its mint."
1698
+ ],
1699
+ writable: true
1700
+ },
1701
+ {
1702
+ name: "tree_out",
1703
+ docs: [
1704
+ "Tree that receives the swapped note."
1705
+ ],
1706
+ writable: true
1707
+ },
1708
+ {
1709
+ name: "treasury",
1710
+ writable: true,
1711
+ pda: {
1712
+ seeds: [
1713
+ {
1714
+ kind: "const",
1715
+ value: [
1716
+ 116,
1717
+ 114,
1718
+ 101,
1719
+ 97,
1720
+ 115,
1721
+ 117,
1722
+ 114,
1723
+ 121
1724
+ ]
1725
+ }
1726
+ ]
1727
+ }
1728
+ },
1729
+ {
1730
+ name: "escrow",
1731
+ docs: [
1732
+ "Signs the DEX call. Holds nothing between transactions."
1733
+ ],
1734
+ writable: true,
1735
+ pda: {
1736
+ seeds: [
1737
+ {
1738
+ kind: "const",
1739
+ value: [
1740
+ 115,
1741
+ 119,
1742
+ 97,
1743
+ 112,
1744
+ 95,
1745
+ 101,
1746
+ 115,
1747
+ 99,
1748
+ 114,
1749
+ 111,
1750
+ 119
1751
+ ]
1752
+ }
1753
+ ]
1754
+ }
1755
+ },
1756
+ {
1757
+ name: "treasury_ata_in",
1758
+ docs: [
1759
+ "Treasury ATA for `mint_in`. `None` when spending SOL."
1760
+ ],
1761
+ writable: true,
1762
+ optional: true
1763
+ },
1764
+ {
1765
+ name: "treasury_ata_out",
1766
+ docs: [
1767
+ "Treasury ATA for `mint_out`. `None` when receiving SOL."
1768
+ ],
1769
+ writable: true,
1770
+ optional: true
1771
+ },
1772
+ {
1773
+ name: "escrow_ata_in",
1774
+ docs: [
1775
+ "Escrow ATA for `mint_in` (wrapped SOL when spending SOL). Must exist: prepend an",
1776
+ "idempotent ATA create. A wrapped-SOL escrow account is closed at the end of the swap."
1777
+ ],
1778
+ writable: true
1779
+ },
1780
+ {
1781
+ name: "escrow_ata_out",
1782
+ docs: [
1783
+ "Escrow ATA for `mint_out` (wrapped SOL when receiving SOL). Must exist, as above."
1784
+ ],
1785
+ writable: true
1786
+ },
1787
+ {
1788
+ name: "relayer_ata",
1789
+ docs: [
1790
+ "Relayer ATA for `mint_in`, paid the relayer fee. `None` when spending SOL."
1791
+ ],
1792
+ writable: true,
1793
+ optional: true
1794
+ },
1795
+ {
1796
+ name: "nullifier0",
1797
+ writable: true,
1798
+ pda: {
1799
+ seeds: [
1800
+ {
1801
+ kind: "const",
1802
+ value: [
1803
+ 110,
1804
+ 117,
1805
+ 108,
1806
+ 108,
1807
+ 105,
1808
+ 102,
1809
+ 105,
1810
+ 101,
1811
+ 114
1812
+ ]
1813
+ },
1814
+ {
1815
+ kind: "arg",
1816
+ path: "proof.input_nullifiers [0]"
1817
+ }
1818
+ ]
1819
+ }
1820
+ },
1821
+ {
1822
+ name: "nullifier1",
1823
+ writable: true,
1824
+ pda: {
1825
+ seeds: [
1826
+ {
1827
+ kind: "const",
1828
+ value: [
1829
+ 110,
1830
+ 117,
1831
+ 108,
1832
+ 108,
1833
+ 105,
1834
+ 102,
1835
+ 105,
1836
+ 101,
1837
+ 114
1838
+ ]
1839
+ },
1840
+ {
1841
+ kind: "arg",
1842
+ path: "proof.input_nullifiers [1]"
1843
+ }
1844
+ ]
1845
+ }
1846
+ },
1847
+ {
1848
+ name: "mint_in",
1849
+ docs: [
1850
+ "Mint of the spent asset (the native mint when spending SOL)."
1851
+ ]
1852
+ },
1853
+ {
1854
+ name: "mint_out",
1855
+ docs: [
1856
+ "Mint of the received asset (the native mint when receiving SOL)."
1857
+ ]
1858
+ },
1859
+ {
1860
+ name: "token_program_in"
1861
+ },
1862
+ {
1863
+ name: "token_program_out"
1864
+ },
1865
+ {
1866
+ name: "dex_program"
1867
+ },
1868
+ {
1869
+ name: "system_program",
1870
+ address: "11111111111111111111111111111111"
1871
+ },
1872
+ {
1873
+ name: "event_authority",
1874
+ pda: {
1875
+ seeds: [
1876
+ {
1877
+ kind: "const",
1878
+ value: [
1879
+ 95,
1880
+ 95,
1881
+ 101,
1882
+ 118,
1445
1883
  101,
1446
- 114
1884
+ 110,
1885
+ 116,
1886
+ 95,
1887
+ 97,
1888
+ 117,
1889
+ 116,
1890
+ 104,
1891
+ 111,
1892
+ 114,
1893
+ 105,
1894
+ 116,
1895
+ 121
1447
1896
  ]
1448
- },
1449
- {
1450
- kind: "account",
1451
- path: "user"
1452
1897
  }
1453
1898
  ]
1454
1899
  }
1900
+ },
1901
+ {
1902
+ name: "program"
1455
1903
  }
1456
1904
  ],
1457
1905
  args: [
1458
1906
  {
1459
- name: "worker",
1460
- type: "pubkey"
1907
+ name: "proof",
1908
+ type: {
1909
+ defined: {
1910
+ name: "TransactionProof"
1911
+ }
1912
+ }
1913
+ },
1914
+ {
1915
+ name: "params",
1916
+ type: {
1917
+ defined: {
1918
+ name: "SwapParams"
1919
+ }
1920
+ }
1921
+ },
1922
+ {
1923
+ name: "encrypted_output1",
1924
+ type: "bytes"
1925
+ },
1926
+ {
1927
+ name: "encrypted_output2",
1928
+ type: "bytes"
1929
+ },
1930
+ {
1931
+ name: "route_data",
1932
+ type: "bytes"
1461
1933
  }
1462
1934
  ]
1463
1935
  },
@@ -1695,6 +2167,38 @@ var veilix_devnet_default = {
1695
2167
  {
1696
2168
  name: "system_program",
1697
2169
  address: "11111111111111111111111111111111"
2170
+ },
2171
+ {
2172
+ name: "event_authority",
2173
+ pda: {
2174
+ seeds: [
2175
+ {
2176
+ kind: "const",
2177
+ value: [
2178
+ 95,
2179
+ 95,
2180
+ 101,
2181
+ 118,
2182
+ 101,
2183
+ 110,
2184
+ 116,
2185
+ 95,
2186
+ 97,
2187
+ 117,
2188
+ 116,
2189
+ 104,
2190
+ 111,
2191
+ 114,
2192
+ 105,
2193
+ 116,
2194
+ 121
2195
+ ]
2196
+ }
2197
+ ]
2198
+ }
2199
+ },
2200
+ {
2201
+ name: "program"
1698
2202
  }
1699
2203
  ],
1700
2204
  args: [
@@ -2061,6 +2565,38 @@ var veilix_devnet_default = {
2061
2565
  {
2062
2566
  name: "system_program",
2063
2567
  address: "11111111111111111111111111111111"
2568
+ },
2569
+ {
2570
+ name: "event_authority",
2571
+ pda: {
2572
+ seeds: [
2573
+ {
2574
+ kind: "const",
2575
+ value: [
2576
+ 95,
2577
+ 95,
2578
+ 101,
2579
+ 118,
2580
+ 101,
2581
+ 110,
2582
+ 116,
2583
+ 95,
2584
+ 97,
2585
+ 117,
2586
+ 116,
2587
+ 104,
2588
+ 111,
2589
+ 114,
2590
+ 105,
2591
+ 116,
2592
+ 121
2593
+ ]
2594
+ }
2595
+ ]
2596
+ }
2597
+ },
2598
+ {
2599
+ name: "program"
2064
2600
  }
2065
2601
  ],
2066
2602
  args: [
@@ -2509,6 +3045,83 @@ var veilix_devnet_default = {
2509
3045
  }
2510
3046
  ]
2511
3047
  },
3048
+ {
3049
+ name: "update_swap_config",
3050
+ docs: [
3051
+ "Replaces the list of DEX programs the swap escrow may call. Config authority only."
3052
+ ],
3053
+ discriminator: [
3054
+ 123,
3055
+ 172,
3056
+ 158,
3057
+ 60,
3058
+ 104,
3059
+ 133,
3060
+ 39,
3061
+ 13
3062
+ ],
3063
+ accounts: [
3064
+ {
3065
+ name: "authority",
3066
+ writable: true,
3067
+ signer: true
3068
+ },
3069
+ {
3070
+ name: "network_state",
3071
+ pda: {
3072
+ seeds: [
3073
+ {
3074
+ kind: "const",
3075
+ value: [
3076
+ 99,
3077
+ 111,
3078
+ 110,
3079
+ 102,
3080
+ 105,
3081
+ 103
3082
+ ]
3083
+ }
3084
+ ]
3085
+ }
3086
+ },
3087
+ {
3088
+ name: "swap_config",
3089
+ writable: true,
3090
+ pda: {
3091
+ seeds: [
3092
+ {
3093
+ kind: "const",
3094
+ value: [
3095
+ 115,
3096
+ 119,
3097
+ 97,
3098
+ 112,
3099
+ 95,
3100
+ 99,
3101
+ 111,
3102
+ 110,
3103
+ 102,
3104
+ 105,
3105
+ 103
3106
+ ]
3107
+ }
3108
+ ]
3109
+ }
3110
+ },
3111
+ {
3112
+ name: "system_program",
3113
+ address: "11111111111111111111111111111111"
3114
+ }
3115
+ ],
3116
+ args: [
3117
+ {
3118
+ name: "allowed_programs",
3119
+ type: {
3120
+ vec: "pubkey"
3121
+ }
3122
+ }
3123
+ ]
3124
+ },
2512
3125
  {
2513
3126
  name: "withdraw",
2514
3127
  discriminator: [
@@ -2667,6 +3280,38 @@ var veilix_devnet_default = {
2667
3280
  {
2668
3281
  name: "system_program",
2669
3282
  address: "11111111111111111111111111111111"
3283
+ },
3284
+ {
3285
+ name: "event_authority",
3286
+ pda: {
3287
+ seeds: [
3288
+ {
3289
+ kind: "const",
3290
+ value: [
3291
+ 95,
3292
+ 95,
3293
+ 101,
3294
+ 118,
3295
+ 101,
3296
+ 110,
3297
+ 116,
3298
+ 95,
3299
+ 97,
3300
+ 117,
3301
+ 116,
3302
+ 104,
3303
+ 111,
3304
+ 114,
3305
+ 105,
3306
+ 116,
3307
+ 121
3308
+ ]
3309
+ }
3310
+ ]
3311
+ }
3312
+ },
3313
+ {
3314
+ name: "program"
2670
3315
  }
2671
3316
  ],
2672
3317
  args: [
@@ -2776,6 +3421,19 @@ var veilix_devnet_default = {
2776
3421
  20
2777
3422
  ]
2778
3423
  },
3424
+ {
3425
+ name: "SwapConfig",
3426
+ discriminator: [
3427
+ 212,
3428
+ 45,
3429
+ 70,
3430
+ 222,
3431
+ 245,
3432
+ 122,
3433
+ 125,
3434
+ 166
3435
+ ]
3436
+ },
2779
3437
  {
2780
3438
  name: "TreeAccount",
2781
3439
  discriminator: [
@@ -2817,6 +3475,19 @@ var veilix_devnet_default = {
2817
3475
  159
2818
3476
  ]
2819
3477
  },
3478
+ {
3479
+ name: "PrivateSwapEvent",
3480
+ discriminator: [
3481
+ 150,
3482
+ 165,
3483
+ 138,
3484
+ 189,
3485
+ 123,
3486
+ 86,
3487
+ 117,
3488
+ 39
3489
+ ]
3490
+ },
2820
3491
  {
2821
3492
  name: "RelayerCancelled",
2822
3493
  discriminator: [
@@ -3061,24 +3732,74 @@ var veilix_devnet_default = {
3061
3732
  msg: "Too many workers"
3062
3733
  },
3063
3734
  {
3064
- code: 6030,
3065
- name: "AlreadyRegistered",
3066
- msg: "Already registered"
3735
+ code: 6030,
3736
+ name: "AlreadyRegistered",
3737
+ msg: "Already registered"
3738
+ },
3739
+ {
3740
+ code: 6031,
3741
+ name: "NotRegistered",
3742
+ msg: "Not registered"
3743
+ },
3744
+ {
3745
+ code: 6032,
3746
+ name: "TooManyFeeAssets",
3747
+ msg: "Relayer has earned fees in too many assets"
3748
+ },
3749
+ {
3750
+ code: 6033,
3751
+ name: "FeeRepaymentAccounts",
3752
+ msg: "Fee repayment accounts do not match earned fees"
3753
+ },
3754
+ {
3755
+ code: 6034,
3756
+ name: "DexProgramNotAllowed",
3757
+ msg: "DEX program is not on the swap allowlist"
3758
+ },
3759
+ {
3760
+ code: 6035,
3761
+ name: "TooManyDexPrograms",
3762
+ msg: "Too many allowlisted DEX programs"
3763
+ },
3764
+ {
3765
+ code: 6036,
3766
+ name: "SlippageExceeded",
3767
+ msg: "Swap output is below the minimum amount"
3768
+ },
3769
+ {
3770
+ code: 6037,
3771
+ name: "SwapInputMismatch",
3772
+ msg: "DEX did not use exactly the escrowed swap input"
3773
+ },
3774
+ {
3775
+ code: 6038,
3776
+ name: "InvalidSwapAccounts",
3777
+ msg: "Swap accounts do not match the trees"
3778
+ },
3779
+ {
3780
+ code: 6039,
3781
+ name: "EscrowTampered",
3782
+ msg: "Swap escrow was modified by the DEX"
3783
+ },
3784
+ {
3785
+ code: 6040,
3786
+ name: "InvalidNoteKey",
3787
+ msg: "Note public key or blinding is not a valid field element"
3067
3788
  },
3068
3789
  {
3069
- code: 6031,
3070
- name: "NotRegistered",
3071
- msg: "Not registered"
3790
+ code: 6041,
3791
+ name: "NotUpgradeAuthority",
3792
+ msg: "Only the program upgrade authority can initialize the network"
3072
3793
  },
3073
3794
  {
3074
- code: 6032,
3075
- name: "TooManyFeeAssets",
3076
- msg: "Relayer has earned fees in too many assets"
3795
+ code: 6042,
3796
+ name: "InvalidFeeSplit",
3797
+ msg: "Fee wallets must be distinct, non-default and split at most the allowed total"
3077
3798
  },
3078
3799
  {
3079
- code: 6033,
3080
- name: "FeeRepaymentAccounts",
3081
- msg: "Fee repayment accounts do not match earned fees"
3800
+ code: 6043,
3801
+ name: "UnsupportedMintExtension",
3802
+ msg: "Token mint has an extension the pool does not support"
3082
3803
  }
3083
3804
  ],
3084
3805
  types: [
@@ -3259,6 +3980,68 @@ var veilix_devnet_default = {
3259
3980
  kind: "struct"
3260
3981
  }
3261
3982
  },
3983
+ {
3984
+ name: "PrivateSwapEvent",
3985
+ docs: [
3986
+ "Emitted once per swap. The asset-B note is `commitment` at `index` in the `mint_out` tree."
3987
+ ],
3988
+ type: {
3989
+ kind: "struct",
3990
+ fields: [
3991
+ {
3992
+ name: "mint_in",
3993
+ type: "pubkey"
3994
+ },
3995
+ {
3996
+ name: "mint_out",
3997
+ type: "pubkey"
3998
+ },
3999
+ {
4000
+ name: "amount_in",
4001
+ type: "u64"
4002
+ },
4003
+ {
4004
+ name: "fee",
4005
+ type: "u64"
4006
+ },
4007
+ {
4008
+ name: "amount_out",
4009
+ type: "u64"
4010
+ },
4011
+ {
4012
+ name: "input_nullifiers",
4013
+ type: {
4014
+ array: [
4015
+ {
4016
+ array: [
4017
+ "u8",
4018
+ 32
4019
+ ]
4020
+ },
4021
+ 2
4022
+ ]
4023
+ }
4024
+ },
4025
+ {
4026
+ name: "relayer",
4027
+ type: "pubkey"
4028
+ },
4029
+ {
4030
+ name: "commitment",
4031
+ type: {
4032
+ array: [
4033
+ "u8",
4034
+ 32
4035
+ ]
4036
+ }
4037
+ },
4038
+ {
4039
+ name: "index",
4040
+ type: "u64"
4041
+ }
4042
+ ]
4043
+ }
4044
+ },
3262
4045
  {
3263
4046
  name: "RelayerAccount",
3264
4047
  docs: [
@@ -3453,6 +4236,86 @@ var veilix_devnet_default = {
3453
4236
  ]
3454
4237
  }
3455
4238
  },
4239
+ {
4240
+ name: "SwapConfig",
4241
+ docs: [
4242
+ 'Programs the swap escrow is allowed to call. PDA seeds: `["swap_config"]`.'
4243
+ ],
4244
+ type: {
4245
+ kind: "struct",
4246
+ fields: [
4247
+ {
4248
+ name: "allowed_programs",
4249
+ type: {
4250
+ vec: "pubkey"
4251
+ }
4252
+ }
4253
+ ]
4254
+ }
4255
+ },
4256
+ {
4257
+ name: "SwapParams",
4258
+ docs: [
4259
+ "Swap parameters. All of them are bound into the proof's `extDataHash`."
4260
+ ],
4261
+ type: {
4262
+ kind: "struct",
4263
+ fields: [
4264
+ {
4265
+ name: "amount_in",
4266
+ docs: [
4267
+ "Asset-A amount spent from the pool, fee included."
4268
+ ],
4269
+ type: "u64"
4270
+ },
4271
+ {
4272
+ name: "fee",
4273
+ docs: [
4274
+ "Asset-A fee: protocol wallets get their split of `amount_in`, the relayer the rest."
4275
+ ],
4276
+ type: "u64"
4277
+ },
4278
+ {
4279
+ name: "min_amount_out",
4280
+ docs: [
4281
+ "Minimum asset-B amount that must reach the treasury."
4282
+ ],
4283
+ type: "u64"
4284
+ },
4285
+ {
4286
+ name: "out_pubkey",
4287
+ docs: [
4288
+ "One-time shielded public key of the asset-B note (32-byte big-endian field element)."
4289
+ ],
4290
+ type: {
4291
+ array: [
4292
+ "u8",
4293
+ 32
4294
+ ]
4295
+ }
4296
+ },
4297
+ {
4298
+ name: "out_blinding",
4299
+ docs: [
4300
+ "Blinding of the asset-B note (32-byte big-endian field element)."
4301
+ ],
4302
+ type: {
4303
+ array: [
4304
+ "u8",
4305
+ 32
4306
+ ]
4307
+ }
4308
+ },
4309
+ {
4310
+ name: "encrypted_note",
4311
+ docs: [
4312
+ "Optional encrypted recovery data for the asset-B note."
4313
+ ],
4314
+ type: "bytes"
4315
+ }
4316
+ ]
4317
+ }
4318
+ },
3456
4319
  {
3457
4320
  name: "TransactionProof",
3458
4321
  docs: [
@@ -7351,7 +8214,7 @@ var MAINNET_TOKEN_MINTS = {
7351
8214
  USDC: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
7352
8215
  };
7353
8216
  var DEVNET_TOKEN_MINTS = {
7354
- Veilix: "GAFN64LvtCBoc5BHncVn3JEJGpq42rUzQjPmvMK2UhZH",
8217
+ Veilix: "Gmo636w21RBZX9ySVtPYcuYP6f1E5bdW5eBYhvK1bc8J",
7355
8218
  Bitcoin: "",
7356
8219
  Ethereum: "",
7357
8220
  USDC: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU"
@@ -7401,7 +8264,7 @@ function getDepositQueueForNetwork(network) {
7401
8264
  // package.json
7402
8265
  var package_default = {
7403
8266
  name: "veilix-sdk",
7404
- version: "0.2.3"};
8267
+ version: "0.3.0"};
7405
8268
 
7406
8269
  // src/circuits/constants.ts
7407
8270
  var PACKAGE_NAME = package_default.name;
@@ -7644,10 +8507,10 @@ var DEPOSIT_COMPUTE_UNIT_LIMIT = 35e4;
7644
8507
  function bytesToHex(bytes) {
7645
8508
  return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
7646
8509
  }
7647
- function hexToBytes(hex) {
7648
- const clean = hex.startsWith("0x") || hex.startsWith("0X") ? hex.slice(2) : hex;
8510
+ function hexToBytes(hex2) {
8511
+ const clean = hex2.startsWith("0x") || hex2.startsWith("0X") ? hex2.slice(2) : hex2;
7649
8512
  if (clean.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(clean)) {
7650
- throw new Error(`veilix-sdk: invalid hex string "${hex}"`);
8513
+ throw new Error(`veilix-sdk: invalid hex string "${hex2}"`);
7651
8514
  }
7652
8515
  const out = new Uint8Array(clean.length / 2);
7653
8516
  for (let i = 0; i < out.length; i++) {
@@ -7656,15 +8519,15 @@ function hexToBytes(hex) {
7656
8519
  return out;
7657
8520
  }
7658
8521
  function bigintToBytes32(value) {
7659
- const hex = BigInt(value).toString(16).padStart(64, "0");
7660
- if (hex.length > 64) {
8522
+ const hex2 = BigInt(value).toString(16).padStart(64, "0");
8523
+ if (hex2.length > 64) {
7661
8524
  throw new Error("veilix-sdk: value does not fit in 32 bytes");
7662
8525
  }
7663
- return hexToBytes(hex);
8526
+ return hexToBytes(hex2);
7664
8527
  }
7665
8528
  function bytesToBigint(bytes) {
7666
- const hex = bytesToHex(bytes);
7667
- return hex ? BigInt(`0x${hex}`) : 0n;
8529
+ const hex2 = bytesToHex(bytes);
8530
+ return hex2 ? BigInt(`0x${hex2}`) : 0n;
7668
8531
  }
7669
8532
  function toHex32(value) {
7670
8533
  return `0x${BigInt(value).toString(16).padStart(64, "0")}`;
@@ -7782,6 +8645,7 @@ var Utxo = class _Utxo {
7782
8645
  // src/core/note.ts
7783
8646
  var NOTE_PREFIX = "vx2";
7784
8647
  var ENCRYPTED_OUTPUT_VERSION = 1;
8648
+ var ENCRYPTED_SWAP_OUTPUT_VERSION = 2;
7785
8649
  var ENCRYPTED_OUTPUT_PLAINTEXT_BYTES = 1 + 8 + 32 + 32;
7786
8650
  var SECRETBOX_NONCE_BYTES = nacl.secretbox.nonceLength;
7787
8651
  function encodeNote(utxo) {
@@ -7814,14 +8678,14 @@ function decodeNote(note) {
7814
8678
  throw new Error("veilix-sdk: invalid note format");
7815
8679
  }
7816
8680
  const [, amountHex, privKeyHex, blindingHex, mint] = parts;
7817
- const hex = /^[0-9a-f]+$/i;
7818
- if (!hex.test(amountHex) || !hex.test(privKeyHex) || !hex.test(blindingHex)) {
8681
+ const hex2 = /^[0-9a-f]+$/i;
8682
+ if (!hex2.test(amountHex) || !hex2.test(privKeyHex) || !hex2.test(blindingHex)) {
7819
8683
  throw new Error("veilix-sdk: invalid note format");
7820
8684
  }
7821
- let mintKey = null;
8685
+ let mintKey2 = null;
7822
8686
  if (mint) {
7823
8687
  try {
7824
- mintKey = new PublicKey(mint);
8688
+ mintKey2 = new PublicKey(mint);
7825
8689
  } catch {
7826
8690
  throw new Error("veilix-sdk: invalid note mint");
7827
8691
  }
@@ -7830,7 +8694,7 @@ function decodeNote(note) {
7830
8694
  amount: BigInt(`0x${amountHex}`),
7831
8695
  keypair: VeilixKeypair.fromPrivateKey(BigInt(`0x${privKeyHex}`)),
7832
8696
  blinding: BigInt(`0x${blindingHex}`),
7833
- mint: mintKey
8697
+ mint: mintKey2
7834
8698
  });
7835
8699
  }
7836
8700
  function describeUtxo(utxo) {
@@ -7848,7 +8712,7 @@ function describeUtxo(utxo) {
7848
8712
  function parseSecretNote(note) {
7849
8713
  return describeUtxo(decodeNote(note));
7850
8714
  }
7851
- function encryptNoteOutput(key, utxo) {
8715
+ function encryptNoteOutput(key2, utxo) {
7852
8716
  const amount = new Uint8Array(8);
7853
8717
  new DataView(amount.buffer).setBigUint64(0, utxo.amount, true);
7854
8718
  const plaintext = concatBytes([
@@ -7858,21 +8722,38 @@ function encryptNoteOutput(key, utxo) {
7858
8722
  bigintToBytes32(utxo.blinding)
7859
8723
  ]);
7860
8724
  const nonce = nacl.randomBytes(SECRETBOX_NONCE_BYTES);
7861
- return concatBytes([nonce, nacl.secretbox(plaintext, nonce, key)]);
8725
+ return concatBytes([nonce, nacl.secretbox(plaintext, nonce, key2)]);
8726
+ }
8727
+ function encryptSwapNoteOutput(key2, keypair, blinding) {
8728
+ const plaintext = concatBytes([
8729
+ Uint8Array.of(ENCRYPTED_SWAP_OUTPUT_VERSION),
8730
+ new Uint8Array(8),
8731
+ bigintToBytes32(keypair.privKey),
8732
+ bigintToBytes32(blinding)
8733
+ ]);
8734
+ const nonce = nacl.randomBytes(SECRETBOX_NONCE_BYTES);
8735
+ return concatBytes([nonce, nacl.secretbox(plaintext, nonce, key2)]);
7862
8736
  }
7863
- function decryptNoteOutput(key, encryptedOutput, mint, index) {
8737
+ function decryptNoteOutput(key2, encryptedOutput, mint, index, onchainAmount = null) {
7864
8738
  if (encryptedOutput.length !== SECRETBOX_NONCE_BYTES + nacl.secretbox.overheadLength + ENCRYPTED_OUTPUT_PLAINTEXT_BYTES) {
7865
8739
  return null;
7866
8740
  }
7867
8741
  const opened = nacl.secretbox.open(
7868
8742
  encryptedOutput.subarray(SECRETBOX_NONCE_BYTES),
7869
8743
  encryptedOutput.subarray(0, SECRETBOX_NONCE_BYTES),
7870
- key
8744
+ key2
7871
8745
  );
7872
- if (!opened || opened[0] !== ENCRYPTED_OUTPUT_VERSION) {
8746
+ if (!opened) {
8747
+ return null;
8748
+ }
8749
+ let amount;
8750
+ if (opened[0] === ENCRYPTED_OUTPUT_VERSION) {
8751
+ amount = new DataView(opened.buffer, opened.byteOffset + 1, 8).getBigUint64(0, true);
8752
+ } else if (opened[0] === ENCRYPTED_SWAP_OUTPUT_VERSION && onchainAmount !== null) {
8753
+ amount = onchainAmount;
8754
+ } else {
7873
8755
  return null;
7874
8756
  }
7875
- const amount = new DataView(opened.buffer, opened.byteOffset + 1, 8).getBigUint64(0, true);
7876
8757
  return new Utxo({
7877
8758
  amount,
7878
8759
  keypair: VeilixKeypair.fromPrivateKey(bytesToBigint(opened.subarray(9, 41))),
@@ -16353,6 +17234,7 @@ async function proveTransaction({
16353
17234
  inputs = [],
16354
17235
  outputs = [],
16355
17236
  ext,
17237
+ extDataHashOverride,
16356
17238
  circuit
16357
17239
  }) {
16358
17240
  for (const utxo of [...inputs, ...outputs]) {
@@ -16402,7 +17284,7 @@ async function proveTransaction({
16402
17284
  const input = {
16403
17285
  root: proofRoot.toString(),
16404
17286
  publicAmount: publicAmount.toString(),
16405
- extDataHash: (await extDataHash(ext)).toString(),
17287
+ extDataHash: (extDataHashOverride ?? await extDataHash(ext)).toString(),
16406
17288
  mint: mintToField(ext.mint).toString(),
16407
17289
  inputNullifier: inputNullifiers.map(String),
16408
17290
  outputCommitment: outputCommitments.map(String),
@@ -16543,8 +17425,8 @@ function generateDepositParams(amount, mint = null) {
16543
17425
  if (value <= 0n) {
16544
17426
  throw new Error("veilix-sdk: deposit amount must be positive");
16545
17427
  }
16546
- const mintKey = mint && mint !== WRAPPED_SOL_MINT ? new PublicKey(mint) : null;
16547
- const note = encodeNote(new Utxo({ amount: value, mint: mintKey }));
17428
+ const mintKey2 = mint && mint !== WRAPPED_SOL_MINT ? new PublicKey(mint) : null;
17429
+ const note = encodeNote(new Utxo({ amount: value, mint: mintKey2 }));
16548
17430
  return { note, params: parseSecretNote(note) };
16549
17431
  }
16550
17432
  function to32ByteBuffer(value) {
@@ -16578,8 +17460,8 @@ function toPublicKey(value) {
16578
17460
  }
16579
17461
  function normalizeTreeMint(mint) {
16580
17462
  if (!mint) return null;
16581
- const key = toPublicKey(mint);
16582
- return key.equals(NATIVE_MINT) || key.equals(PublicKey.default) ? null : key;
17463
+ const key2 = toPublicKey(mint);
17464
+ return key2.equals(NATIVE_MINT) || key2.equals(PublicKey.default) ? null : key2;
16583
17465
  }
16584
17466
  function getTreePDA(mint) {
16585
17467
  const treeMint = normalizeTreeMint(mint);
@@ -16830,8 +17712,8 @@ async function resolveEncryptKey() {
16830
17712
  }
16831
17713
  async function buildBackupNotesInstruction(sender, notes) {
16832
17714
  const { program } = getConfig();
16833
- const key = await resolveEncryptKey();
16834
- return program.methods.backupNotes(notes.map((note) => encryptData(key, note))).accountsPartial({ user: sender }).instruction();
17715
+ const key2 = await resolveEncryptKey();
17716
+ return program.methods.backupNotes(notes.map((note) => encryptData(key2, note))).accountsPartial({ user: sender }).instruction();
16835
17717
  }
16836
17718
  async function isExtendBackupPdaNeeded(walletPubkey, newNotesLength) {
16837
17719
  const account = await fetchNotesAccount(walletPubkey);
@@ -16936,16 +17818,16 @@ async function getEncryptionKey(wallet) {
16936
17818
  }
16937
17819
  return nacl.hash(signature).slice(0, 32);
16938
17820
  }
16939
- function encryptData(key, plaintext) {
17821
+ function encryptData(key2, plaintext) {
16940
17822
  const nonce = nacl.randomBytes(24);
16941
- const box = nacl.secretbox(new TextEncoder().encode(plaintext), nonce, key);
17823
+ const box = nacl.secretbox(new TextEncoder().encode(plaintext), nonce, key2);
16942
17824
  const combined = new Uint8Array(nonce.length + box.length);
16943
17825
  combined.set(nonce);
16944
17826
  combined.set(box, nonce.length);
16945
17827
  return Buffer.from(combined);
16946
17828
  }
16947
- function decryptData(key, combined) {
16948
- const decrypted = nacl.secretbox.open(combined.slice(24), combined.slice(0, 24), key);
17829
+ function decryptData(key2, combined) {
17830
+ const decrypted = nacl.secretbox.open(combined.slice(24), combined.slice(0, 24), key2);
16949
17831
  if (!decrypted) throw new Error("Decryption failed");
16950
17832
  return new TextDecoder().decode(decrypted);
16951
17833
  }
@@ -16983,8 +17865,8 @@ var COMMITMENTS_PAGE_LIMIT = 8e3;
16983
17865
  var VALIDATE_NULLIFIERS_BATCH = 64;
16984
17866
  async function indexerGet(path, params) {
16985
17867
  const query = new URLSearchParams();
16986
- for (const [key, value] of Object.entries(params)) {
16987
- if (value !== void 0 && value !== "") query.set(key, value);
17868
+ for (const [key2, value] of Object.entries(params)) {
17869
+ if (value !== void 0 && value !== "") query.set(key2, value);
16988
17870
  }
16989
17871
  const qs = query.toString();
16990
17872
  return httpFetch(`${getIndexerUrl()}${path}${qs ? `?${qs}` : ""}`, {
@@ -17199,7 +18081,7 @@ async function scanOwnedNotes({
17199
18081
  mints,
17200
18082
  includeSpent = false
17201
18083
  } = {}) {
17202
- const key = requireEncryptKey();
18084
+ const key2 = requireEncryptKey();
17203
18085
  const explicit = mints !== void 0;
17204
18086
  const tokenMints = getTokenMintsForNetwork(getConfig().network);
17205
18087
  const targets = mints ?? [null, tokenMints.Veilix, tokenMints.Bitcoin, tokenMints.Ethereum, tokenMints.USDC].filter(
@@ -17217,7 +18099,13 @@ async function scanOwnedNotes({
17217
18099
  }
17218
18100
  for (const leaf of leaves) {
17219
18101
  if (!leaf.encryptedOutput || leaf.encryptedOutput.length <= 2) continue;
17220
- const utxo = decryptNoteOutput(key, hexToBytes(leaf.encryptedOutput), treeMint, leaf.index);
18102
+ const utxo = decryptNoteOutput(
18103
+ key2,
18104
+ hexToBytes(leaf.encryptedOutput),
18105
+ treeMint,
18106
+ leaf.index,
18107
+ leaf.amountRaw ? BigInt(leaf.amountRaw) : null
18108
+ );
17221
18109
  if (!utxo || utxo.amount === 0n) continue;
17222
18110
  if (toHex32(utxo.commitment()) !== toHex32(BigInt(leaf.commitment))) continue;
17223
18111
  found.push({ utxo, note: encodeNote(utxo), signature: null });
@@ -17497,6 +18385,364 @@ async function getQuote(params) {
17497
18385
  }
17498
18386
  return data;
17499
18387
  }
18388
+ var SWAP_DOMAIN = new TextEncoder().encode("veilix:swap:v1");
18389
+ async function swapExtDataHash(ext) {
18390
+ const hash = await sha256(
18391
+ concatBytes([
18392
+ SWAP_DOMAIN,
18393
+ (ext.mintIn ?? PublicKey.default).toBytes(),
18394
+ (ext.mintOut ?? PublicKey.default).toBytes(),
18395
+ ext.relayer.toBytes(),
18396
+ u64le(ext.amountIn),
18397
+ u64le(ext.fee),
18398
+ u64le(ext.minAmountOut),
18399
+ bigintToBytes32(ext.outPubkey),
18400
+ bigintToBytes32(ext.outBlinding),
18401
+ u32le(ext.encryptedOutput1.length),
18402
+ ext.encryptedOutput1,
18403
+ u32le(ext.encryptedOutput2.length),
18404
+ ext.encryptedOutput2,
18405
+ u32le(ext.encryptedNote.length),
18406
+ ext.encryptedNote
18407
+ ])
18408
+ );
18409
+ hash[0] = 0;
18410
+ return bytesToBigint(hash);
18411
+ }
18412
+ var CPMM_PROGRAM_IDS = {
18413
+ devnet: "DRaycpLY18LhpbydsBWbVJtxpNv9oXPgjRSfpF2bWpYb",
18414
+ mainnet: "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C"
18415
+ };
18416
+ var FEE_RATE_DENOMINATOR = 1000000n;
18417
+ var SWAP_DISABLED_BIT = 2;
18418
+ var key = (data, offset) => new PublicKey(data.subarray(offset, offset + 32));
18419
+ var u64 = (data, offset) => new DataView(data.buffer, data.byteOffset + offset, 8).getBigUint64(0, true);
18420
+ var ceilDiv = (a, b) => (a + b - 1n) / b;
18421
+ var feeOf = (amount, rate) => ceilDiv(amount * rate, FEE_RATE_DENOMINATOR);
18422
+ async function quoteCpmm(connection, network, poolAddress, treeMintIn, treeMintOut, amountIn) {
18423
+ const programId = new PublicKey(CPMM_PROGRAM_IDS[network]);
18424
+ const poolInfo = await connection.getAccountInfo(poolAddress, "confirmed");
18425
+ if (!poolInfo || !poolInfo.owner.equals(programId) || poolInfo.data.length < 381) {
18426
+ throw new Error("veilix-sdk: swap pool is not a Raydium CPMM pool");
18427
+ }
18428
+ const data = poolInfo.data;
18429
+ const pool = {
18430
+ ammConfig: key(data, 8),
18431
+ vault0: key(data, 72),
18432
+ vault1: key(data, 104),
18433
+ mint0: key(data, 168),
18434
+ mint1: key(data, 200),
18435
+ status: data[329],
18436
+ protocolFees: [u64(data, 341), u64(data, 349)],
18437
+ fundFees: [u64(data, 357), u64(data, 365)],
18438
+ creatorFeeOn: data.length >= 413 ? data[389] : 0,
18439
+ enableCreatorFee: data.length >= 413 ? data[390] === 1 : false,
18440
+ creatorFees: data.length >= 413 ? [u64(data, 397), u64(data, 405)] : [0n, 0n]
18441
+ };
18442
+ if (pool.status >> SWAP_DISABLED_BIT & 1) {
18443
+ throw new Error("veilix-sdk: swaps are disabled on this pool");
18444
+ }
18445
+ const mintIn = treeMintIn ?? NATIVE_MINT;
18446
+ const mintOut = treeMintOut ?? NATIVE_MINT;
18447
+ let zeroForOne;
18448
+ if (pool.mint0.equals(mintIn) && pool.mint1.equals(mintOut)) zeroForOne = true;
18449
+ else if (pool.mint1.equals(mintIn) && pool.mint0.equals(mintOut)) zeroForOne = false;
18450
+ else throw new Error("veilix-sdk: swap pool does not trade this pair");
18451
+ const [i, o] = zeroForOne ? [0, 1] : [1, 0];
18452
+ const [configInfo, vaultIn, vaultOut] = await connection.getMultipleAccountsInfo(
18453
+ [pool.ammConfig, zeroForOne ? pool.vault0 : pool.vault1, zeroForOne ? pool.vault1 : pool.vault0],
18454
+ "confirmed"
18455
+ );
18456
+ if (!configInfo || !vaultIn || !vaultOut) {
18457
+ throw new Error("veilix-sdk: swap pool accounts are missing");
18458
+ }
18459
+ const tradeFeeRate = u64(configInfo.data, 12);
18460
+ const creatorFeeRate = pool.enableCreatorFee && configInfo.data.length >= 116 ? u64(configInfo.data, 108) : 0n;
18461
+ const reserveIn = u64(vaultIn.data, 64) - pool.protocolFees[i] - pool.fundFees[i] - pool.creatorFees[i];
18462
+ const reserveOut = u64(vaultOut.data, 64) - pool.protocolFees[o] - pool.fundFees[o] - pool.creatorFees[o];
18463
+ if (reserveIn <= 0n || reserveOut <= 0n) {
18464
+ throw new Error("veilix-sdk: swap pool has no liquidity");
18465
+ }
18466
+ const creatorOnInput = pool.creatorFeeOn === 0 || pool.creatorFeeOn === 1 && zeroForOne || pool.creatorFeeOn === 2 && !zeroForOne;
18467
+ let inLessFees = amountIn - feeOf(amountIn, tradeFeeRate);
18468
+ if (creatorOnInput) inLessFees -= feeOf(amountIn, creatorFeeRate);
18469
+ let amountOut = inLessFees * reserveOut / (reserveIn + inLessFees);
18470
+ if (!creatorOnInput) amountOut -= feeOf(amountOut, creatorFeeRate);
18471
+ if (amountOut <= 0n) {
18472
+ throw new Error("veilix-sdk: swap amount is too small for this pool");
18473
+ }
18474
+ const spotOut = Number(inLessFees) * (Number(reserveOut) / Number(reserveIn));
18475
+ const priceImpact = spotOut > 0 ? Math.max(0, 1 - Number(amountOut) / spotOut) : 1;
18476
+ return { amountOut, priceImpact };
18477
+ }
18478
+
18479
+ // src/swap/execute.ts
18480
+ var SWAP_MAX_WAIT_MS = 18e4;
18481
+ var DEFAULT_SLIPPAGE_BPS = 100;
18482
+ var MAX_SLIPPAGE_BPS = 5e3;
18483
+ var MAX_PRICE_IMPACT = 0.1;
18484
+ var hex = (bytes) => `0x${bytesToHex(bytes)}`;
18485
+ var mintKey = (mint) => mint?.toBase58() ?? null;
18486
+ async function fetchRelayerQuote(relayerUrl, mintIn, mintOut, amountIn) {
18487
+ const params = new URLSearchParams({ amountIn: amountIn.toString() });
18488
+ if (mintIn) params.set("mintIn", mintIn.toBase58());
18489
+ if (mintOut) params.set("mintOut", mintOut.toBase58());
18490
+ const base = relayerUrl.replace(/\/$/, "");
18491
+ const res = await httpFetch(`${base}/v1/swapQuote?${params}`, {
18492
+ headers: { Accept: "application/json" }
18493
+ });
18494
+ const body = await res.json().catch(() => ({}));
18495
+ if (!res.ok) {
18496
+ throw new Error(body.error || `Swap quote failed (${res.status})`);
18497
+ }
18498
+ return { ...body, relayerUrl: base };
18499
+ }
18500
+ function swapCandidates(relayers, relayerUrl) {
18501
+ if (relayerUrl) {
18502
+ const wanted = relayerUrl.replace(/\/$/, "");
18503
+ const match = relayers.find((r) => r.url.replace(/\/$/, "") === wanted);
18504
+ if (!match) throw new Error(`veilix-sdk: relayer ${relayerUrl} is not available`);
18505
+ return [match];
18506
+ }
18507
+ if (!relayers.length) throw new Error("veilix-sdk: no relayer available");
18508
+ const first = getRandomRelayer(relayers);
18509
+ return [first, ...relayers.filter((r) => r !== first)];
18510
+ }
18511
+ async function getSwapQuote(params) {
18512
+ const { relayers } = getConfig();
18513
+ const mintIn = normalizeTreeMint(params.mintIn);
18514
+ const mintOut = normalizeTreeMint(params.mintOut);
18515
+ if (mintKey(mintIn) === mintKey(mintOut)) {
18516
+ throw new Error("veilix-sdk: swap needs two different assets");
18517
+ }
18518
+ const amountIn = BigInt(params.amountIn);
18519
+ if (amountIn <= 0n) throw new Error("veilix-sdk: swap amount must be positive");
18520
+ const { connection, network } = getConfig();
18521
+ const platformWallets = await fetchPlatformFeeWallets();
18522
+ let lastError = null;
18523
+ for (const relayer of swapCandidates(relayers, params.relayerUrl)) {
18524
+ try {
18525
+ const quote = await fetchRelayerQuote(relayer.url, mintIn, mintOut, amountIn);
18526
+ if (quote.relayer !== relayer.value) {
18527
+ throw new Error("Relayer quoted for a different reward account");
18528
+ }
18529
+ const { fee } = computeWithdrawFee(amountIn, relayer.fee, platformWallets);
18530
+ if (fee >= amountIn) throw new Error("Amount is too small to cover the fees");
18531
+ if (BigInt(quote.fee) !== fee) throw new Error("Relayer quoted a different fee");
18532
+ if (quote.dexProgram !== CPMM_PROGRAM_IDS[network]) {
18533
+ throw new Error("Relayer routes through an unsupported DEX");
18534
+ }
18535
+ const own = await quoteCpmm(
18536
+ connection,
18537
+ network,
18538
+ new PublicKey(quote.pool),
18539
+ mintIn,
18540
+ mintOut,
18541
+ amountIn - fee
18542
+ );
18543
+ if (own.priceImpact > MAX_PRICE_IMPACT) {
18544
+ throw new Error(
18545
+ `Price impact ${(own.priceImpact * 100).toFixed(1)}% is too high for this pool; swap less`
18546
+ );
18547
+ }
18548
+ return {
18549
+ quote: {
18550
+ ...quote,
18551
+ swapIn: (amountIn - fee).toString(),
18552
+ amountOut: own.amountOut.toString(),
18553
+ priceImpact: own.priceImpact
18554
+ },
18555
+ relayer
18556
+ };
18557
+ } catch (error) {
18558
+ lastError = error;
18559
+ }
18560
+ }
18561
+ const reason = lastError instanceof Error ? lastError.message : "no relayer routes this pair";
18562
+ throw new Error(`veilix-sdk: no swap route for this pair (${reason})`);
18563
+ }
18564
+ async function buildSwapPayload(params, options = {}) {
18565
+ const { encryptKey } = getConfig();
18566
+ const utxo = decodeNote(params.note);
18567
+ const mintIn = utxo.mint;
18568
+ const mintOut = normalizeTreeMint(params.mintOut ?? null);
18569
+ const slippageBps = params.slippageBps ?? DEFAULT_SLIPPAGE_BPS;
18570
+ if (!Number.isInteger(slippageBps) || slippageBps < 0 || slippageBps > MAX_SLIPPAGE_BPS) {
18571
+ throw new Error(`veilix-sdk: slippageBps must be an integer between 0 and ${MAX_SLIPPAGE_BPS}`);
18572
+ }
18573
+ const { index } = await locateNote(utxo);
18574
+ if (index === null) {
18575
+ throw new Error("Note is not in the Veilix pool yet (deposit not confirmed or not indexed)");
18576
+ }
18577
+ utxo.index = index;
18578
+ if ((await validateNullifier(toHex32(utxo.nullifier()))).exists) {
18579
+ throw new Error("This note has already been spent");
18580
+ }
18581
+ const amountIn = params.amount === void 0 ? utxo.amount : BigInt(params.amount);
18582
+ if (amountIn <= 0n || amountIn > utxo.amount) {
18583
+ throw new Error(`Swap amount must be between 1 and ${utxo.amount}`);
18584
+ }
18585
+ const { quote, relayer } = await getSwapQuote({
18586
+ mintIn,
18587
+ mintOut,
18588
+ amountIn,
18589
+ relayerUrl: params.relayerUrl
18590
+ });
18591
+ const fee = BigInt(quote.fee);
18592
+ const minAmountOut = BigInt(quote.amountOut) * BigInt(1e4 - slippageBps) / 10000n;
18593
+ if (minAmountOut <= 0n) {
18594
+ throw new Error("Swap amount is too small for this pool");
18595
+ }
18596
+ let tree = options.tree;
18597
+ if (!tree || tree.elements.length <= index) {
18598
+ tree = await fetchAssetTree(mintKey(mintIn));
18599
+ }
18600
+ if (tree.elements.length <= index) {
18601
+ throw new Error("The indexer has not synced this note yet, retry shortly");
18602
+ }
18603
+ const change = utxo.amount - amountIn;
18604
+ const changeUtxo = change > 0n ? new Utxo({ amount: change, mint: mintIn }) : null;
18605
+ const encryptedOutput1 = changeUtxo && encryptKey ? encryptNoteOutput(encryptKey, changeUtxo) : new Uint8Array();
18606
+ const encryptedOutput2 = new Uint8Array();
18607
+ const outKeypair = VeilixKeypair.random();
18608
+ const outBlinding = randomFieldElement();
18609
+ const encryptedNote = encryptKey ? encryptSwapNoteOutput(encryptKey, outKeypair, outBlinding) : new Uint8Array();
18610
+ const relayerKey = new PublicKey(relayer.value);
18611
+ const hash = await swapExtDataHash({
18612
+ mintIn,
18613
+ mintOut,
18614
+ relayer: relayerKey,
18615
+ amountIn,
18616
+ fee,
18617
+ minAmountOut,
18618
+ outPubkey: outKeypair.pubKey,
18619
+ outBlinding,
18620
+ encryptedOutput1,
18621
+ encryptedOutput2,
18622
+ encryptedNote
18623
+ });
18624
+ const proved = await withCircuitArtifacts(
18625
+ options.circuitArtifacts,
18626
+ (artifacts) => proveTransaction({
18627
+ tree,
18628
+ inputs: [utxo],
18629
+ outputs: changeUtxo ? [changeUtxo] : [],
18630
+ ext: {
18631
+ mint: mintIn,
18632
+ recipient: PublicKey.default,
18633
+ relayer: relayerKey,
18634
+ extAmount: -amountIn,
18635
+ fee,
18636
+ encryptedOutput1,
18637
+ encryptedOutput2
18638
+ },
18639
+ extDataHashOverride: hash,
18640
+ circuit: artifacts
18641
+ })
18642
+ );
18643
+ const { proof } = proved;
18644
+ const payload = {
18645
+ proof: hex(proof.proof),
18646
+ root: hex(proof.root),
18647
+ inputNullifiers: [hex(proof.inputNullifiers[0]), hex(proof.inputNullifiers[1])],
18648
+ outputCommitments: [hex(proof.outputCommitments[0]), hex(proof.outputCommitments[1])],
18649
+ ...mintIn ? { mintIn: mintIn.toBase58() } : {},
18650
+ ...mintOut ? { mintOut: mintOut.toBase58() } : {},
18651
+ amountIn: amountIn.toString(),
18652
+ fee: fee.toString(),
18653
+ minAmountOut: minAmountOut.toString(),
18654
+ outPubkey: hex(bigintToBytes32(outKeypair.pubKey)),
18655
+ outBlinding: hex(bigintToBytes32(outBlinding)),
18656
+ relayer: relayerKey.toBase58(),
18657
+ encryptedOutput1: hex(encryptedOutput1),
18658
+ encryptedOutput2: hex(encryptedOutput2),
18659
+ encryptedNote: hex(encryptedNote)
18660
+ };
18661
+ return {
18662
+ payload,
18663
+ relayerUrl: quote.relayerUrl,
18664
+ quote,
18665
+ amountIn,
18666
+ fee,
18667
+ minAmountOut,
18668
+ changeNote: changeUtxo ? encodeNote(changeUtxo) : null,
18669
+ output: {
18670
+ mint: mintKey(mintOut),
18671
+ privKey: outKeypair.privKey.toString(),
18672
+ blinding: outBlinding.toString()
18673
+ },
18674
+ nullifiers: [...payload.inputNullifiers]
18675
+ };
18676
+ }
18677
+ async function pollSwapJob(relayerUrl, jobId, maxWaitMs) {
18678
+ const start = Date.now();
18679
+ while (Date.now() - start < maxWaitMs) {
18680
+ const res = await httpFetch(`${relayerUrl}/v1/jobs/${encodeURIComponent(jobId)}`, {
18681
+ headers: { Accept: "application/json" }
18682
+ });
18683
+ const job = await res.json().catch(() => ({}));
18684
+ if (!res.ok) throw new Error(job.error || "Failed to poll relayer job");
18685
+ if (job.status === "CONFIRMED" || job.status === "FAILED") return job;
18686
+ await new Promise((resolve) => setTimeout(resolve, 3e3));
18687
+ }
18688
+ throw new Error("Swap timed out");
18689
+ }
18690
+ function swapOutputNote(output, result) {
18691
+ const utxo = new Utxo({
18692
+ amount: BigInt(result.amountOut),
18693
+ keypair: VeilixKeypair.fromPrivateKey(output.privKey),
18694
+ blinding: BigInt(output.blinding),
18695
+ mint: output.mint ? new PublicKey(output.mint) : null,
18696
+ index: result.outputIndex
18697
+ });
18698
+ if (toHex32(utxo.commitment()) !== toHex32(BigInt(result.outputCommitment))) {
18699
+ throw new Error("veilix-sdk: swapped note does not match the on-chain commitment");
18700
+ }
18701
+ return encodeNote(utxo);
18702
+ }
18703
+ async function submitSwapPayload(bundle) {
18704
+ const res = await httpFetch(`${bundle.relayerUrl}/v1/veilixSwap`, {
18705
+ method: "POST",
18706
+ headers: { "Content-Type": "application/json" },
18707
+ body: JSON.stringify(bundle.payload)
18708
+ });
18709
+ const body = await res.json().catch(() => ({}));
18710
+ if (!res.ok || !body.id) {
18711
+ throw new Error(body.error || "Swap submission failed");
18712
+ }
18713
+ const job = await pollSwapJob(bundle.relayerUrl, body.id, SWAP_MAX_WAIT_MS);
18714
+ const base = {
18715
+ changeNote: bundle.changeNote,
18716
+ amountIn: bundle.amountIn.toString(),
18717
+ fee: bundle.fee.toString(),
18718
+ minAmountOut: bundle.minAmountOut.toString()
18719
+ };
18720
+ if (job.status === "FAILED") {
18721
+ return {
18722
+ ...base,
18723
+ txHash: job.txHash ?? "",
18724
+ status: "failed",
18725
+ error: job.failedReason || "Swap failed",
18726
+ // A failed swap spends nothing: the original note is still valid.
18727
+ outputNote: null,
18728
+ changeNote: null,
18729
+ amountOut: null
18730
+ };
18731
+ }
18732
+ if (!job.txHash || !job.swapResult) {
18733
+ throw new Error("Swap confirmed but the relayer did not report the swapped note");
18734
+ }
18735
+ return {
18736
+ ...base,
18737
+ txHash: job.txHash,
18738
+ status: "success",
18739
+ outputNote: swapOutputNote(bundle.output, job.swapResult),
18740
+ amountOut: job.swapResult.amountOut
18741
+ };
18742
+ }
18743
+ async function executeSwap(params) {
18744
+ return submitSwapPayload(await buildSwapPayload(params));
18745
+ }
17500
18746
 
17501
18747
  // src/withdraw/assets.ts
17502
18748
  var TOKEN_UNITS = {
@@ -17937,6 +19183,26 @@ var VeilixSDK = class _VeilixSDK {
17937
19183
  submitWithdrawPayload(bundle) {
17938
19184
  return this.runAsync(() => submitWithdrawPayload(bundle));
17939
19185
  }
19186
+ // ── Private swap ─────────────────────────────────────────────────────
19187
+ /** Fee and expected output of swapping `amountIn` of `mintIn` into `mintOut`. */
19188
+ getSwapQuote(params) {
19189
+ return this.runAsync(() => getSwapQuote(params));
19190
+ }
19191
+ /**
19192
+ * Swap a note of asset A into a new shielded note of asset B (`mintOut`, `null` for
19193
+ * SOL) through a relayer and an allowlisted DEX. Funds never leave the pool
19194
+ * unshielded. Returns the asset-B note and any asset-A change note.
19195
+ */
19196
+ swap(params) {
19197
+ return this.runAsync(() => executeSwap(params));
19198
+ }
19199
+ /** Prove a swap without submitting it (see {@link submitSwapPayload}). */
19200
+ buildSwapPayload(params, options) {
19201
+ return this.runAsync(() => buildSwapPayload(params, options));
19202
+ }
19203
+ submitSwapPayload(bundle) {
19204
+ return this.runAsync(() => submitSwapPayload(bundle));
19205
+ }
17940
19206
  /**
17941
19207
  * Private transfer: deposit one note per item, then withdraw each note in full
17942
19208
  * to its recipient through the indexer submission queue.
@@ -18048,15 +19314,15 @@ var VeilixSDK = class _VeilixSDK {
18048
19314
  * Accepts a frontend wallet adapter (`signMessage`) or a backend {@link Keypair}.
18049
19315
  */
18050
19316
  async getEncryptionKey(wallet) {
18051
- const key = await getEncryptionKey(wallet);
18052
- this.config.encryptKey = key;
18053
- return key;
19317
+ const key2 = await getEncryptionKey(wallet);
19318
+ this.config.encryptKey = key2;
19319
+ return key2;
18054
19320
  }
18055
- encryptData(key, plaintext) {
18056
- return encryptData(key, plaintext);
19321
+ encryptData(key2, plaintext) {
19322
+ return encryptData(key2, plaintext);
18057
19323
  }
18058
- decryptData(key, combined) {
18059
- return decryptData(key, combined);
19324
+ decryptData(key2, combined) {
19325
+ return decryptData(key2, combined);
18060
19326
  }
18061
19327
  // ── Utilities ────────────────────────────────────────────────────────
18062
19328
  parseAmountToBaseUnits(amount, decimals) {