mirror of
https://github.com/logos-blockchain/lez-programs.git
synced 2026-07-25 00:03:11 +00:00
feat(amm): metal-safe amm_client_ffi crate + root flake for on-chain swap calls
This commit is contained in:
parent
cca063ce2d
commit
3b9ca241c2
189
Cargo.lock
generated
189
Cargo.lock
generated
@ -76,13 +76,27 @@ dependencies = [
|
||||
"risc0-zkvm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "amm_client_ffi"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"amm_core",
|
||||
"borsh",
|
||||
"cbindgen",
|
||||
"lee_core 0.1.0 (git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0-rc6)",
|
||||
"risc0-binfmt",
|
||||
"risc0-zkvm",
|
||||
"ruint",
|
||||
"twap_oracle_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "amm_core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"borsh",
|
||||
"lee_core",
|
||||
"lee_core 0.1.0 (git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0)",
|
||||
"risc0-zkvm",
|
||||
"ruint",
|
||||
"serde",
|
||||
@ -96,7 +110,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"amm_core",
|
||||
"clock_core",
|
||||
"lee_core",
|
||||
"lee_core 0.1.0 (git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0)",
|
||||
"token_core",
|
||||
"twap_oracle_core",
|
||||
]
|
||||
@ -110,6 +124,56 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell_polyfill",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.103"
|
||||
@ -480,7 +544,7 @@ name = "ata_core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"borsh",
|
||||
"lee_core",
|
||||
"lee_core 0.1.0 (git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0)",
|
||||
"risc0-zkvm",
|
||||
"serde",
|
||||
]
|
||||
@ -490,7 +554,7 @@ name = "ata_program"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ata_core",
|
||||
"lee_core",
|
||||
"lee_core 0.1.0 (git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0)",
|
||||
"token_core",
|
||||
]
|
||||
|
||||
@ -802,6 +866,25 @@ dependencies = [
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cbindgen"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fce8dd7fcfcbf3a0a87d8f515194b49d6135acab73e18bd380d1d93bb1a15eb"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"heck 0.4.1",
|
||||
"indexmap 2.14.0",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn 2.0.118",
|
||||
"tempfile",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.65"
|
||||
@ -858,13 +941,40 @@ dependencies = [
|
||||
"inout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
||||
|
||||
[[package]]
|
||||
name = "clock_core"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0#a58fbce2ff48c58b7bb5001b1a27e64b9596ee3a"
|
||||
dependencies = [
|
||||
"borsh",
|
||||
"lee_core",
|
||||
"lee_core 0.1.0 (git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -882,6 +992,12 @@ dependencies = [
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
|
||||
|
||||
[[package]]
|
||||
name = "const-hex"
|
||||
version = "1.19.1"
|
||||
@ -1274,7 +1390,7 @@ version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e92f10a49176cbffacaedabfaa11d51db1ea0f80a83c26e1873b43cd1742c24"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"proc-macro2-diagnostics",
|
||||
]
|
||||
@ -1684,6 +1800,12 @@ dependencies = [
|
||||
"hashbrown 0.15.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
@ -2053,7 +2175,7 @@ dependencies = [
|
||||
"ata_core",
|
||||
"clock_core",
|
||||
"lee",
|
||||
"lee_core",
|
||||
"lee_core 0.1.0 (git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0)",
|
||||
"stablecoin-methods",
|
||||
"stablecoin_core",
|
||||
"token-methods",
|
||||
@ -2068,6 +2190,12 @@ version = "2.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
@ -2223,7 +2351,7 @@ dependencies = [
|
||||
"build_utils",
|
||||
"hex",
|
||||
"k256",
|
||||
"lee_core",
|
||||
"lee_core 0.1.0 (git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0)",
|
||||
"log",
|
||||
"rand 0.8.6",
|
||||
"risc0-binfmt",
|
||||
@ -2251,6 +2379,23 @@ dependencies = [
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lee_core"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0-rc6#e37876a64028a335eb693198a1ed6a0e875ec5b4"
|
||||
dependencies = [
|
||||
"base58",
|
||||
"borsh",
|
||||
"bytemuck",
|
||||
"bytesize",
|
||||
"chacha20",
|
||||
"ml-kem",
|
||||
"risc0-zkvm",
|
||||
"serde",
|
||||
"serde_with",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.186"
|
||||
@ -2489,6 +2634,12 @@ version = "1.21.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
version = "0.2.0"
|
||||
@ -3696,7 +3847,7 @@ source = "git+https://github.com/logos-co/spel.git?tag=v0.6.0#0cb7e0980535af6194
|
||||
dependencies = [
|
||||
"base58",
|
||||
"borsh",
|
||||
"lee_core",
|
||||
"lee_core 0.1.0 (git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0)",
|
||||
"proc-macro2",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -3776,7 +3927,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"borsh",
|
||||
"lee_core",
|
||||
"lee_core 0.1.0 (git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0)",
|
||||
"risc0-zkvm",
|
||||
"ruint",
|
||||
"serde",
|
||||
@ -3788,7 +3939,7 @@ dependencies = [
|
||||
name = "stablecoin_program"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"lee_core",
|
||||
"lee_core 0.1.0 (git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0)",
|
||||
"stablecoin_core",
|
||||
"token_core",
|
||||
]
|
||||
@ -3820,7 +3971,7 @@ version = "0.27.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.118",
|
||||
@ -4002,7 +4153,7 @@ name = "token_core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"borsh",
|
||||
"lee_core",
|
||||
"lee_core 0.1.0 (git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0)",
|
||||
"serde",
|
||||
"spel-framework-macros",
|
||||
]
|
||||
@ -4011,7 +4162,7 @@ dependencies = [
|
||||
name = "token_program"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"lee_core",
|
||||
"lee_core 0.1.0 (git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0)",
|
||||
"token_core",
|
||||
]
|
||||
|
||||
@ -4231,7 +4382,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"alloy-primitives",
|
||||
"borsh",
|
||||
"lee_core",
|
||||
"lee_core 0.1.0 (git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0)",
|
||||
"risc0-zkvm",
|
||||
"ruint",
|
||||
"serde",
|
||||
@ -4244,7 +4395,7 @@ name = "twap_oracle_program"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clock_core",
|
||||
"lee_core",
|
||||
"lee_core 0.1.0 (git+https://github.com/logos-blockchain/logos-execution-zone.git?tag=v0.2.0)",
|
||||
"twap_oracle_core",
|
||||
]
|
||||
|
||||
@ -4331,6 +4482,12 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.1"
|
||||
|
||||
@ -6,6 +6,7 @@ members = [
|
||||
"programs/amm/core",
|
||||
"programs/amm",
|
||||
"programs/amm/methods",
|
||||
"programs/amm/client-ffi",
|
||||
"programs/ata/core",
|
||||
"programs/ata",
|
||||
"programs/ata/methods",
|
||||
|
||||
98
flake.lock
generated
Normal file
98
flake.lock
generated
Normal file
@ -0,0 +1,98 @@
|
||||
{
|
||||
"nodes": {
|
||||
"crane": {
|
||||
"locked": {
|
||||
"lastModified": 1783203018,
|
||||
"narHash": "sha256-G6R9IT/xwFuu+CYBWDUAok6AdC4ERC4ZfPPFtEpxnZE=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "80db5bdc391be8a1794f6d8a2d56e3a84ebcede2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1783776592,
|
||||
"narHash": "sha256-UgCQzxeWI75XM8G+hPrPh+MKzEPjG3SpAj7dtqSbksA=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e7a3ca8092b61ff85b6a45bf863ea2b2d6a661b3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"crane": "crane",
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1783921439,
|
||||
"narHash": "sha256-DsSIQSRMrLOz40LrGZ03sp2RlJ9sz3wKpd8XPTOzXnw=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "e013376c32a8fcf07ddb6ec71739552bc118b7bd",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
72
flake.nix
Normal file
72
flake.nix
Normal file
@ -0,0 +1,72 @@
|
||||
{
|
||||
description = "LEZ programs — AMM client FFI";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
crane.url = "github:ipetkov/crane";
|
||||
rust-overlay = {
|
||||
url = "github:oxalica/rust-overlay";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs =
|
||||
{ self, nixpkgs, flake-utils, crane, rust-overlay }:
|
||||
flake-utils.lib.eachDefaultSystem (
|
||||
system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [ rust-overlay.overlays.default ];
|
||||
};
|
||||
# Honor the repo's pinned toolchain (rust-toolchain.toml -> 1.94.0).
|
||||
rustToolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
|
||||
craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchain;
|
||||
|
||||
# Whole workspace: crane needs Cargo.lock + all path deps (amm_core,
|
||||
# twap_oracle_core, token_core, ...) to resolve `-p amm_client_ffi`.
|
||||
src = ./.;
|
||||
|
||||
commonArgs = {
|
||||
inherit src;
|
||||
strictDeps = true;
|
||||
pname = "amm_client_ffi";
|
||||
version = "0.1.0";
|
||||
# CRITICAL: scope to ONLY this crate. The workspace also contains
|
||||
# `amm/methods` etc. whose build.rs compiles the risc0 guest (which
|
||||
# WOULD invoke Metal on darwin). `-p amm_client_ffi` never builds
|
||||
# those crates or their build scripts.
|
||||
cargoExtraArgs = "-p amm_client_ffi";
|
||||
doCheck = false;
|
||||
# NOTE: cbindgen is used here as a Cargo *build-dependency*
|
||||
# (invoked from build.rs via its Rust library API), not as the
|
||||
# standalone CLI package — so no nativeBuildInputs entry is
|
||||
# needed; crane builds it as part of the normal cargo graph.
|
||||
};
|
||||
|
||||
cargoArtifacts = craneLib.buildDepsOnly commonArgs;
|
||||
|
||||
ammClientFfi = craneLib.buildPackage (
|
||||
commonArgs
|
||||
// {
|
||||
inherit cargoArtifacts;
|
||||
postInstall =
|
||||
''
|
||||
mkdir -p $out/include
|
||||
cp programs/amm/client-ffi/amm_client_ffi.h $out/include/
|
||||
''
|
||||
+ pkgs.lib.optionalString pkgs.stdenv.isDarwin ''
|
||||
if [ -f $out/lib/libamm_client_ffi.dylib ]; then
|
||||
install_name_tool -id @rpath/libamm_client_ffi.dylib $out/lib/libamm_client_ffi.dylib
|
||||
fi
|
||||
'';
|
||||
}
|
||||
);
|
||||
in
|
||||
{
|
||||
packages.default = ammClientFfi;
|
||||
packages.amm_client_ffi = ammClientFfi;
|
||||
}
|
||||
);
|
||||
}
|
||||
25
programs/amm/client-ffi/Cargo.toml
Normal file
25
programs/amm/client-ffi/Cargo.toml
Normal file
@ -0,0 +1,25 @@
|
||||
[package]
|
||||
name = "amm_client_ffi"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "amm_client_ffi"
|
||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
amm_core = { path = "../core" }
|
||||
twap_oracle_core = { path = "../../twap_oracle/core" }
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc6", features = ["host"], package = "lee_core" }
|
||||
borsh = { version = "1.5", features = ["derive"] }
|
||||
risc0-zkvm = { version = "=3.0.5", default-features = false }
|
||||
risc0-binfmt = { version = "=3.0.4", default-features = false }
|
||||
# amm_core's ruint is default-features=false (for the no_std guest); enable std
|
||||
# here (host-only) so its Uint::root compiles. Guest build is unaffected.
|
||||
ruint = { version = "=1.17.0", default-features = false, features = ["std"] }
|
||||
|
||||
[build-dependencies]
|
||||
cbindgen = "0.27"
|
||||
135
programs/amm/client-ffi/amm_client_ffi.h
Normal file
135
programs/amm/client-ffi/amm_client_ffi.h
Normal file
@ -0,0 +1,135 @@
|
||||
#ifndef AMM_CLIENT_FFI_H
|
||||
#define AMM_CLIENT_FFI_H
|
||||
|
||||
#pragma once
|
||||
|
||||
/* Generated by cbindgen. Do not edit. */
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* Heap-allocated buffer of RISC0 instruction words, returned across the C
|
||||
* boundary. Free with `amm_client_free_words`.
|
||||
*/
|
||||
typedef struct AmmWords {
|
||||
uint32_t *ptr;
|
||||
uintptr_t len;
|
||||
bool ok;
|
||||
} AmmWords;
|
||||
|
||||
/**
|
||||
* C-ABI representation of `nssa_core::program::ProgramId` (an Image ID),
|
||||
* which is itself defined as `[u32; 8]`. Declared as a concrete array here
|
||||
* (rather than an alias through `nssa_core::program::ProgramId`) so
|
||||
* cbindgen — which only inspects this crate's source, not its
|
||||
* dependencies' — can emit a real typedef instead of an opaque,
|
||||
* self-referential `ProgramId` in the generated header. Since both are
|
||||
* plain type aliases to `[u32; 8]`, they remain interchangeable to rustc.
|
||||
*/
|
||||
typedef uint32_t ProgramId[8];
|
||||
|
||||
/**
|
||||
* C-ABI mirror of `pool::PoolView`. u128 fields are little-endian bytes.
|
||||
*/
|
||||
typedef struct FfiPoolView {
|
||||
uint8_t def_a[32];
|
||||
uint8_t def_b[32];
|
||||
uint8_t vault_a[32];
|
||||
uint8_t vault_b[32];
|
||||
uint8_t reserve_a[16];
|
||||
uint8_t reserve_b[16];
|
||||
uint8_t liquidity_supply[16];
|
||||
uint32_t fees;
|
||||
bool ok;
|
||||
} FfiPoolView;
|
||||
|
||||
/**
|
||||
* Builds the RISC0 instruction words for a `SwapExactInput`. `amount_in` and
|
||||
* `min_out` are little-endian encoded `u128` values (`[u8; 16]`). The
|
||||
* returned buffer must be freed with `amm_client_free_words`.
|
||||
*
|
||||
* # Safety
|
||||
* `amount_in` and `min_out` must be valid, non-null pointers to readable
|
||||
* memory of the indicated sizes.
|
||||
*/
|
||||
struct AmmWords amm_client_swap_words(const uint8_t (*amount_in)[16],
|
||||
const uint8_t (*min_out)[16],
|
||||
uint64_t deadline);
|
||||
|
||||
/**
|
||||
* Frees a buffer previously returned by `amm_client_swap_words`.
|
||||
*
|
||||
* # Safety
|
||||
* `w` must be a value previously returned by `amm_client_swap_words` that
|
||||
* has not already been freed.
|
||||
*/
|
||||
void amm_client_free_words(struct AmmWords w);
|
||||
|
||||
/**
|
||||
* Computes the `ProgramId` (Image ID) of a compiled guest ELF. Returns
|
||||
* `false` on an invalid ELF, leaving `out` unwritten.
|
||||
*
|
||||
* # Safety
|
||||
* `elf` must be valid for reads of `elf_len` bytes, and `out` must be a
|
||||
* valid, non-null pointer to writable memory for a `ProgramId`.
|
||||
*/
|
||||
bool amm_client_program_id_from_elf(const uint8_t *elf, uintptr_t elf_len, ProgramId *out);
|
||||
|
||||
/**
|
||||
* Fills `out` with the AMM config PDA.
|
||||
*
|
||||
* # Safety
|
||||
* `amm` must be a valid, non-null pointer to a readable `ProgramId`, and
|
||||
* `out` must be a valid, non-null pointer to writable memory.
|
||||
*/
|
||||
void amm_client_config_pda(const ProgramId *amm, uint8_t (*out)[32]);
|
||||
|
||||
/**
|
||||
* Fills `out` with the pool PDA for the two definition ids.
|
||||
*
|
||||
* # Safety
|
||||
* All pointer arguments must be valid, non-null, and point to readable (or,
|
||||
* for `out`, writable) memory of the indicated sizes.
|
||||
*/
|
||||
void amm_client_pool_pda(const ProgramId *amm,
|
||||
const uint8_t (*def_a)[32],
|
||||
const uint8_t (*def_b)[32],
|
||||
uint8_t (*out)[32]);
|
||||
|
||||
/**
|
||||
* Fills `out` with the vault PDA for a pool + token definition.
|
||||
*
|
||||
* # Safety
|
||||
* All pointer arguments must be valid, non-null, and point to readable (or,
|
||||
* for `out`, writable) memory of the indicated sizes.
|
||||
*/
|
||||
void amm_client_vault_pda(const ProgramId *amm,
|
||||
const uint8_t (*pool)[32],
|
||||
const uint8_t (*def)[32],
|
||||
uint8_t (*out)[32]);
|
||||
|
||||
/**
|
||||
* Fills `out` with the TWAP oracle current-tick PDA for a pool.
|
||||
*
|
||||
* # Safety
|
||||
* All pointer arguments must be valid, non-null, and point to readable (or,
|
||||
* for `out`, writable) memory of the indicated sizes.
|
||||
*/
|
||||
void amm_client_current_tick_pda(const ProgramId *twap,
|
||||
const uint8_t (*pool)[32],
|
||||
uint8_t (*out)[32]);
|
||||
|
||||
/**
|
||||
* Decodes a `PoolDefinition` account's raw bytes into `out`. Returns `false`
|
||||
* on decode failure, leaving `out` unwritten.
|
||||
*
|
||||
* # Safety
|
||||
* `bytes` must be valid for reads of `len` bytes, and `out` must be a
|
||||
* valid, non-null pointer to writable memory for a `FfiPoolView`.
|
||||
*/
|
||||
bool amm_client_decode_pool(const uint8_t *bytes, uintptr_t len, struct FfiPoolView *out);
|
||||
|
||||
#endif /* AMM_CLIENT_FFI_H */
|
||||
8
programs/amm/client-ffi/build.rs
Normal file
8
programs/amm/client-ffi/build.rs
Normal file
@ -0,0 +1,8 @@
|
||||
fn main() {
|
||||
let crate_dir =
|
||||
std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by cargo");
|
||||
cbindgen::generate(&crate_dir)
|
||||
.expect("cbindgen")
|
||||
.write_to_file(format!("{crate_dir}/amm_client_ffi.h"));
|
||||
println!("cargo:rerun-if-changed=src/lib.rs");
|
||||
}
|
||||
7
programs/amm/client-ffi/cbindgen.toml
Normal file
7
programs/amm/client-ffi/cbindgen.toml
Normal file
@ -0,0 +1,7 @@
|
||||
language = "C"
|
||||
include_guard = "AMM_CLIENT_FFI_H"
|
||||
pragma_once = true
|
||||
autogen_warning = "/* Generated by cbindgen. Do not edit. */"
|
||||
|
||||
[export]
|
||||
prefix = ""
|
||||
203
programs/amm/client-ffi/src/lib.rs
Normal file
203
programs/amm/client-ffi/src/lib.rs
Normal file
@ -0,0 +1,203 @@
|
||||
//! C-ABI client helpers for calling the AMM program from host apps.
|
||||
//! All AMM instruction/PDA logic is delegated to `amm_core`; encoding is
|
||||
//! delegated to `lee` — this crate only bridges to a C ABI.
|
||||
#![allow(
|
||||
unsafe_code,
|
||||
reason = "this crate exists solely to expose a C ABI; every unsafe fn \
|
||||
is a documented pointer dereference at the FFI boundary"
|
||||
)]
|
||||
|
||||
mod pda;
|
||||
mod pool;
|
||||
mod swap;
|
||||
|
||||
use nssa_core::account::AccountId;
|
||||
|
||||
/// C-ABI representation of `nssa_core::program::ProgramId` (an Image ID),
|
||||
/// which is itself defined as `[u32; 8]`. Declared as a concrete array here
|
||||
/// (rather than an alias through `nssa_core::program::ProgramId`) so
|
||||
/// cbindgen — which only inspects this crate's source, not its
|
||||
/// dependencies' — can emit a real typedef instead of an opaque,
|
||||
/// self-referential `ProgramId` in the generated header. Since both are
|
||||
/// plain type aliases to `[u32; 8]`, they remain interchangeable to rustc.
|
||||
pub type ProgramId = [u32; 8];
|
||||
|
||||
/// Heap-allocated buffer of RISC0 instruction words, returned across the C
|
||||
/// boundary. Free with `amm_client_free_words`.
|
||||
#[repr(C)]
|
||||
pub struct AmmWords {
|
||||
pub ptr: *mut u32,
|
||||
pub len: usize,
|
||||
pub ok: bool,
|
||||
}
|
||||
|
||||
/// C-ABI mirror of `pool::PoolView`. u128 fields are little-endian bytes.
|
||||
#[repr(C)]
|
||||
pub struct FfiPoolView {
|
||||
pub def_a: [u8; 32],
|
||||
pub def_b: [u8; 32],
|
||||
pub vault_a: [u8; 32],
|
||||
pub vault_b: [u8; 32],
|
||||
pub reserve_a: [u8; 16],
|
||||
pub reserve_b: [u8; 16],
|
||||
pub liquidity_supply: [u8; 16],
|
||||
pub fees: u32,
|
||||
pub ok: bool,
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// `p` must be a valid, non-null pointer to a readable `[u8; 32]`.
|
||||
unsafe fn acc(p: *const [u8; 32]) -> AccountId {
|
||||
AccountId::new(*p)
|
||||
}
|
||||
|
||||
/// Builds the RISC0 instruction words for a `SwapExactInput`. `amount_in` and
|
||||
/// `min_out` are little-endian encoded `u128` values (`[u8; 16]`). The
|
||||
/// returned buffer must be freed with `amm_client_free_words`.
|
||||
///
|
||||
/// # Safety
|
||||
/// `amount_in` and `min_out` must be valid, non-null pointers to readable
|
||||
/// memory of the indicated sizes.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn amm_client_swap_words(
|
||||
amount_in: *const [u8; 16],
|
||||
min_out: *const [u8; 16],
|
||||
deadline: u64,
|
||||
) -> AmmWords {
|
||||
let (a, m) = (u128::from_le_bytes(*amount_in), u128::from_le_bytes(*min_out));
|
||||
match swap::swap_exact_input_words(a, m, deadline) {
|
||||
Ok(w) => {
|
||||
let boxed = w.into_boxed_slice();
|
||||
let len = boxed.len();
|
||||
let ptr = Box::into_raw(boxed).cast::<u32>();
|
||||
AmmWords { ptr, len, ok: true }
|
||||
}
|
||||
Err(_) => AmmWords {
|
||||
ptr: core::ptr::null_mut(),
|
||||
len: 0,
|
||||
ok: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Frees a buffer previously returned by `amm_client_swap_words`.
|
||||
///
|
||||
/// # Safety
|
||||
/// `w` must be a value previously returned by `amm_client_swap_words` that
|
||||
/// has not already been freed.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn amm_client_free_words(w: AmmWords) {
|
||||
if !w.ptr.is_null() {
|
||||
drop(Box::from_raw(std::ptr::slice_from_raw_parts_mut(
|
||||
w.ptr, w.len,
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the `ProgramId` (Image ID) of a compiled guest ELF. Returns
|
||||
/// `false` on an invalid ELF, leaving `out` unwritten.
|
||||
///
|
||||
/// # Safety
|
||||
/// `elf` must be valid for reads of `elf_len` bytes, and `out` must be a
|
||||
/// valid, non-null pointer to writable memory for a `ProgramId`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn amm_client_program_id_from_elf(
|
||||
elf: *const u8,
|
||||
elf_len: usize,
|
||||
out: *mut ProgramId,
|
||||
) -> bool {
|
||||
let bytes = core::slice::from_raw_parts(elf, elf_len);
|
||||
match pda::program_id_from_elf(bytes) {
|
||||
Ok(id) => {
|
||||
*out = id;
|
||||
true
|
||||
}
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Fills `out` with the AMM config PDA.
|
||||
///
|
||||
/// # Safety
|
||||
/// `amm` must be a valid, non-null pointer to a readable `ProgramId`, and
|
||||
/// `out` must be a valid, non-null pointer to writable memory.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn amm_client_config_pda(amm: *const ProgramId, out: *mut [u8; 32]) {
|
||||
*out = pda::config_pda(*amm).into_value();
|
||||
}
|
||||
|
||||
/// Fills `out` with the pool PDA for the two definition ids.
|
||||
///
|
||||
/// # Safety
|
||||
/// All pointer arguments must be valid, non-null, and point to readable (or,
|
||||
/// for `out`, writable) memory of the indicated sizes.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn amm_client_pool_pda(
|
||||
amm: *const ProgramId,
|
||||
def_a: *const [u8; 32],
|
||||
def_b: *const [u8; 32],
|
||||
out: *mut [u8; 32],
|
||||
) {
|
||||
*out = pda::pool_pda(*amm, acc(def_a), acc(def_b)).into_value();
|
||||
}
|
||||
|
||||
/// Fills `out` with the vault PDA for a pool + token definition.
|
||||
///
|
||||
/// # Safety
|
||||
/// All pointer arguments must be valid, non-null, and point to readable (or,
|
||||
/// for `out`, writable) memory of the indicated sizes.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn amm_client_vault_pda(
|
||||
amm: *const ProgramId,
|
||||
pool: *const [u8; 32],
|
||||
def: *const [u8; 32],
|
||||
out: *mut [u8; 32],
|
||||
) {
|
||||
*out = pda::vault_pda(*amm, acc(pool), acc(def)).into_value();
|
||||
}
|
||||
|
||||
/// Fills `out` with the TWAP oracle current-tick PDA for a pool.
|
||||
///
|
||||
/// # Safety
|
||||
/// All pointer arguments must be valid, non-null, and point to readable (or,
|
||||
/// for `out`, writable) memory of the indicated sizes.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn amm_client_current_tick_pda(
|
||||
twap: *const ProgramId,
|
||||
pool: *const [u8; 32],
|
||||
out: *mut [u8; 32],
|
||||
) {
|
||||
*out = pda::current_tick_pda(*twap, acc(pool)).into_value();
|
||||
}
|
||||
|
||||
/// Decodes a `PoolDefinition` account's raw bytes into `out`. Returns `false`
|
||||
/// on decode failure, leaving `out` unwritten.
|
||||
///
|
||||
/// # Safety
|
||||
/// `bytes` must be valid for reads of `len` bytes, and `out` must be a
|
||||
/// valid, non-null pointer to writable memory for a `FfiPoolView`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn amm_client_decode_pool(
|
||||
bytes: *const u8,
|
||||
len: usize,
|
||||
out: *mut FfiPoolView,
|
||||
) -> bool {
|
||||
let b = core::slice::from_raw_parts(bytes, len);
|
||||
match pool::decode_pool(b) {
|
||||
Ok(v) => {
|
||||
*out = FfiPoolView {
|
||||
def_a: v.def_a,
|
||||
def_b: v.def_b,
|
||||
vault_a: v.vault_a,
|
||||
vault_b: v.vault_b,
|
||||
reserve_a: v.reserve_a.to_le_bytes(),
|
||||
reserve_b: v.reserve_b.to_le_bytes(),
|
||||
liquidity_supply: v.liquidity_supply.to_le_bytes(),
|
||||
fees: v.fees,
|
||||
ok: true,
|
||||
};
|
||||
true
|
||||
}
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
48
programs/amm/client-ffi/src/pda.rs
Normal file
48
programs/amm/client-ffi/src/pda.rs
Normal file
@ -0,0 +1,48 @@
|
||||
//! PDA derivation and program-id helpers, delegating to `amm_core` /
|
||||
//! `twap_oracle_core` so the client never re-implements seed hashing.
|
||||
|
||||
use amm_core::{compute_config_pda, compute_pool_pda, compute_vault_pda};
|
||||
use nssa_core::{account::AccountId, program::ProgramId};
|
||||
use risc0_binfmt::ProgramBinary;
|
||||
use twap_oracle_core::compute_current_tick_account_pda;
|
||||
|
||||
/// Computes the `ProgramId` (Image ID) of a compiled guest ELF, the same way
|
||||
/// the sequencer/wallet does when deploying a program.
|
||||
pub fn program_id_from_elf(elf: &[u8]) -> Result<ProgramId, String> {
|
||||
let binary = ProgramBinary::decode(elf).map_err(|e| format!("{e:?}"))?;
|
||||
let id = binary.compute_image_id().map_err(|e| format!("{e:?}"))?;
|
||||
Ok(id.into())
|
||||
}
|
||||
|
||||
pub fn config_pda(amm: ProgramId) -> AccountId {
|
||||
compute_config_pda(amm)
|
||||
}
|
||||
|
||||
pub fn pool_pda(amm: ProgramId, def_a: AccountId, def_b: AccountId) -> AccountId {
|
||||
compute_pool_pda(amm, def_a, def_b)
|
||||
}
|
||||
|
||||
pub fn vault_pda(amm: ProgramId, pool: AccountId, def: AccountId) -> AccountId {
|
||||
compute_vault_pda(amm, pool, def)
|
||||
}
|
||||
|
||||
pub fn current_tick_pda(twap: ProgramId, pool: AccountId) -> AccountId {
|
||||
compute_current_tick_account_pda(twap, pool)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use amm_core::compute_pool_pda;
|
||||
use nssa_core::account::AccountId;
|
||||
use nssa_core::program::ProgramId;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn pool_pda_matches_core() {
|
||||
let amm: ProgramId = [1u32; 8];
|
||||
let a = AccountId::new([2u8; 32]);
|
||||
let b = AccountId::new([3u8; 32]);
|
||||
assert_eq!(pool_pda(amm, a, b), compute_pool_pda(amm, a, b));
|
||||
}
|
||||
}
|
||||
47
programs/amm/client-ffi/src/pool.rs
Normal file
47
programs/amm/client-ffi/src/pool.rs
Normal file
@ -0,0 +1,47 @@
|
||||
//! Decoding for the AMM's on-chain `PoolDefinition` account, so client apps
|
||||
//! can read reserves / fees / vault ids without depending on `amm_core`
|
||||
//! directly.
|
||||
|
||||
use amm_core::PoolDefinition;
|
||||
|
||||
pub struct PoolView {
|
||||
pub def_a: [u8; 32],
|
||||
pub def_b: [u8; 32],
|
||||
pub vault_a: [u8; 32],
|
||||
pub vault_b: [u8; 32],
|
||||
pub reserve_a: u128,
|
||||
pub reserve_b: u128,
|
||||
pub liquidity_supply: u128,
|
||||
/// Fee tier in basis points. Source is `u128` but supported tiers are all
|
||||
/// <= 100, so downcasting to `u32` is safe.
|
||||
pub fees: u32,
|
||||
}
|
||||
|
||||
pub fn decode_pool(bytes: &[u8]) -> Result<PoolView, String> {
|
||||
let p: PoolDefinition = borsh::from_slice(bytes).map_err(|e| format!("{e:?}"))?;
|
||||
Ok(PoolView {
|
||||
def_a: p.definition_token_a_id.into_value(),
|
||||
def_b: p.definition_token_b_id.into_value(),
|
||||
vault_a: p.vault_a_id.into_value(),
|
||||
vault_b: p.vault_b_id.into_value(),
|
||||
reserve_a: p.reserve_a,
|
||||
reserve_b: p.reserve_b,
|
||||
liquidity_supply: p.liquidity_pool_supply,
|
||||
fees: u32::try_from(p.fees).unwrap_or(u32::MAX),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use amm_core::PoolDefinition;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn decode_roundtrip() {
|
||||
let p = PoolDefinition::default();
|
||||
let bytes = borsh::to_vec(&p).unwrap();
|
||||
let v = decode_pool(&bytes).unwrap();
|
||||
assert_eq!(v.reserve_a, 0);
|
||||
}
|
||||
}
|
||||
52
programs/amm/client-ffi/src/swap.rs
Normal file
52
programs/amm/client-ffi/src/swap.rs
Normal file
@ -0,0 +1,52 @@
|
||||
use amm_core::Instruction;
|
||||
|
||||
/// Build the RISC0 instruction words for a SwapExactInput, via the exact
|
||||
/// serializer the public-transaction path and the guest decoder share.
|
||||
pub fn swap_exact_input_words(
|
||||
amount_in: u128,
|
||||
min_out: u128,
|
||||
deadline: u64,
|
||||
) -> Result<Vec<u32>, String> {
|
||||
let instruction = Instruction::SwapExactInput {
|
||||
swap_amount_in: amount_in,
|
||||
min_amount_out: min_out,
|
||||
deadline,
|
||||
};
|
||||
risc0_zkvm::serde::to_vec(&instruction).map_err(|e| format!("{e:?}"))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use amm_core::Instruction;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn words_roundtrip_to_same_instruction() {
|
||||
let words = swap_exact_input_words(1000, 1, u64::MAX).unwrap();
|
||||
// Deserialize back through the exact serde the guest decoder uses.
|
||||
// `Instruction` derives neither `Debug` nor `PartialEq`, so assert
|
||||
// field-by-field instead of matching with a `{:?}` fallback arm.
|
||||
let decoded: Instruction = risc0_zkvm::serde::from_slice(&words).unwrap();
|
||||
match decoded {
|
||||
Instruction::SwapExactInput {
|
||||
swap_amount_in,
|
||||
min_amount_out,
|
||||
deadline,
|
||||
} => {
|
||||
assert_eq!(swap_amount_in, 1000);
|
||||
assert_eq!(min_amount_out, 1);
|
||||
assert_eq!(deadline, u64::MAX);
|
||||
}
|
||||
Instruction::Initialize { .. }
|
||||
| Instruction::UpdateConfig { .. }
|
||||
| Instruction::CreatePriceObservations { .. }
|
||||
| Instruction::CreateOraclePriceAccount { .. }
|
||||
| Instruction::NewDefinition { .. }
|
||||
| Instruction::AddLiquidity { .. }
|
||||
| Instruction::RemoveLiquidity { .. }
|
||||
| Instruction::SwapExactOutput { .. }
|
||||
| Instruction::SyncReserves => panic!("wrong variant: expected SwapExactInput"),
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user