veilix-sdk 0.2.2 → 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.
@@ -67,7 +67,7 @@ function formatBaseUnits(value, decimals) {
67
67
 
68
68
  // src/idl/veilix-devnet.json
69
69
  var veilix_devnet_default = {
70
- address: "HbatG5gpfs2g3N4gc2Qkfmmeu4zaBEVxzrDdYtWNLyyA",
70
+ address: "Vxi1QK84Akv4yGngjvkWNmEsK7XpsSrpDaPBoiyXGPG",
71
71
  metadata: {
72
72
  name: "veilix",
73
73
  version: "0.2.0",
@@ -668,6 +668,38 @@ var veilix_devnet_default = {
668
668
  {
669
669
  name: "system_program",
670
670
  address: "11111111111111111111111111111111"
671
+ },
672
+ {
673
+ name: "event_authority",
674
+ pda: {
675
+ seeds: [
676
+ {
677
+ kind: "const",
678
+ value: [
679
+ 95,
680
+ 95,
681
+ 101,
682
+ 118,
683
+ 101,
684
+ 110,
685
+ 116,
686
+ 95,
687
+ 97,
688
+ 117,
689
+ 116,
690
+ 104,
691
+ 111,
692
+ 114,
693
+ 105,
694
+ 116,
695
+ 121
696
+ ]
697
+ }
698
+ ]
699
+ }
700
+ },
701
+ {
702
+ name: "program"
671
703
  }
672
704
  ],
673
705
  args: [
@@ -730,6 +762,91 @@ var veilix_devnet_default = {
730
762
  ]
731
763
  }
732
764
  },
765
+ {
766
+ name: "program_data",
767
+ docs: [
768
+ "This program's ProgramData. Only its upgrade authority may initialize the network,",
769
+ "so nobody can claim the config authority between deploy and setup."
770
+ ],
771
+ pda: {
772
+ seeds: [
773
+ {
774
+ kind: "const",
775
+ value: [
776
+ 7,
777
+ 107,
778
+ 64,
779
+ 50,
780
+ 251,
781
+ 172,
782
+ 47,
783
+ 215,
784
+ 89,
785
+ 179,
786
+ 92,
787
+ 125,
788
+ 67,
789
+ 162,
790
+ 96,
791
+ 45,
792
+ 239,
793
+ 91,
794
+ 223,
795
+ 168,
796
+ 251,
797
+ 138,
798
+ 165,
799
+ 133,
800
+ 253,
801
+ 74,
802
+ 152,
803
+ 142,
804
+ 6,
805
+ 85,
806
+ 93,
807
+ 119
808
+ ]
809
+ }
810
+ ],
811
+ program: {
812
+ kind: "const",
813
+ value: [
814
+ 2,
815
+ 168,
816
+ 246,
817
+ 145,
818
+ 78,
819
+ 136,
820
+ 161,
821
+ 176,
822
+ 226,
823
+ 16,
824
+ 21,
825
+ 62,
826
+ 247,
827
+ 99,
828
+ 174,
829
+ 43,
830
+ 0,
831
+ 194,
832
+ 185,
833
+ 61,
834
+ 22,
835
+ 193,
836
+ 36,
837
+ 210,
838
+ 192,
839
+ 83,
840
+ 122,
841
+ 16,
842
+ 4,
843
+ 128,
844
+ 0,
845
+ 0
846
+ ]
847
+ }
848
+ }
849
+ },
733
850
  {
734
851
  name: "system_program",
735
852
  address: "11111111111111111111111111111111"
@@ -1058,6 +1175,31 @@ var veilix_devnet_default = {
1058
1175
  ]
1059
1176
  }
1060
1177
  },
1178
+ {
1179
+ name: "treasury",
1180
+ docs: [
1181
+ "Holds the SOL pool. Funded with its rent-exempt reserve here so that no withdrawal",
1182
+ "can fail for leaving it below that reserve."
1183
+ ],
1184
+ writable: true,
1185
+ pda: {
1186
+ seeds: [
1187
+ {
1188
+ kind: "const",
1189
+ value: [
1190
+ 116,
1191
+ 114,
1192
+ 101,
1193
+ 97,
1194
+ 115,
1195
+ 117,
1196
+ 114,
1197
+ 121
1198
+ ]
1199
+ }
1200
+ ]
1201
+ }
1202
+ },
1061
1203
  {
1062
1204
  name: "system_program",
1063
1205
  address: "11111111111111111111111111111111"
@@ -1453,38 +1595,368 @@ var veilix_devnet_default = {
1453
1595
  ],
1454
1596
  accounts: [
1455
1597
  {
1456
- name: "user",
1457
- signer: true
1598
+ name: "user",
1599
+ signer: true
1600
+ },
1601
+ {
1602
+ name: "relayer",
1603
+ writable: true,
1604
+ pda: {
1605
+ seeds: [
1606
+ {
1607
+ kind: "const",
1608
+ value: [
1609
+ 114,
1610
+ 101,
1611
+ 108,
1612
+ 97,
1613
+ 121,
1614
+ 101,
1615
+ 114
1616
+ ]
1617
+ },
1618
+ {
1619
+ kind: "account",
1620
+ path: "user"
1621
+ }
1622
+ ]
1623
+ }
1624
+ }
1625
+ ],
1626
+ args: [
1627
+ {
1628
+ name: "worker",
1629
+ type: "pubkey"
1630
+ }
1631
+ ]
1632
+ },
1633
+ {
1634
+ name: "swap",
1635
+ docs: [
1636
+ "Private swap. Remaining accounts: the protocol fee wallets for the input asset (SOL",
1637
+ "accounts or their token accounts, in config order), then the DEX instruction's accounts."
1638
+ ],
1639
+ discriminator: [
1640
+ 248,
1641
+ 198,
1642
+ 158,
1643
+ 145,
1644
+ 225,
1645
+ 117,
1646
+ 135,
1647
+ 200
1648
+ ],
1649
+ accounts: [
1650
+ {
1651
+ name: "relayer",
1652
+ writable: true,
1653
+ signer: true
1654
+ },
1655
+ {
1656
+ name: "relayer_account",
1657
+ writable: true,
1658
+ pda: {
1659
+ seeds: [
1660
+ {
1661
+ kind: "const",
1662
+ value: [
1663
+ 114,
1664
+ 101,
1665
+ 108,
1666
+ 97,
1667
+ 121,
1668
+ 101,
1669
+ 114
1670
+ ]
1671
+ },
1672
+ {
1673
+ kind: "account",
1674
+ path: "relayer_account.owner",
1675
+ account: "RelayerAccount"
1676
+ }
1677
+ ]
1678
+ }
1679
+ },
1680
+ {
1681
+ name: "network_state",
1682
+ pda: {
1683
+ seeds: [
1684
+ {
1685
+ kind: "const",
1686
+ value: [
1687
+ 99,
1688
+ 111,
1689
+ 110,
1690
+ 102,
1691
+ 105,
1692
+ 103
1693
+ ]
1694
+ }
1695
+ ]
1696
+ }
1697
+ },
1698
+ {
1699
+ name: "swap_config",
1700
+ pda: {
1701
+ seeds: [
1702
+ {
1703
+ kind: "const",
1704
+ value: [
1705
+ 115,
1706
+ 119,
1707
+ 97,
1708
+ 112,
1709
+ 95,
1710
+ 99,
1711
+ 111,
1712
+ 110,
1713
+ 102,
1714
+ 105,
1715
+ 103
1716
+ ]
1717
+ }
1718
+ ]
1719
+ }
1720
+ },
1721
+ {
1722
+ name: "tree_in",
1723
+ docs: [
1724
+ "Tree of the asset being spent. The handler checks it is the PDA for its mint."
1725
+ ],
1726
+ writable: true
1727
+ },
1728
+ {
1729
+ name: "tree_out",
1730
+ docs: [
1731
+ "Tree that receives the swapped note."
1732
+ ],
1733
+ writable: true
1734
+ },
1735
+ {
1736
+ name: "treasury",
1737
+ writable: true,
1738
+ pda: {
1739
+ seeds: [
1740
+ {
1741
+ kind: "const",
1742
+ value: [
1743
+ 116,
1744
+ 114,
1745
+ 101,
1746
+ 97,
1747
+ 115,
1748
+ 117,
1749
+ 114,
1750
+ 121
1751
+ ]
1752
+ }
1753
+ ]
1754
+ }
1755
+ },
1756
+ {
1757
+ name: "escrow",
1758
+ docs: [
1759
+ "Signs the DEX call. Holds nothing between transactions."
1760
+ ],
1761
+ writable: true,
1762
+ pda: {
1763
+ seeds: [
1764
+ {
1765
+ kind: "const",
1766
+ value: [
1767
+ 115,
1768
+ 119,
1769
+ 97,
1770
+ 112,
1771
+ 95,
1772
+ 101,
1773
+ 115,
1774
+ 99,
1775
+ 114,
1776
+ 111,
1777
+ 119
1778
+ ]
1779
+ }
1780
+ ]
1781
+ }
1782
+ },
1783
+ {
1784
+ name: "treasury_ata_in",
1785
+ docs: [
1786
+ "Treasury ATA for `mint_in`. `None` when spending SOL."
1787
+ ],
1788
+ writable: true,
1789
+ optional: true
1790
+ },
1791
+ {
1792
+ name: "treasury_ata_out",
1793
+ docs: [
1794
+ "Treasury ATA for `mint_out`. `None` when receiving SOL."
1795
+ ],
1796
+ writable: true,
1797
+ optional: true
1798
+ },
1799
+ {
1800
+ name: "escrow_ata_in",
1801
+ docs: [
1802
+ "Escrow ATA for `mint_in` (wrapped SOL when spending SOL). Must exist: prepend an",
1803
+ "idempotent ATA create. A wrapped-SOL escrow account is closed at the end of the swap."
1804
+ ],
1805
+ writable: true
1806
+ },
1807
+ {
1808
+ name: "escrow_ata_out",
1809
+ docs: [
1810
+ "Escrow ATA for `mint_out` (wrapped SOL when receiving SOL). Must exist, as above."
1811
+ ],
1812
+ writable: true
1813
+ },
1814
+ {
1815
+ name: "relayer_ata",
1816
+ docs: [
1817
+ "Relayer ATA for `mint_in`, paid the relayer fee. `None` when spending SOL."
1818
+ ],
1819
+ writable: true,
1820
+ optional: true
1821
+ },
1822
+ {
1823
+ name: "nullifier0",
1824
+ writable: true,
1825
+ pda: {
1826
+ seeds: [
1827
+ {
1828
+ kind: "const",
1829
+ value: [
1830
+ 110,
1831
+ 117,
1832
+ 108,
1833
+ 108,
1834
+ 105,
1835
+ 102,
1836
+ 105,
1837
+ 101,
1838
+ 114
1839
+ ]
1840
+ },
1841
+ {
1842
+ kind: "arg",
1843
+ path: "proof.input_nullifiers [0]"
1844
+ }
1845
+ ]
1846
+ }
1847
+ },
1848
+ {
1849
+ name: "nullifier1",
1850
+ writable: true,
1851
+ pda: {
1852
+ seeds: [
1853
+ {
1854
+ kind: "const",
1855
+ value: [
1856
+ 110,
1857
+ 117,
1858
+ 108,
1859
+ 108,
1860
+ 105,
1861
+ 102,
1862
+ 105,
1863
+ 101,
1864
+ 114
1865
+ ]
1866
+ },
1867
+ {
1868
+ kind: "arg",
1869
+ path: "proof.input_nullifiers [1]"
1870
+ }
1871
+ ]
1872
+ }
1873
+ },
1874
+ {
1875
+ name: "mint_in",
1876
+ docs: [
1877
+ "Mint of the spent asset (the native mint when spending SOL)."
1878
+ ]
1879
+ },
1880
+ {
1881
+ name: "mint_out",
1882
+ docs: [
1883
+ "Mint of the received asset (the native mint when receiving SOL)."
1884
+ ]
1885
+ },
1886
+ {
1887
+ name: "token_program_in"
1888
+ },
1889
+ {
1890
+ name: "token_program_out"
1891
+ },
1892
+ {
1893
+ name: "dex_program"
1458
1894
  },
1459
1895
  {
1460
- name: "relayer",
1461
- writable: true,
1896
+ name: "system_program",
1897
+ address: "11111111111111111111111111111111"
1898
+ },
1899
+ {
1900
+ name: "event_authority",
1462
1901
  pda: {
1463
1902
  seeds: [
1464
1903
  {
1465
1904
  kind: "const",
1466
1905
  value: [
1467
- 114,
1906
+ 95,
1907
+ 95,
1468
1908
  101,
1469
- 108,
1470
- 97,
1471
- 121,
1909
+ 118,
1472
1910
  101,
1473
- 114
1911
+ 110,
1912
+ 116,
1913
+ 95,
1914
+ 97,
1915
+ 117,
1916
+ 116,
1917
+ 104,
1918
+ 111,
1919
+ 114,
1920
+ 105,
1921
+ 116,
1922
+ 121
1474
1923
  ]
1475
- },
1476
- {
1477
- kind: "account",
1478
- path: "user"
1479
1924
  }
1480
1925
  ]
1481
1926
  }
1927
+ },
1928
+ {
1929
+ name: "program"
1482
1930
  }
1483
1931
  ],
1484
1932
  args: [
1485
1933
  {
1486
- name: "worker",
1487
- type: "pubkey"
1934
+ name: "proof",
1935
+ type: {
1936
+ defined: {
1937
+ name: "TransactionProof"
1938
+ }
1939
+ }
1940
+ },
1941
+ {
1942
+ name: "params",
1943
+ type: {
1944
+ defined: {
1945
+ name: "SwapParams"
1946
+ }
1947
+ }
1948
+ },
1949
+ {
1950
+ name: "encrypted_output1",
1951
+ type: "bytes"
1952
+ },
1953
+ {
1954
+ name: "encrypted_output2",
1955
+ type: "bytes"
1956
+ },
1957
+ {
1958
+ name: "route_data",
1959
+ type: "bytes"
1488
1960
  }
1489
1961
  ]
1490
1962
  },
@@ -1722,6 +2194,38 @@ var veilix_devnet_default = {
1722
2194
  {
1723
2195
  name: "system_program",
1724
2196
  address: "11111111111111111111111111111111"
2197
+ },
2198
+ {
2199
+ name: "event_authority",
2200
+ pda: {
2201
+ seeds: [
2202
+ {
2203
+ kind: "const",
2204
+ value: [
2205
+ 95,
2206
+ 95,
2207
+ 101,
2208
+ 118,
2209
+ 101,
2210
+ 110,
2211
+ 116,
2212
+ 95,
2213
+ 97,
2214
+ 117,
2215
+ 116,
2216
+ 104,
2217
+ 111,
2218
+ 114,
2219
+ 105,
2220
+ 116,
2221
+ 121
2222
+ ]
2223
+ }
2224
+ ]
2225
+ }
2226
+ },
2227
+ {
2228
+ name: "program"
1725
2229
  }
1726
2230
  ],
1727
2231
  args: [
@@ -2088,6 +2592,38 @@ var veilix_devnet_default = {
2088
2592
  {
2089
2593
  name: "system_program",
2090
2594
  address: "11111111111111111111111111111111"
2595
+ },
2596
+ {
2597
+ name: "event_authority",
2598
+ pda: {
2599
+ seeds: [
2600
+ {
2601
+ kind: "const",
2602
+ value: [
2603
+ 95,
2604
+ 95,
2605
+ 101,
2606
+ 118,
2607
+ 101,
2608
+ 110,
2609
+ 116,
2610
+ 95,
2611
+ 97,
2612
+ 117,
2613
+ 116,
2614
+ 104,
2615
+ 111,
2616
+ 114,
2617
+ 105,
2618
+ 116,
2619
+ 121
2620
+ ]
2621
+ }
2622
+ ]
2623
+ }
2624
+ },
2625
+ {
2626
+ name: "program"
2091
2627
  }
2092
2628
  ],
2093
2629
  args: [
@@ -2536,6 +3072,83 @@ var veilix_devnet_default = {
2536
3072
  }
2537
3073
  ]
2538
3074
  },
3075
+ {
3076
+ name: "update_swap_config",
3077
+ docs: [
3078
+ "Replaces the list of DEX programs the swap escrow may call. Config authority only."
3079
+ ],
3080
+ discriminator: [
3081
+ 123,
3082
+ 172,
3083
+ 158,
3084
+ 60,
3085
+ 104,
3086
+ 133,
3087
+ 39,
3088
+ 13
3089
+ ],
3090
+ accounts: [
3091
+ {
3092
+ name: "authority",
3093
+ writable: true,
3094
+ signer: true
3095
+ },
3096
+ {
3097
+ name: "network_state",
3098
+ pda: {
3099
+ seeds: [
3100
+ {
3101
+ kind: "const",
3102
+ value: [
3103
+ 99,
3104
+ 111,
3105
+ 110,
3106
+ 102,
3107
+ 105,
3108
+ 103
3109
+ ]
3110
+ }
3111
+ ]
3112
+ }
3113
+ },
3114
+ {
3115
+ name: "swap_config",
3116
+ writable: true,
3117
+ pda: {
3118
+ seeds: [
3119
+ {
3120
+ kind: "const",
3121
+ value: [
3122
+ 115,
3123
+ 119,
3124
+ 97,
3125
+ 112,
3126
+ 95,
3127
+ 99,
3128
+ 111,
3129
+ 110,
3130
+ 102,
3131
+ 105,
3132
+ 103
3133
+ ]
3134
+ }
3135
+ ]
3136
+ }
3137
+ },
3138
+ {
3139
+ name: "system_program",
3140
+ address: "11111111111111111111111111111111"
3141
+ }
3142
+ ],
3143
+ args: [
3144
+ {
3145
+ name: "allowed_programs",
3146
+ type: {
3147
+ vec: "pubkey"
3148
+ }
3149
+ }
3150
+ ]
3151
+ },
2539
3152
  {
2540
3153
  name: "withdraw",
2541
3154
  discriminator: [
@@ -2694,6 +3307,38 @@ var veilix_devnet_default = {
2694
3307
  {
2695
3308
  name: "system_program",
2696
3309
  address: "11111111111111111111111111111111"
3310
+ },
3311
+ {
3312
+ name: "event_authority",
3313
+ pda: {
3314
+ seeds: [
3315
+ {
3316
+ kind: "const",
3317
+ value: [
3318
+ 95,
3319
+ 95,
3320
+ 101,
3321
+ 118,
3322
+ 101,
3323
+ 110,
3324
+ 116,
3325
+ 95,
3326
+ 97,
3327
+ 117,
3328
+ 116,
3329
+ 104,
3330
+ 111,
3331
+ 114,
3332
+ 105,
3333
+ 116,
3334
+ 121
3335
+ ]
3336
+ }
3337
+ ]
3338
+ }
3339
+ },
3340
+ {
3341
+ name: "program"
2697
3342
  }
2698
3343
  ],
2699
3344
  args: [
@@ -2803,6 +3448,19 @@ var veilix_devnet_default = {
2803
3448
  20
2804
3449
  ]
2805
3450
  },
3451
+ {
3452
+ name: "SwapConfig",
3453
+ discriminator: [
3454
+ 212,
3455
+ 45,
3456
+ 70,
3457
+ 222,
3458
+ 245,
3459
+ 122,
3460
+ 125,
3461
+ 166
3462
+ ]
3463
+ },
2806
3464
  {
2807
3465
  name: "TreeAccount",
2808
3466
  discriminator: [
@@ -2844,6 +3502,19 @@ var veilix_devnet_default = {
2844
3502
  159
2845
3503
  ]
2846
3504
  },
3505
+ {
3506
+ name: "PrivateSwapEvent",
3507
+ discriminator: [
3508
+ 150,
3509
+ 165,
3510
+ 138,
3511
+ 189,
3512
+ 123,
3513
+ 86,
3514
+ 117,
3515
+ 39
3516
+ ]
3517
+ },
2847
3518
  {
2848
3519
  name: "RelayerCancelled",
2849
3520
  discriminator: [
@@ -3103,9 +3774,59 @@ var veilix_devnet_default = {
3103
3774
  msg: "Relayer has earned fees in too many assets"
3104
3775
  },
3105
3776
  {
3106
- code: 6033,
3107
- name: "FeeRepaymentAccounts",
3108
- msg: "Fee repayment accounts do not match earned fees"
3777
+ code: 6033,
3778
+ name: "FeeRepaymentAccounts",
3779
+ msg: "Fee repayment accounts do not match earned fees"
3780
+ },
3781
+ {
3782
+ code: 6034,
3783
+ name: "DexProgramNotAllowed",
3784
+ msg: "DEX program is not on the swap allowlist"
3785
+ },
3786
+ {
3787
+ code: 6035,
3788
+ name: "TooManyDexPrograms",
3789
+ msg: "Too many allowlisted DEX programs"
3790
+ },
3791
+ {
3792
+ code: 6036,
3793
+ name: "SlippageExceeded",
3794
+ msg: "Swap output is below the minimum amount"
3795
+ },
3796
+ {
3797
+ code: 6037,
3798
+ name: "SwapInputMismatch",
3799
+ msg: "DEX did not use exactly the escrowed swap input"
3800
+ },
3801
+ {
3802
+ code: 6038,
3803
+ name: "InvalidSwapAccounts",
3804
+ msg: "Swap accounts do not match the trees"
3805
+ },
3806
+ {
3807
+ code: 6039,
3808
+ name: "EscrowTampered",
3809
+ msg: "Swap escrow was modified by the DEX"
3810
+ },
3811
+ {
3812
+ code: 6040,
3813
+ name: "InvalidNoteKey",
3814
+ msg: "Note public key or blinding is not a valid field element"
3815
+ },
3816
+ {
3817
+ code: 6041,
3818
+ name: "NotUpgradeAuthority",
3819
+ msg: "Only the program upgrade authority can initialize the network"
3820
+ },
3821
+ {
3822
+ code: 6042,
3823
+ name: "InvalidFeeSplit",
3824
+ msg: "Fee wallets must be distinct, non-default and split at most the allowed total"
3825
+ },
3826
+ {
3827
+ code: 6043,
3828
+ name: "UnsupportedMintExtension",
3829
+ msg: "Token mint has an extension the pool does not support"
3109
3830
  }
3110
3831
  ],
3111
3832
  types: [
@@ -3286,6 +4007,68 @@ var veilix_devnet_default = {
3286
4007
  kind: "struct"
3287
4008
  }
3288
4009
  },
4010
+ {
4011
+ name: "PrivateSwapEvent",
4012
+ docs: [
4013
+ "Emitted once per swap. The asset-B note is `commitment` at `index` in the `mint_out` tree."
4014
+ ],
4015
+ type: {
4016
+ kind: "struct",
4017
+ fields: [
4018
+ {
4019
+ name: "mint_in",
4020
+ type: "pubkey"
4021
+ },
4022
+ {
4023
+ name: "mint_out",
4024
+ type: "pubkey"
4025
+ },
4026
+ {
4027
+ name: "amount_in",
4028
+ type: "u64"
4029
+ },
4030
+ {
4031
+ name: "fee",
4032
+ type: "u64"
4033
+ },
4034
+ {
4035
+ name: "amount_out",
4036
+ type: "u64"
4037
+ },
4038
+ {
4039
+ name: "input_nullifiers",
4040
+ type: {
4041
+ array: [
4042
+ {
4043
+ array: [
4044
+ "u8",
4045
+ 32
4046
+ ]
4047
+ },
4048
+ 2
4049
+ ]
4050
+ }
4051
+ },
4052
+ {
4053
+ name: "relayer",
4054
+ type: "pubkey"
4055
+ },
4056
+ {
4057
+ name: "commitment",
4058
+ type: {
4059
+ array: [
4060
+ "u8",
4061
+ 32
4062
+ ]
4063
+ }
4064
+ },
4065
+ {
4066
+ name: "index",
4067
+ type: "u64"
4068
+ }
4069
+ ]
4070
+ }
4071
+ },
3289
4072
  {
3290
4073
  name: "RelayerAccount",
3291
4074
  docs: [
@@ -3480,6 +4263,86 @@ var veilix_devnet_default = {
3480
4263
  ]
3481
4264
  }
3482
4265
  },
4266
+ {
4267
+ name: "SwapConfig",
4268
+ docs: [
4269
+ 'Programs the swap escrow is allowed to call. PDA seeds: `["swap_config"]`.'
4270
+ ],
4271
+ type: {
4272
+ kind: "struct",
4273
+ fields: [
4274
+ {
4275
+ name: "allowed_programs",
4276
+ type: {
4277
+ vec: "pubkey"
4278
+ }
4279
+ }
4280
+ ]
4281
+ }
4282
+ },
4283
+ {
4284
+ name: "SwapParams",
4285
+ docs: [
4286
+ "Swap parameters. All of them are bound into the proof's `extDataHash`."
4287
+ ],
4288
+ type: {
4289
+ kind: "struct",
4290
+ fields: [
4291
+ {
4292
+ name: "amount_in",
4293
+ docs: [
4294
+ "Asset-A amount spent from the pool, fee included."
4295
+ ],
4296
+ type: "u64"
4297
+ },
4298
+ {
4299
+ name: "fee",
4300
+ docs: [
4301
+ "Asset-A fee: protocol wallets get their split of `amount_in`, the relayer the rest."
4302
+ ],
4303
+ type: "u64"
4304
+ },
4305
+ {
4306
+ name: "min_amount_out",
4307
+ docs: [
4308
+ "Minimum asset-B amount that must reach the treasury."
4309
+ ],
4310
+ type: "u64"
4311
+ },
4312
+ {
4313
+ name: "out_pubkey",
4314
+ docs: [
4315
+ "One-time shielded public key of the asset-B note (32-byte big-endian field element)."
4316
+ ],
4317
+ type: {
4318
+ array: [
4319
+ "u8",
4320
+ 32
4321
+ ]
4322
+ }
4323
+ },
4324
+ {
4325
+ name: "out_blinding",
4326
+ docs: [
4327
+ "Blinding of the asset-B note (32-byte big-endian field element)."
4328
+ ],
4329
+ type: {
4330
+ array: [
4331
+ "u8",
4332
+ 32
4333
+ ]
4334
+ }
4335
+ },
4336
+ {
4337
+ name: "encrypted_note",
4338
+ docs: [
4339
+ "Optional encrypted recovery data for the asset-B note."
4340
+ ],
4341
+ type: "bytes"
4342
+ }
4343
+ ]
4344
+ }
4345
+ },
3483
4346
  {
3484
4347
  name: "TransactionProof",
3485
4348
  docs: [
@@ -7378,7 +8241,7 @@ var MAINNET_TOKEN_MINTS = {
7378
8241
  USDC: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
7379
8242
  };
7380
8243
  var DEVNET_TOKEN_MINTS = {
7381
- Veilix: "GAFN64LvtCBoc5BHncVn3JEJGpq42rUzQjPmvMK2UhZH",
8244
+ Veilix: "Gmo636w21RBZX9ySVtPYcuYP6f1E5bdW5eBYhvK1bc8J",
7382
8245
  Bitcoin: "",
7383
8246
  Ethereum: "",
7384
8247
  USDC: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU"
@@ -7407,6 +8270,13 @@ var TOKEN_DECIMALS = {
7407
8270
  Bitcoin: 8,
7408
8271
  USDC: 6
7409
8272
  };
8273
+ var INDEXER_ASSET_LABELS = {
8274
+ Solana: "SOL",
8275
+ Veilix: "VEILIX",
8276
+ Bitcoin: "WBTC",
8277
+ Ethereum: "WETH",
8278
+ USDC: "USDC"
8279
+ };
7410
8280
  function getTokenDecimals(symbol) {
7411
8281
  return TOKEN_DECIMALS[symbol];
7412
8282
  }
@@ -7421,7 +8291,7 @@ function getDepositQueueForNetwork(network) {
7421
8291
  // package.json
7422
8292
  var package_default = {
7423
8293
  name: "veilix-sdk",
7424
- version: "0.2.2"};
8294
+ version: "0.3.0"};
7425
8295
 
7426
8296
  // src/circuits/constants.ts
7427
8297
  var PACKAGE_NAME = package_default.name;
@@ -7664,10 +8534,10 @@ var DEPOSIT_COMPUTE_UNIT_LIMIT = 35e4;
7664
8534
  function bytesToHex(bytes) {
7665
8535
  return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
7666
8536
  }
7667
- function hexToBytes(hex) {
7668
- const clean = hex.startsWith("0x") || hex.startsWith("0X") ? hex.slice(2) : hex;
8537
+ function hexToBytes(hex2) {
8538
+ const clean = hex2.startsWith("0x") || hex2.startsWith("0X") ? hex2.slice(2) : hex2;
7669
8539
  if (clean.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(clean)) {
7670
- throw new Error(`veilix-sdk: invalid hex string "${hex}"`);
8540
+ throw new Error(`veilix-sdk: invalid hex string "${hex2}"`);
7671
8541
  }
7672
8542
  const out = new Uint8Array(clean.length / 2);
7673
8543
  for (let i = 0; i < out.length; i++) {
@@ -7676,15 +8546,15 @@ function hexToBytes(hex) {
7676
8546
  return out;
7677
8547
  }
7678
8548
  function bigintToBytes32(value) {
7679
- const hex = BigInt(value).toString(16).padStart(64, "0");
7680
- if (hex.length > 64) {
8549
+ const hex2 = BigInt(value).toString(16).padStart(64, "0");
8550
+ if (hex2.length > 64) {
7681
8551
  throw new Error("veilix-sdk: value does not fit in 32 bytes");
7682
8552
  }
7683
- return hexToBytes(hex);
8553
+ return hexToBytes(hex2);
7684
8554
  }
7685
8555
  function bytesToBigint(bytes) {
7686
- const hex = bytesToHex(bytes);
7687
- return hex ? BigInt(`0x${hex}`) : 0n;
8556
+ const hex2 = bytesToHex(bytes);
8557
+ return hex2 ? BigInt(`0x${hex2}`) : 0n;
7688
8558
  }
7689
8559
  function toHex32(value) {
7690
8560
  return `0x${BigInt(value).toString(16).padStart(64, "0")}`;
@@ -7802,6 +8672,7 @@ var Utxo = class _Utxo {
7802
8672
  // src/core/note.ts
7803
8673
  var NOTE_PREFIX = "vx2";
7804
8674
  var ENCRYPTED_OUTPUT_VERSION = 1;
8675
+ var ENCRYPTED_SWAP_OUTPUT_VERSION = 2;
7805
8676
  var ENCRYPTED_OUTPUT_PLAINTEXT_BYTES = 1 + 8 + 32 + 32;
7806
8677
  var SECRETBOX_NONCE_BYTES = nacl__default.default.secretbox.nonceLength;
7807
8678
  function encodeNote(utxo) {
@@ -7834,14 +8705,14 @@ function decodeNote(note) {
7834
8705
  throw new Error("veilix-sdk: invalid note format");
7835
8706
  }
7836
8707
  const [, amountHex, privKeyHex, blindingHex, mint] = parts;
7837
- const hex = /^[0-9a-f]+$/i;
7838
- if (!hex.test(amountHex) || !hex.test(privKeyHex) || !hex.test(blindingHex)) {
8708
+ const hex2 = /^[0-9a-f]+$/i;
8709
+ if (!hex2.test(amountHex) || !hex2.test(privKeyHex) || !hex2.test(blindingHex)) {
7839
8710
  throw new Error("veilix-sdk: invalid note format");
7840
8711
  }
7841
- let mintKey = null;
8712
+ let mintKey2 = null;
7842
8713
  if (mint) {
7843
8714
  try {
7844
- mintKey = new web3_js.PublicKey(mint);
8715
+ mintKey2 = new web3_js.PublicKey(mint);
7845
8716
  } catch {
7846
8717
  throw new Error("veilix-sdk: invalid note mint");
7847
8718
  }
@@ -7850,7 +8721,7 @@ function decodeNote(note) {
7850
8721
  amount: BigInt(`0x${amountHex}`),
7851
8722
  keypair: VeilixKeypair.fromPrivateKey(BigInt(`0x${privKeyHex}`)),
7852
8723
  blinding: BigInt(`0x${blindingHex}`),
7853
- mint: mintKey
8724
+ mint: mintKey2
7854
8725
  });
7855
8726
  }
7856
8727
  function describeUtxo(utxo) {
@@ -7868,7 +8739,7 @@ function describeUtxo(utxo) {
7868
8739
  function parseSecretNote(note) {
7869
8740
  return describeUtxo(decodeNote(note));
7870
8741
  }
7871
- function encryptNoteOutput(key, utxo) {
8742
+ function encryptNoteOutput(key2, utxo) {
7872
8743
  const amount = new Uint8Array(8);
7873
8744
  new DataView(amount.buffer).setBigUint64(0, utxo.amount, true);
7874
8745
  const plaintext = concatBytes([
@@ -7878,21 +8749,38 @@ function encryptNoteOutput(key, utxo) {
7878
8749
  bigintToBytes32(utxo.blinding)
7879
8750
  ]);
7880
8751
  const nonce = nacl__default.default.randomBytes(SECRETBOX_NONCE_BYTES);
7881
- return concatBytes([nonce, nacl__default.default.secretbox(plaintext, nonce, key)]);
8752
+ return concatBytes([nonce, nacl__default.default.secretbox(plaintext, nonce, key2)]);
8753
+ }
8754
+ function encryptSwapNoteOutput(key2, keypair, blinding) {
8755
+ const plaintext = concatBytes([
8756
+ Uint8Array.of(ENCRYPTED_SWAP_OUTPUT_VERSION),
8757
+ new Uint8Array(8),
8758
+ bigintToBytes32(keypair.privKey),
8759
+ bigintToBytes32(blinding)
8760
+ ]);
8761
+ const nonce = nacl__default.default.randomBytes(SECRETBOX_NONCE_BYTES);
8762
+ return concatBytes([nonce, nacl__default.default.secretbox(plaintext, nonce, key2)]);
7882
8763
  }
7883
- function decryptNoteOutput(key, encryptedOutput, mint, index) {
8764
+ function decryptNoteOutput(key2, encryptedOutput, mint, index, onchainAmount = null) {
7884
8765
  if (encryptedOutput.length !== SECRETBOX_NONCE_BYTES + nacl__default.default.secretbox.overheadLength + ENCRYPTED_OUTPUT_PLAINTEXT_BYTES) {
7885
8766
  return null;
7886
8767
  }
7887
8768
  const opened = nacl__default.default.secretbox.open(
7888
8769
  encryptedOutput.subarray(SECRETBOX_NONCE_BYTES),
7889
8770
  encryptedOutput.subarray(0, SECRETBOX_NONCE_BYTES),
7890
- key
8771
+ key2
7891
8772
  );
7892
- if (!opened || opened[0] !== ENCRYPTED_OUTPUT_VERSION) {
8773
+ if (!opened) {
8774
+ return null;
8775
+ }
8776
+ let amount;
8777
+ if (opened[0] === ENCRYPTED_OUTPUT_VERSION) {
8778
+ amount = new DataView(opened.buffer, opened.byteOffset + 1, 8).getBigUint64(0, true);
8779
+ } else if (opened[0] === ENCRYPTED_SWAP_OUTPUT_VERSION && onchainAmount !== null) {
8780
+ amount = onchainAmount;
8781
+ } else {
7893
8782
  return null;
7894
8783
  }
7895
- const amount = new DataView(opened.buffer, opened.byteOffset + 1, 8).getBigUint64(0, true);
7896
8784
  return new Utxo({
7897
8785
  amount,
7898
8786
  keypair: VeilixKeypair.fromPrivateKey(bytesToBigint(opened.subarray(9, 41))),
@@ -16373,6 +17261,7 @@ async function proveTransaction({
16373
17261
  inputs = [],
16374
17262
  outputs = [],
16375
17263
  ext,
17264
+ extDataHashOverride,
16376
17265
  circuit
16377
17266
  }) {
16378
17267
  for (const utxo of [...inputs, ...outputs]) {
@@ -16422,7 +17311,7 @@ async function proveTransaction({
16422
17311
  const input = {
16423
17312
  root: proofRoot.toString(),
16424
17313
  publicAmount: publicAmount.toString(),
16425
- extDataHash: (await extDataHash(ext)).toString(),
17314
+ extDataHash: (extDataHashOverride ?? await extDataHash(ext)).toString(),
16426
17315
  mint: mintToField(ext.mint).toString(),
16427
17316
  inputNullifier: inputNullifiers.map(String),
16428
17317
  outputCommitment: outputCommitments.map(String),
@@ -16563,8 +17452,8 @@ function generateDepositParams(amount, mint = null) {
16563
17452
  if (value <= 0n) {
16564
17453
  throw new Error("veilix-sdk: deposit amount must be positive");
16565
17454
  }
16566
- const mintKey = mint && mint !== WRAPPED_SOL_MINT ? new web3_js.PublicKey(mint) : null;
16567
- const note = encodeNote(new Utxo({ amount: value, mint: mintKey }));
17455
+ const mintKey2 = mint && mint !== WRAPPED_SOL_MINT ? new web3_js.PublicKey(mint) : null;
17456
+ const note = encodeNote(new Utxo({ amount: value, mint: mintKey2 }));
16568
17457
  return { note, params: parseSecretNote(note) };
16569
17458
  }
16570
17459
  function to32ByteBuffer(value) {
@@ -16598,8 +17487,8 @@ function toPublicKey(value) {
16598
17487
  }
16599
17488
  function normalizeTreeMint(mint) {
16600
17489
  if (!mint) return null;
16601
- const key = toPublicKey(mint);
16602
- return key.equals(splToken.NATIVE_MINT) || key.equals(web3_js.PublicKey.default) ? null : key;
17490
+ const key2 = toPublicKey(mint);
17491
+ return key2.equals(splToken.NATIVE_MINT) || key2.equals(web3_js.PublicKey.default) ? null : key2;
16603
17492
  }
16604
17493
  function getTreePDA(mint) {
16605
17494
  const treeMint = normalizeTreeMint(mint);
@@ -16850,8 +17739,8 @@ async function resolveEncryptKey() {
16850
17739
  }
16851
17740
  async function buildBackupNotesInstruction(sender, notes) {
16852
17741
  const { program } = getConfig();
16853
- const key = await resolveEncryptKey();
16854
- return program.methods.backupNotes(notes.map((note) => encryptData(key, note))).accountsPartial({ user: sender }).instruction();
17742
+ const key2 = await resolveEncryptKey();
17743
+ return program.methods.backupNotes(notes.map((note) => encryptData(key2, note))).accountsPartial({ user: sender }).instruction();
16855
17744
  }
16856
17745
  async function isExtendBackupPdaNeeded(walletPubkey, newNotesLength) {
16857
17746
  const account = await fetchNotesAccount(walletPubkey);
@@ -16956,30 +17845,40 @@ async function getEncryptionKey(wallet) {
16956
17845
  }
16957
17846
  return nacl__default.default.hash(signature).slice(0, 32);
16958
17847
  }
16959
- function encryptData(key, plaintext) {
17848
+ function encryptData(key2, plaintext) {
16960
17849
  const nonce = nacl__default.default.randomBytes(24);
16961
- const box = nacl__default.default.secretbox(new TextEncoder().encode(plaintext), nonce, key);
17850
+ const box = nacl__default.default.secretbox(new TextEncoder().encode(plaintext), nonce, key2);
16962
17851
  const combined = new Uint8Array(nonce.length + box.length);
16963
17852
  combined.set(nonce);
16964
17853
  combined.set(box, nonce.length);
16965
17854
  return buffer.Buffer.from(combined);
16966
17855
  }
16967
- function decryptData(key, combined) {
16968
- const decrypted = nacl__default.default.secretbox.open(combined.slice(24), combined.slice(0, 24), key);
17856
+ function decryptData(key2, combined) {
17857
+ const decrypted = nacl__default.default.secretbox.open(combined.slice(24), combined.slice(0, 24), key2);
16969
17858
  if (!decrypted) throw new Error("Decryption failed");
16970
17859
  return new TextDecoder().decode(decrypted);
16971
17860
  }
16972
17861
 
16973
17862
  // src/tokenAssets.ts
16974
17863
  var WRAPPED_SOL_MINT2 = "So11111111111111111111111111111111111111112";
17864
+ var TOKEN_MINT_TABLES = [MAINNET_TOKEN_MINTS, DEVNET_TOKEN_MINTS];
17865
+ function indexerLabelForMint(mint) {
17866
+ if (mint === WRAPPED_SOL_MINT2) return INDEXER_ASSET_LABELS.Solana;
17867
+ for (const table of TOKEN_MINT_TABLES) {
17868
+ for (const symbol of Object.keys(table)) {
17869
+ if (table[symbol] && table[symbol] === mint) return INDEXER_ASSET_LABELS[symbol];
17870
+ }
17871
+ }
17872
+ return void 0;
17873
+ }
16975
17874
  function resolveIndexerAsset(indexerAsset) {
16976
- if (!indexerAsset) return "SOL";
17875
+ if (!indexerAsset) return INDEXER_ASSET_LABELS.Solana;
16977
17876
  if (typeof indexerAsset === "string") {
16978
- return indexerAsset === WRAPPED_SOL_MINT2 ? "SOL" : indexerAsset;
17877
+ return indexerLabelForMint(indexerAsset) ?? indexerAsset;
16979
17878
  }
16980
- if (indexerAsset.asset) return indexerAsset.asset;
16981
- if (indexerAsset.mint && indexerAsset.mint !== WRAPPED_SOL_MINT2) return indexerAsset.mint;
16982
- return "SOL";
17879
+ if (indexerAsset.asset) return indexerLabelForMint(indexerAsset.asset) ?? indexerAsset.asset;
17880
+ if (indexerAsset.mint) return indexerLabelForMint(indexerAsset.mint) ?? indexerAsset.mint;
17881
+ return INDEXER_ASSET_LABELS.Solana;
16983
17882
  }
16984
17883
  function indexerAssetForMint(mint) {
16985
17884
  return resolveIndexerAsset(mint ?? null);
@@ -16993,8 +17892,8 @@ var COMMITMENTS_PAGE_LIMIT = 8e3;
16993
17892
  var VALIDATE_NULLIFIERS_BATCH = 64;
16994
17893
  async function indexerGet(path, params) {
16995
17894
  const query = new URLSearchParams();
16996
- for (const [key, value] of Object.entries(params)) {
16997
- if (value !== void 0 && value !== "") query.set(key, value);
17895
+ for (const [key2, value] of Object.entries(params)) {
17896
+ if (value !== void 0 && value !== "") query.set(key2, value);
16998
17897
  }
16999
17898
  const qs = query.toString();
17000
17899
  return httpFetch(`${getIndexerUrl()}${path}${qs ? `?${qs}` : ""}`, {
@@ -17209,7 +18108,7 @@ async function scanOwnedNotes({
17209
18108
  mints,
17210
18109
  includeSpent = false
17211
18110
  } = {}) {
17212
- const key = requireEncryptKey();
18111
+ const key2 = requireEncryptKey();
17213
18112
  const explicit = mints !== void 0;
17214
18113
  const tokenMints = getTokenMintsForNetwork(getConfig().network);
17215
18114
  const targets = mints ?? [null, tokenMints.Veilix, tokenMints.Bitcoin, tokenMints.Ethereum, tokenMints.USDC].filter(
@@ -17227,7 +18126,13 @@ async function scanOwnedNotes({
17227
18126
  }
17228
18127
  for (const leaf of leaves) {
17229
18128
  if (!leaf.encryptedOutput || leaf.encryptedOutput.length <= 2) continue;
17230
- const utxo = decryptNoteOutput(key, hexToBytes(leaf.encryptedOutput), treeMint, leaf.index);
18129
+ const utxo = decryptNoteOutput(
18130
+ key2,
18131
+ hexToBytes(leaf.encryptedOutput),
18132
+ treeMint,
18133
+ leaf.index,
18134
+ leaf.amountRaw ? BigInt(leaf.amountRaw) : null
18135
+ );
17231
18136
  if (!utxo || utxo.amount === 0n) continue;
17232
18137
  if (toHex32(utxo.commitment()) !== toHex32(BigInt(leaf.commitment))) continue;
17233
18138
  found.push({ utxo, note: encodeNote(utxo), signature: null });
@@ -17507,6 +18412,364 @@ async function getQuote(params) {
17507
18412
  }
17508
18413
  return data;
17509
18414
  }
18415
+ var SWAP_DOMAIN = new TextEncoder().encode("veilix:swap:v1");
18416
+ async function swapExtDataHash(ext) {
18417
+ const hash = await sha256(
18418
+ concatBytes([
18419
+ SWAP_DOMAIN,
18420
+ (ext.mintIn ?? web3_js.PublicKey.default).toBytes(),
18421
+ (ext.mintOut ?? web3_js.PublicKey.default).toBytes(),
18422
+ ext.relayer.toBytes(),
18423
+ u64le(ext.amountIn),
18424
+ u64le(ext.fee),
18425
+ u64le(ext.minAmountOut),
18426
+ bigintToBytes32(ext.outPubkey),
18427
+ bigintToBytes32(ext.outBlinding),
18428
+ u32le(ext.encryptedOutput1.length),
18429
+ ext.encryptedOutput1,
18430
+ u32le(ext.encryptedOutput2.length),
18431
+ ext.encryptedOutput2,
18432
+ u32le(ext.encryptedNote.length),
18433
+ ext.encryptedNote
18434
+ ])
18435
+ );
18436
+ hash[0] = 0;
18437
+ return bytesToBigint(hash);
18438
+ }
18439
+ var CPMM_PROGRAM_IDS = {
18440
+ devnet: "DRaycpLY18LhpbydsBWbVJtxpNv9oXPgjRSfpF2bWpYb",
18441
+ mainnet: "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C"
18442
+ };
18443
+ var FEE_RATE_DENOMINATOR = 1000000n;
18444
+ var SWAP_DISABLED_BIT = 2;
18445
+ var key = (data, offset) => new web3_js.PublicKey(data.subarray(offset, offset + 32));
18446
+ var u64 = (data, offset) => new DataView(data.buffer, data.byteOffset + offset, 8).getBigUint64(0, true);
18447
+ var ceilDiv = (a, b) => (a + b - 1n) / b;
18448
+ var feeOf = (amount, rate) => ceilDiv(amount * rate, FEE_RATE_DENOMINATOR);
18449
+ async function quoteCpmm(connection, network, poolAddress, treeMintIn, treeMintOut, amountIn) {
18450
+ const programId = new web3_js.PublicKey(CPMM_PROGRAM_IDS[network]);
18451
+ const poolInfo = await connection.getAccountInfo(poolAddress, "confirmed");
18452
+ if (!poolInfo || !poolInfo.owner.equals(programId) || poolInfo.data.length < 381) {
18453
+ throw new Error("veilix-sdk: swap pool is not a Raydium CPMM pool");
18454
+ }
18455
+ const data = poolInfo.data;
18456
+ const pool = {
18457
+ ammConfig: key(data, 8),
18458
+ vault0: key(data, 72),
18459
+ vault1: key(data, 104),
18460
+ mint0: key(data, 168),
18461
+ mint1: key(data, 200),
18462
+ status: data[329],
18463
+ protocolFees: [u64(data, 341), u64(data, 349)],
18464
+ fundFees: [u64(data, 357), u64(data, 365)],
18465
+ creatorFeeOn: data.length >= 413 ? data[389] : 0,
18466
+ enableCreatorFee: data.length >= 413 ? data[390] === 1 : false,
18467
+ creatorFees: data.length >= 413 ? [u64(data, 397), u64(data, 405)] : [0n, 0n]
18468
+ };
18469
+ if (pool.status >> SWAP_DISABLED_BIT & 1) {
18470
+ throw new Error("veilix-sdk: swaps are disabled on this pool");
18471
+ }
18472
+ const mintIn = treeMintIn ?? splToken.NATIVE_MINT;
18473
+ const mintOut = treeMintOut ?? splToken.NATIVE_MINT;
18474
+ let zeroForOne;
18475
+ if (pool.mint0.equals(mintIn) && pool.mint1.equals(mintOut)) zeroForOne = true;
18476
+ else if (pool.mint1.equals(mintIn) && pool.mint0.equals(mintOut)) zeroForOne = false;
18477
+ else throw new Error("veilix-sdk: swap pool does not trade this pair");
18478
+ const [i, o] = zeroForOne ? [0, 1] : [1, 0];
18479
+ const [configInfo, vaultIn, vaultOut] = await connection.getMultipleAccountsInfo(
18480
+ [pool.ammConfig, zeroForOne ? pool.vault0 : pool.vault1, zeroForOne ? pool.vault1 : pool.vault0],
18481
+ "confirmed"
18482
+ );
18483
+ if (!configInfo || !vaultIn || !vaultOut) {
18484
+ throw new Error("veilix-sdk: swap pool accounts are missing");
18485
+ }
18486
+ const tradeFeeRate = u64(configInfo.data, 12);
18487
+ const creatorFeeRate = pool.enableCreatorFee && configInfo.data.length >= 116 ? u64(configInfo.data, 108) : 0n;
18488
+ const reserveIn = u64(vaultIn.data, 64) - pool.protocolFees[i] - pool.fundFees[i] - pool.creatorFees[i];
18489
+ const reserveOut = u64(vaultOut.data, 64) - pool.protocolFees[o] - pool.fundFees[o] - pool.creatorFees[o];
18490
+ if (reserveIn <= 0n || reserveOut <= 0n) {
18491
+ throw new Error("veilix-sdk: swap pool has no liquidity");
18492
+ }
18493
+ const creatorOnInput = pool.creatorFeeOn === 0 || pool.creatorFeeOn === 1 && zeroForOne || pool.creatorFeeOn === 2 && !zeroForOne;
18494
+ let inLessFees = amountIn - feeOf(amountIn, tradeFeeRate);
18495
+ if (creatorOnInput) inLessFees -= feeOf(amountIn, creatorFeeRate);
18496
+ let amountOut = inLessFees * reserveOut / (reserveIn + inLessFees);
18497
+ if (!creatorOnInput) amountOut -= feeOf(amountOut, creatorFeeRate);
18498
+ if (amountOut <= 0n) {
18499
+ throw new Error("veilix-sdk: swap amount is too small for this pool");
18500
+ }
18501
+ const spotOut = Number(inLessFees) * (Number(reserveOut) / Number(reserveIn));
18502
+ const priceImpact = spotOut > 0 ? Math.max(0, 1 - Number(amountOut) / spotOut) : 1;
18503
+ return { amountOut, priceImpact };
18504
+ }
18505
+
18506
+ // src/swap/execute.ts
18507
+ var SWAP_MAX_WAIT_MS = 18e4;
18508
+ var DEFAULT_SLIPPAGE_BPS = 100;
18509
+ var MAX_SLIPPAGE_BPS = 5e3;
18510
+ var MAX_PRICE_IMPACT = 0.1;
18511
+ var hex = (bytes) => `0x${bytesToHex(bytes)}`;
18512
+ var mintKey = (mint) => mint?.toBase58() ?? null;
18513
+ async function fetchRelayerQuote(relayerUrl, mintIn, mintOut, amountIn) {
18514
+ const params = new URLSearchParams({ amountIn: amountIn.toString() });
18515
+ if (mintIn) params.set("mintIn", mintIn.toBase58());
18516
+ if (mintOut) params.set("mintOut", mintOut.toBase58());
18517
+ const base = relayerUrl.replace(/\/$/, "");
18518
+ const res = await httpFetch(`${base}/v1/swapQuote?${params}`, {
18519
+ headers: { Accept: "application/json" }
18520
+ });
18521
+ const body = await res.json().catch(() => ({}));
18522
+ if (!res.ok) {
18523
+ throw new Error(body.error || `Swap quote failed (${res.status})`);
18524
+ }
18525
+ return { ...body, relayerUrl: base };
18526
+ }
18527
+ function swapCandidates(relayers, relayerUrl) {
18528
+ if (relayerUrl) {
18529
+ const wanted = relayerUrl.replace(/\/$/, "");
18530
+ const match = relayers.find((r) => r.url.replace(/\/$/, "") === wanted);
18531
+ if (!match) throw new Error(`veilix-sdk: relayer ${relayerUrl} is not available`);
18532
+ return [match];
18533
+ }
18534
+ if (!relayers.length) throw new Error("veilix-sdk: no relayer available");
18535
+ const first = getRandomRelayer(relayers);
18536
+ return [first, ...relayers.filter((r) => r !== first)];
18537
+ }
18538
+ async function getSwapQuote(params) {
18539
+ const { relayers } = getConfig();
18540
+ const mintIn = normalizeTreeMint(params.mintIn);
18541
+ const mintOut = normalizeTreeMint(params.mintOut);
18542
+ if (mintKey(mintIn) === mintKey(mintOut)) {
18543
+ throw new Error("veilix-sdk: swap needs two different assets");
18544
+ }
18545
+ const amountIn = BigInt(params.amountIn);
18546
+ if (amountIn <= 0n) throw new Error("veilix-sdk: swap amount must be positive");
18547
+ const { connection, network } = getConfig();
18548
+ const platformWallets = await fetchPlatformFeeWallets();
18549
+ let lastError = null;
18550
+ for (const relayer of swapCandidates(relayers, params.relayerUrl)) {
18551
+ try {
18552
+ const quote = await fetchRelayerQuote(relayer.url, mintIn, mintOut, amountIn);
18553
+ if (quote.relayer !== relayer.value) {
18554
+ throw new Error("Relayer quoted for a different reward account");
18555
+ }
18556
+ const { fee } = computeWithdrawFee(amountIn, relayer.fee, platformWallets);
18557
+ if (fee >= amountIn) throw new Error("Amount is too small to cover the fees");
18558
+ if (BigInt(quote.fee) !== fee) throw new Error("Relayer quoted a different fee");
18559
+ if (quote.dexProgram !== CPMM_PROGRAM_IDS[network]) {
18560
+ throw new Error("Relayer routes through an unsupported DEX");
18561
+ }
18562
+ const own = await quoteCpmm(
18563
+ connection,
18564
+ network,
18565
+ new web3_js.PublicKey(quote.pool),
18566
+ mintIn,
18567
+ mintOut,
18568
+ amountIn - fee
18569
+ );
18570
+ if (own.priceImpact > MAX_PRICE_IMPACT) {
18571
+ throw new Error(
18572
+ `Price impact ${(own.priceImpact * 100).toFixed(1)}% is too high for this pool; swap less`
18573
+ );
18574
+ }
18575
+ return {
18576
+ quote: {
18577
+ ...quote,
18578
+ swapIn: (amountIn - fee).toString(),
18579
+ amountOut: own.amountOut.toString(),
18580
+ priceImpact: own.priceImpact
18581
+ },
18582
+ relayer
18583
+ };
18584
+ } catch (error) {
18585
+ lastError = error;
18586
+ }
18587
+ }
18588
+ const reason = lastError instanceof Error ? lastError.message : "no relayer routes this pair";
18589
+ throw new Error(`veilix-sdk: no swap route for this pair (${reason})`);
18590
+ }
18591
+ async function buildSwapPayload(params, options = {}) {
18592
+ const { encryptKey } = getConfig();
18593
+ const utxo = decodeNote(params.note);
18594
+ const mintIn = utxo.mint;
18595
+ const mintOut = normalizeTreeMint(params.mintOut ?? null);
18596
+ const slippageBps = params.slippageBps ?? DEFAULT_SLIPPAGE_BPS;
18597
+ if (!Number.isInteger(slippageBps) || slippageBps < 0 || slippageBps > MAX_SLIPPAGE_BPS) {
18598
+ throw new Error(`veilix-sdk: slippageBps must be an integer between 0 and ${MAX_SLIPPAGE_BPS}`);
18599
+ }
18600
+ const { index } = await locateNote(utxo);
18601
+ if (index === null) {
18602
+ throw new Error("Note is not in the Veilix pool yet (deposit not confirmed or not indexed)");
18603
+ }
18604
+ utxo.index = index;
18605
+ if ((await validateNullifier(toHex32(utxo.nullifier()))).exists) {
18606
+ throw new Error("This note has already been spent");
18607
+ }
18608
+ const amountIn = params.amount === void 0 ? utxo.amount : BigInt(params.amount);
18609
+ if (amountIn <= 0n || amountIn > utxo.amount) {
18610
+ throw new Error(`Swap amount must be between 1 and ${utxo.amount}`);
18611
+ }
18612
+ const { quote, relayer } = await getSwapQuote({
18613
+ mintIn,
18614
+ mintOut,
18615
+ amountIn,
18616
+ relayerUrl: params.relayerUrl
18617
+ });
18618
+ const fee = BigInt(quote.fee);
18619
+ const minAmountOut = BigInt(quote.amountOut) * BigInt(1e4 - slippageBps) / 10000n;
18620
+ if (minAmountOut <= 0n) {
18621
+ throw new Error("Swap amount is too small for this pool");
18622
+ }
18623
+ let tree = options.tree;
18624
+ if (!tree || tree.elements.length <= index) {
18625
+ tree = await fetchAssetTree(mintKey(mintIn));
18626
+ }
18627
+ if (tree.elements.length <= index) {
18628
+ throw new Error("The indexer has not synced this note yet, retry shortly");
18629
+ }
18630
+ const change = utxo.amount - amountIn;
18631
+ const changeUtxo = change > 0n ? new Utxo({ amount: change, mint: mintIn }) : null;
18632
+ const encryptedOutput1 = changeUtxo && encryptKey ? encryptNoteOutput(encryptKey, changeUtxo) : new Uint8Array();
18633
+ const encryptedOutput2 = new Uint8Array();
18634
+ const outKeypair = VeilixKeypair.random();
18635
+ const outBlinding = randomFieldElement();
18636
+ const encryptedNote = encryptKey ? encryptSwapNoteOutput(encryptKey, outKeypair, outBlinding) : new Uint8Array();
18637
+ const relayerKey = new web3_js.PublicKey(relayer.value);
18638
+ const hash = await swapExtDataHash({
18639
+ mintIn,
18640
+ mintOut,
18641
+ relayer: relayerKey,
18642
+ amountIn,
18643
+ fee,
18644
+ minAmountOut,
18645
+ outPubkey: outKeypair.pubKey,
18646
+ outBlinding,
18647
+ encryptedOutput1,
18648
+ encryptedOutput2,
18649
+ encryptedNote
18650
+ });
18651
+ const proved = await withCircuitArtifacts(
18652
+ options.circuitArtifacts,
18653
+ (artifacts) => proveTransaction({
18654
+ tree,
18655
+ inputs: [utxo],
18656
+ outputs: changeUtxo ? [changeUtxo] : [],
18657
+ ext: {
18658
+ mint: mintIn,
18659
+ recipient: web3_js.PublicKey.default,
18660
+ relayer: relayerKey,
18661
+ extAmount: -amountIn,
18662
+ fee,
18663
+ encryptedOutput1,
18664
+ encryptedOutput2
18665
+ },
18666
+ extDataHashOverride: hash,
18667
+ circuit: artifacts
18668
+ })
18669
+ );
18670
+ const { proof } = proved;
18671
+ const payload = {
18672
+ proof: hex(proof.proof),
18673
+ root: hex(proof.root),
18674
+ inputNullifiers: [hex(proof.inputNullifiers[0]), hex(proof.inputNullifiers[1])],
18675
+ outputCommitments: [hex(proof.outputCommitments[0]), hex(proof.outputCommitments[1])],
18676
+ ...mintIn ? { mintIn: mintIn.toBase58() } : {},
18677
+ ...mintOut ? { mintOut: mintOut.toBase58() } : {},
18678
+ amountIn: amountIn.toString(),
18679
+ fee: fee.toString(),
18680
+ minAmountOut: minAmountOut.toString(),
18681
+ outPubkey: hex(bigintToBytes32(outKeypair.pubKey)),
18682
+ outBlinding: hex(bigintToBytes32(outBlinding)),
18683
+ relayer: relayerKey.toBase58(),
18684
+ encryptedOutput1: hex(encryptedOutput1),
18685
+ encryptedOutput2: hex(encryptedOutput2),
18686
+ encryptedNote: hex(encryptedNote)
18687
+ };
18688
+ return {
18689
+ payload,
18690
+ relayerUrl: quote.relayerUrl,
18691
+ quote,
18692
+ amountIn,
18693
+ fee,
18694
+ minAmountOut,
18695
+ changeNote: changeUtxo ? encodeNote(changeUtxo) : null,
18696
+ output: {
18697
+ mint: mintKey(mintOut),
18698
+ privKey: outKeypair.privKey.toString(),
18699
+ blinding: outBlinding.toString()
18700
+ },
18701
+ nullifiers: [...payload.inputNullifiers]
18702
+ };
18703
+ }
18704
+ async function pollSwapJob(relayerUrl, jobId, maxWaitMs) {
18705
+ const start = Date.now();
18706
+ while (Date.now() - start < maxWaitMs) {
18707
+ const res = await httpFetch(`${relayerUrl}/v1/jobs/${encodeURIComponent(jobId)}`, {
18708
+ headers: { Accept: "application/json" }
18709
+ });
18710
+ const job = await res.json().catch(() => ({}));
18711
+ if (!res.ok) throw new Error(job.error || "Failed to poll relayer job");
18712
+ if (job.status === "CONFIRMED" || job.status === "FAILED") return job;
18713
+ await new Promise((resolve) => setTimeout(resolve, 3e3));
18714
+ }
18715
+ throw new Error("Swap timed out");
18716
+ }
18717
+ function swapOutputNote(output, result) {
18718
+ const utxo = new Utxo({
18719
+ amount: BigInt(result.amountOut),
18720
+ keypair: VeilixKeypair.fromPrivateKey(output.privKey),
18721
+ blinding: BigInt(output.blinding),
18722
+ mint: output.mint ? new web3_js.PublicKey(output.mint) : null,
18723
+ index: result.outputIndex
18724
+ });
18725
+ if (toHex32(utxo.commitment()) !== toHex32(BigInt(result.outputCommitment))) {
18726
+ throw new Error("veilix-sdk: swapped note does not match the on-chain commitment");
18727
+ }
18728
+ return encodeNote(utxo);
18729
+ }
18730
+ async function submitSwapPayload(bundle) {
18731
+ const res = await httpFetch(`${bundle.relayerUrl}/v1/veilixSwap`, {
18732
+ method: "POST",
18733
+ headers: { "Content-Type": "application/json" },
18734
+ body: JSON.stringify(bundle.payload)
18735
+ });
18736
+ const body = await res.json().catch(() => ({}));
18737
+ if (!res.ok || !body.id) {
18738
+ throw new Error(body.error || "Swap submission failed");
18739
+ }
18740
+ const job = await pollSwapJob(bundle.relayerUrl, body.id, SWAP_MAX_WAIT_MS);
18741
+ const base = {
18742
+ changeNote: bundle.changeNote,
18743
+ amountIn: bundle.amountIn.toString(),
18744
+ fee: bundle.fee.toString(),
18745
+ minAmountOut: bundle.minAmountOut.toString()
18746
+ };
18747
+ if (job.status === "FAILED") {
18748
+ return {
18749
+ ...base,
18750
+ txHash: job.txHash ?? "",
18751
+ status: "failed",
18752
+ error: job.failedReason || "Swap failed",
18753
+ // A failed swap spends nothing: the original note is still valid.
18754
+ outputNote: null,
18755
+ changeNote: null,
18756
+ amountOut: null
18757
+ };
18758
+ }
18759
+ if (!job.txHash || !job.swapResult) {
18760
+ throw new Error("Swap confirmed but the relayer did not report the swapped note");
18761
+ }
18762
+ return {
18763
+ ...base,
18764
+ txHash: job.txHash,
18765
+ status: "success",
18766
+ outputNote: swapOutputNote(bundle.output, job.swapResult),
18767
+ amountOut: job.swapResult.amountOut
18768
+ };
18769
+ }
18770
+ async function executeSwap(params) {
18771
+ return submitSwapPayload(await buildSwapPayload(params));
18772
+ }
17510
18773
 
17511
18774
  // src/withdraw/assets.ts
17512
18775
  var TOKEN_UNITS = {
@@ -17947,6 +19210,26 @@ var VeilixSDK = class _VeilixSDK {
17947
19210
  submitWithdrawPayload(bundle) {
17948
19211
  return this.runAsync(() => submitWithdrawPayload(bundle));
17949
19212
  }
19213
+ // ── Private swap ─────────────────────────────────────────────────────
19214
+ /** Fee and expected output of swapping `amountIn` of `mintIn` into `mintOut`. */
19215
+ getSwapQuote(params) {
19216
+ return this.runAsync(() => getSwapQuote(params));
19217
+ }
19218
+ /**
19219
+ * Swap a note of asset A into a new shielded note of asset B (`mintOut`, `null` for
19220
+ * SOL) through a relayer and an allowlisted DEX. Funds never leave the pool
19221
+ * unshielded. Returns the asset-B note and any asset-A change note.
19222
+ */
19223
+ swap(params) {
19224
+ return this.runAsync(() => executeSwap(params));
19225
+ }
19226
+ /** Prove a swap without submitting it (see {@link submitSwapPayload}). */
19227
+ buildSwapPayload(params, options) {
19228
+ return this.runAsync(() => buildSwapPayload(params, options));
19229
+ }
19230
+ submitSwapPayload(bundle) {
19231
+ return this.runAsync(() => submitSwapPayload(bundle));
19232
+ }
17950
19233
  /**
17951
19234
  * Private transfer: deposit one note per item, then withdraw each note in full
17952
19235
  * to its recipient through the indexer submission queue.
@@ -18058,15 +19341,15 @@ var VeilixSDK = class _VeilixSDK {
18058
19341
  * Accepts a frontend wallet adapter (`signMessage`) or a backend {@link Keypair}.
18059
19342
  */
18060
19343
  async getEncryptionKey(wallet) {
18061
- const key = await getEncryptionKey(wallet);
18062
- this.config.encryptKey = key;
18063
- return key;
19344
+ const key2 = await getEncryptionKey(wallet);
19345
+ this.config.encryptKey = key2;
19346
+ return key2;
18064
19347
  }
18065
- encryptData(key, plaintext) {
18066
- return encryptData(key, plaintext);
19348
+ encryptData(key2, plaintext) {
19349
+ return encryptData(key2, plaintext);
18067
19350
  }
18068
- decryptData(key, combined) {
18069
- return decryptData(key, combined);
19351
+ decryptData(key2, combined) {
19352
+ return decryptData(key2, combined);
18070
19353
  }
18071
19354
  // ── Utilities ────────────────────────────────────────────────────────
18072
19355
  parseAmountToBaseUnits(amount, decimals) {