Parceros
  • 馃懡Recursos
    • 馃捇Nodos validadores
      • Buenas pr谩cticas y seguridad de un validador
      • Montaje de nodo validador de Stargaze
      • Montaje de nodo validador de Tgrade
      • Montaje de nodo validador de Juno
      • Instalacion del Cosmovisor
      • Instalaci贸n de AutoCompound
      • Gu铆a de instalaci贸n Prometheus y Grafana para un Validador
    • 馃帗Desarrollo
      • Fundamentos en Gnu/Linux
      • Fundamentos en Blockchain
      • Billeteras
      • Introducci贸n a Cosmos Hub
      • Guia de Inicio en Rust
      • Clases de CosmWasm
        • Introducci贸n a CosmWasm
        • Puntos de entrada de un contrato vacio
        • Consultas - Query
      • Clases de Rust
        • Introducci贸n a Rust
        • Ciclos
        • Funciones
        • Manejo de la memoria
        • Tipos de datos avanzados
        • Macros
        • Manejo de paquetes
        • Manejo de errores
      • Guia Archway
        • Instalaci贸n de requisitos
        • Configuraci贸n del proyecto
        • Solicitud de tokens Testnet
        • Mi primera app
          • Configuracion
          • Produciendo ejecutables wasm
          • Despliegue e instanciaci贸n de contratos en la cadena
          • Interactuar con su contrato
          • Construir el frontend de la dApp
        • Proyecto NFT
          • Creando un proyecto NFT
          • Despliegue del contrato de tokens
          • Acu帽aci贸n y env铆o de tokens
          • Construye la Dapp NFT
        • Fee Grant
          • Comprendiendo los Fee grant
          • Grant asignaci贸n
          • Utilizando asignaciones grant
        • Multifirmas
          • Archway multi firma hub
          • Navegar por la interfaz multi firmas
      • Cosmwasm Documentacion
        • Introducci贸n
        • Primeros pasos
          • Introducci贸n
          • Configuraci贸n del entorno
          • Elaborar un contrato
          • Test Unitarios
          • Despliegue e interacci贸n
          • Integraci贸n con contratos inteligentes
          • Pr贸ximos pasos
        • Arquitectura
          • 驴Qu茅 son los contratos multicadena?
          • Modelo de actor para las convocatorias de contratos
          • Nombres y direcciones
          • Consulta del estado del contrato
          • Formatos de serializaci贸n
          • Composici贸n del contrato
          • Comparaci贸n con los contratos de solidity
        • Contratos inteligentes
          • Sem谩ntica contractual
          • Message
            • Messages
            • Submensajes
          • State
            • Simple state
            • Complex state y maps
          • Result y option
          • Entry points
          • Query
          • Events
          • Math
          • Verificaci贸n de contratos inteligentes
          • Migration
          • Migrar una dapp a una red diferente
          • Testing
          • Ejecuci贸n Sudo
          • CosmWasm y CIB
        • Tutoriales
          • Opcion simple
            • Testing
          • Storage
            • 驴C贸mo funciona el almacenamiento de valores clave?
            • 脥ndices
            • Modelizaci贸n avanzada de estados
          • Cosmwasm con ejemplos
            • Operaciones matem谩ticas de Cosmowasm
            • Crear una instancia de un contrato CosmWasm
            • Timelock
            • Contrato Crowdfunding
            • Respuestas y atributos en Cosmwasm
            • Lee y escribe
            • Env铆o de tokens
            • Token Vaults
            • Creador de mercado autom谩tico de productos constantes (AMM)
      • Guia Celestia
        • Descripcion general de celestia
          • Introduccion
          • Blockchains monol铆ticos vs modulares
          • Capa de disponibilidad de datos
            • La capa de disponibilidad de datos de Celestia
            • El ciclo de vida de una transacci贸n celestia-app
            • Recuperabilidad de datos y poda
            • Disponibilidad de datos FAQ
          • Recursos adicionales
            • Aprende modular
            • Glosario de Celestia
            • Especificaciones de aplicaci贸n de celestes
            • Documentaci贸n API de nodo celestial
        • Ejecutar un nodo
          • Descripci贸n general de los nodos en ejecuci贸n en Celestia
          • Gu铆a de inicio r谩pido
            • Decidir qu茅 nodo ejecutar
            • Entorno de desarrollo
            • Instalar celestia-node
            • Instalar celestia-app
            • 馃惓 Configuraci贸n de Docker
          • Redes
            • Resumen de redes
            • Mainnet Beta
            • Mocha testnet
            • Ar谩bica devnet
          • Tipos de nodos
            • Disponibilidad de datos
              • Nodo ligero
              • Nodo completo
              • Nodo puente
            • Consenso
            • Relay de IBC
              • Gu铆a de retransmisi贸n IBC
              • Relays de IBC
          • Recursos
            • nodo-celestia
              • Metricas
              • gu铆a config.toml
              • Redes y valores personalizados
              • Soluci贸n de problemas
            • celestia-app
              • Especificaciones
              • M茅tricas, visualizaci贸n y alertas
              • Mec谩nica de corte
              • Crear un testnet Celestia
              • Comandos CLI 煤tiles
              • Monitor de Actualizaci贸n
              • Carteras en celestia-app
              • Multisig
              • Crea una cuenta de adquisici贸n
            • SystemD
            • Proceso de hardfork
        • Desarrolladores
          • Construir modular
          • Env铆o de blobs de datos a Celestia
          • Directrices de reenv铆o de transacciones
          • API de nodo
            • Celestia-node RPC CLI tutorial
            • Documentaci贸n de la API RPC de Celestia-Node
            • R谩pido Scavenger
            • Page
          • Integrar con Blobstream
            • Descripci贸n general de Blobstream
            • Integrarse con contratos de Blobstream
            • Integrar con el cliente Blobstream
            • Consultando las pruebas de Blobstream
            • Operadores locales de Blobstream X
              • Solicitar rangos de compromiso de datos
              • Nuevas implementaciones de Blobstream X
          • Implementar un rollup
            • L2s Ethereum
              • Ethereum fallback
              • Arbitro
                • Introducci贸n a los rollups de Arbitrum con Celestia como DA
                • Implementar un arbitrum rollup devnet
                • Testnet de nitr贸geno
                • Implementar un contrato inteligente sobre la implementaci贸n de Arbitrum
                • Implemente un dapp en su devnet Arbitrum rollup
                • Optimismo
                  • Introducci贸n a la integraci贸n de OP Stack
                  • Bubs testnet
                  • Implemente un contrato inteligente en Bubs testnet
                  • Implemente un dapp en Bubs testnet
                  • Implemente un devnet OP Stack
                  • Implemente un devnet OP Stack en Celestia
                  • Auditor铆a
                  • Implemente un dapp con thirdweb
                  • Rollups-as-a-Servicio
                    • Caldera
            • Rollkit
            • Astria
              • Documentaci贸n
              • Implementar a Dusknet
            • SDK Soberano
            • Vistara
            • Dimensi贸n
          • Carteras
            • Crea una billetera con celestia-node
            • Integraciones de billeteras con Celestia
          • Integre Celestia para proveedores de servicios
      • Uni贸n
        • Arquitectura
          • CometBLS
          • Galois
          • Voyager
        • Conceptos
          • BLS Firmas
          • Clientes de Luz Condicional
          • Verificaci贸n de Consenso
          • Tecnolog铆a de validador distribuido
          • IBC
          • Sin permiso versus sin confianza
        • Infraestructura
          • Operador de nodo
            • Empezando
            • Docker Compose
            • Kubernetes
            • NixOS
            • Configuraci贸n del Nodo
        • Integracion
          • IBC Enabled Solidity
        • Demostrar
          • Dirigiendo el Union Devnet
          • PingPong
        • Unirse al testnet
          • Empezando
          • Ejecutar el binario cliente
          • Ejecuci贸n de Unionvisor
          • Obteniendo Tokens Testnet
          • Crear un Validador
          • Endpoints publicos
          • Sincronizaci贸n de estado
          • Liberar un validador
          • Preguntas frecuentes
          • Historial de actualizaciones
        • Guia de estilo
          • Lista de palabras
      • Avail
        • Introducci贸n a Avail
          • Aprovechar DA
          • Aprovechar Nexus
          • Aprovechar la fusi贸n
        • Informacion de red
        • M谩s informaci贸n sobre disponibilidad
          • El conseso
            • BABE
            • GRANDPA
            • NPoS
          • EIP-4844 y disponible
        • Guia de nuevo usuario
          • C贸mo crear y administrar una cuenta disponible
          • C贸mo utilizar el Explorador Goldberg Testnet
          • C贸mo utilizar el faucet Testnet
          • C贸mo establecer una identidad en cadena
          • C贸mo generar una identificaci贸n de aplicaci贸n disponible
          • C贸mo realizar transferencias de saldo disponibles
          • C贸mo crear grupos de nominaciones disponibles
        • Construir con disponibilidad
          • Cree un paquete acumulativo con Avail
          • Comience con Avail
          • Optimium
            • OP Stack
            • Aprovechando la pila OP con Avail
            • C贸mo utilizar la pila OP con Avail
            • Adaptador de pila OP 馃敆
          • Validium
            • Polygon zkEVM
              • Construyendo sobre Polygon zkEVM con Avail
              • C贸mo utilizar Polygon zkEVM con Avail
              • Nodo Validium 馃敆
              • Contratos de Validium 馃敆
              • Puente Validium 馃敆
            • Madara Starknet
              • Construyendo sobre Madara Stack con Avail
              • C贸mo utilizar Madara con Avail
              • Madara Starknet馃敆
            • Referencia
          • Sovereign Rollups
            • Sovereign SDK 馃敆
            • Rollkit 馃敆
            • OpEVM 馃敆
        • Glosario
        • Preguntas generales frecuentes
      • Dymension
        • Aprender
          • ELI5
          • RollApps
            • RollApps
            • Tokens
            • Gobernancia
            • Puente
            • En profundidad
              • Dymension RDK
                • Dymint
              • Gobernanza
                • Gobernador
                  • Descripci贸n general
                  • Crear gobernador
                  • Otros comandos
                • Votaci贸n
                  • Par谩metros ajustables
                  • Gasto comunitario
                  • Registro de tokens ERC-20
              • IBC Puente
                • Visi贸n general
                • Seguridad
                • Retransmisores
          • Dymension
            • Visi贸n general
            • DYM
              • Supply
              • Demanda
              • Crecimiento
              • Distribuci贸n
            • Seguridad
              • Est谩ndares
              • Actualizable
              • Disponibilidad de datos
              • Pruebas de fraude
              • Resistencia a la censura
              • Page 1
            • Puentes
              • IBC
              • eIBC
            • Liquidez
              • Descripci贸n general
              • Depositar tokens
              • Vinculaci贸n de tokens LP
              • Incentivos
              • Comisiones
            • Gobernanza
              • Descripci贸n general
              • Preparando una propuesta
              • Proponiendo a la dimocracia
        • Construir
          • Descripci贸n general
          • Testnet
            • EVM
              • Descripci贸n general
            • CosmWasm
              • Descripci贸n general
              • Informaci贸n
              • Ejemplo de cosmoWasm
          • Roller CLI
            • Descripci贸n general
            • Comenzar
              • Instalar
              • Inicializar RollApp
              • Registro
              • Correr
                • Simple
                • Avanzado
                  • Cliente ligero DA
                  • Secuenciador
                  • Retransmisor
            • Nodo en ejecuci贸n
              • Ejecutando en producci贸n
              • Supervisi贸n
              • Informaci贸n de RollApp
              • Exportar claves
              • Mejora
              • Editar la configuraci贸n de RollApp
              • Sincronizaci贸n de estado
            • Soluci贸n de problemas
              • Descripci贸n general
              • Saldos
              • Hardware
              • Rollapp de importaci贸n/exportaci贸n
              • Acceso externo
              • Estado
              • Archivos de registro
            • RollApp local
              • Ejecute la aplicaci贸n EVM RollApp
              • Ejecute la aplicaci贸n CosmWasm RollApp
        • Validar
          • Preguntas frecuentes sobre nodos
          • Construir dimensi贸n
          • Configuraci贸n de nodo
          • 脷nase a una red
          • Nodo de sincronizaci贸n
          • Validador
          • Actualizaciones
          • Soluci贸n de problemas
          • Programa de delegaci贸n
            • objetivos del programa
            • Par谩metros de evaluaci贸n
            • Solicitud
      • Movement
        • Desarrolladores
          • Inicio r谩pido
          • Configuraci贸n
            • Usando contenedores
            • Usando el instalador
          • Tutoriales
            • Desplegar
              • M贸dulo Aptos
              • M贸dulo Sui
              • Contratos EVM
                • Implementaci贸n de contratos de solidez en movimiento utilizando Foundry y Fractal
                • Implementaci贸n de contratos de solidez en M1 usando Hardhat y Fractal
                • Implementaci贸n de contratos inteligentes de Solidity en M1 utilizando el tiempo de ejecuci贸n Fractal
            • Ejecute MoveVM
              • Ejecutando M1 usted mismo
            • Construir dApp
              • Aptos Move dApp
              • Aplicaci贸n Sui Move
              • DApp de solidity
            • Interoperar
              • AptosVM<>MEVM
          • Herramientas de desarrollo
            • Movement CLI
              • Movement aptos
                • cuenta
                  • crear
                  • crear-cuenta-de-recursos
                    • derivar-direcci贸n-de-cuenta-de-recursos
                  • fondo-con-grifo
                  • lista
                  • direcci贸n de b煤squeda
                  • rotar llave
                  • transferir
                • configuraci贸n
                  • generar-compleciones-de-shell
                  • configurar-global-config
                  • show-global-config
                  • mostrar-perfiles
                • g茅nesis
                  • generar-admin-escritura-conjunto
                  • generar-g茅nesis
                  • obtener direcciones de grupo
                  • generar-claves
                  • generar-plantilla-de-dise帽o
                  • configuraci贸n-git
                  • configuraci贸n-del-validador-de-conjuntos
                • gobernancia
                  • proponer
                  • votar
                  • propuesta de show
                  • lista-propuestas
                  • verificar-propuesta
                  • ejecutar propuesta
                  • generar-propuesta-de-actualizaci贸n
                  • aprobar-ejecuci贸n-hash
                • informaci贸n
                • init
                • llave
                  • generar
                  • extraer-peer
                • mover
                  • construir-publicar-carga 煤til
                  • limpio
                  • compilar
                  • script de compilaci贸n
                  • cobertura
                    • resumen
                    • fuente
                    • c贸digo de bytes
                  • crear-cuenta-de-recursos-y-publicar-paquete
                  • desmontar
                  • documento
                  • descargar
                  • init
                  • list
                  • probar
                  • publicar
                  • correr
                  • ejecutar gui贸n
                  • prueba
                  • prueba transaccional
                  • verificar-paquete
                  • vista
                • multifirma
                  • aprobar
                  • crear
                  • crear-transacci贸n
                  • ejecutar
                  • ejecutar-rechazar
                  • ejecutar con carga 煤til
                  • rechazar
                  • verificar-propuesta
                • nodo
                  • analizar-validador-rendimiento
                  • arranque-db
                  • verificar-conectividad-de-red
                  • conseguir-participaci贸n-pool
                  • inicializar-validador
                  • conjunto de validadores de uni贸n
                  • conjunto de validadores de licencia
                  • mostrar-informaci贸n-de-茅poca
                  • mostrar-validador-config
                  • mostrar-conjunto-validador
                  • mostrar-validador-participaci贸n
                  • ejecutar-testnet-local
                  • actualizaci贸n-clave-de-consenso
                  • actualizar-validador-direcciones-de-red
                • apostar
                  • agregar apuesta
                  • crear-contrato-de-participaci贸n
                  • distribuir-monedas-adquiridas
                  • aumentar-bloqueo
                  • inicializar-propietario de la participaci贸n
                  • solicitud-comisi贸n
                  • establecer-votante-delegado
                  • operador de conjunto
                  • desbloquear-apuesta
                  • desbloquear-monedas-adquiridas
                  • retirar-apuesta
                • actualizar
              • movement sui
                • comenzar
                • g茅nesis
                • ceremonia-genesis
                  • init
                  • estado de validaci贸n
                  • agregar-validador
                  • validadores de lista
                  • punto de control de compilaci贸n sin firmar
                  • examinar-punto-de-control-g茅nesis
                  • verificar y firmar
                  • finalizar
                • herramienta clave
                  • convertir
                  • decodificar-tx-bytes
                  • decodificar-multi-sig
                  • generar
                  • importar
                  • lista
                  • par de claves de carga
                  • direcci贸n multifirma
                  • multi-sig-combinar-sig-parcial
                  • herencia-sig-parcial-combinada-multi-sig
                  • espect谩culo
                  • firmar
                  • se帽al-kms
                  • deshacer
                  • zk-login-firmar-y-ejecutar-tx
                  • zk-login-ingresar-token
                  • zk-login-sig-verificar
                  • zk-login-signo-inseguro-mensaje-personal
                • consola
                • cliente
                  • direcci贸n activa
                  • entorno-activo
                  • direcciones
                  • llamar
                  • identificador de cadena
                  • campo din谩mico
                  • env
                  • ejecutar-tx firmado
                  • gas
                  • fusionar moneda
                  • nueva direccion
                  • nuevo-ambiente
                  • objeto
                  • objetos
                  • pagar
                  • pago todo-sui
                  • pay-sui
                  • publicar
                  • moneda dividida
                  • cambiar
                  • bloque tx
                  • transferir
                  • transferencia-sui
                  • mejora
                  • verificar-bytecode-metro
                  • verificar-fuente
                  • transacci贸n-repetici贸n
                  • lote de repetici贸n
                  • punto de control de repetici贸n
                • validador
                  • hacer-informaci贸n-validador
                  • convertirse en candidato
                  • comit茅 conjunto
                  • comit茅 de licencia
                  • metadatos de visualizaci贸n
                  • actualizar-metadatos
                    • nombre
                    • descripci贸n
                    • URL de la imagen
                    • URL del proyecto
                    • direcci贸n de red
                    • direcci贸n primaria
                    • direcci贸n-trabajador
                    • direcci贸n-p2p
                    • clave-pub-de-red
                    • clave-pub-trabajador
                    • protocolo-pub-clave
                  • actualizar-precio-de-gas
                  • validador de informes
                  • serializar-carga 煤til-pop
                  • mostrar-actualizaci贸n-del-precio-del-gas-raw-txn
                • move
                  • construir
                  • cobertura
                    • resumen
                    • fuente
                    • c贸digo de bytes
                  • desmontar
                  • nuevo
                  • probar
                  • prueba
                • simulacro de incendio
                  • rotaci贸n de metadatos
              • movement ctl
              • movement manage
            • fractales
              • marco evm
          • Desarrolladores Aptos
            • Configurar la CLI de Aptos
            • Usando la CLI de Aptos
          • Desarrolladores Sui
            • Configurar Sui CLI
            • Usando Sui CLI
          • Preguntas m谩s frecuentes
        • Ecosistema
          • Wallets
          • Tokens
          • Faucet
          • Move idioma
            • M贸dulos y scripts
            • Tipos primitivos
              • Enteros
              • booleano
              • DIRECCI脫N
              • Vector
              • Firmante
              • Referencias
              • Tuplas y unidad
          • Recursos de aprendizaje
          • Techpedia
            • Paralelizaci贸n
            • Mover recursos
            • SDK de movement
      • Initia
        • ACERCA DE
          • Bienvenido a Inicia
          • Arquitectura Omnitia
            • Inicia (Capa 1)
            • Minitia (Capa 2)
          • Ciclo de vida de la transacci贸n
          • Liquidez y apuestas consagradas
            • IniciaDEX
          • Programa de intereses adquiridos
        • CONSTRUIR SOBRE LA INICIATIVA
          • iniciado
          • inicia.js
          • Creando cuenta
          • Tutoriales espec铆ficos de VM
            • MoverVM
              • Implementaci贸n de m贸dulos de movimiento
              • Creando moneda de movimiento
              • Env铆o de moneda de movimiento
              • Creando movimiento NFT
              • M贸dulos relacionados con el replanteo
              • Interactuar con Oracle en MoveVM
              • Mover ganchos IBC
            • WASMVM
              • Implementaci贸n del contrato CosmWasm
              • Interactuando con Oracle en WasmVM
              • Ganchos Wasm IBC
              • F谩brica de fichas
            • EVM
              • Implementaci贸n del contrato de solidez
              • Crear un token ERC-20 personalizado
              • Consultar estados del cosmos
              • Ejecutando mensajes de Cosmos
              • Conversi贸n de direcciones entre EVM y Cosmos
              • Conversi贸n entre direcciones Denom y ERC-20
              • Interactuar con Oracle en EVM
              • Ganchos EVM IBC
              • Ethereum JSON-RPC
          • Tutoriales generales
            • Or谩culo: Furtivo
            • Mensajes entre cadenas
            • Saltar API
            • Miniswap
              • Interactuando con Minitswap
            • Conversi贸n entre nombres de usuario y direcciones
            • Usando el Explorador local de Initia
            • Interactuando con InitiaDEX
            • Usando el widget de billetera Initia
        • IMPLEMENTAR MINITIA
          • Empezando
            • Implementaci贸n de su propia Minitia (Capa 2)
          • Configuraci贸n
          • Implementaci贸n de una Minitia independiente
          • Implementaci贸n completa de Minitia
            • Dirigiendo la Minitia
            • Pila de OPinit
              • M贸dulo OPinit: OPhost y OPchild
              • Configurar robots OPinit
                • Ejecutor del puente
                • Remitente de salida
                • Desafiador
                • Env铆o por lotes
                  • Env铆o de lotes a Inicia L1
                  • Env铆o de lotes a Celestia
            • Rel茅 Hermes (IBC)
            • Habilitando or谩culos
          • Retroceder
          • Agregar tokens a Initia Wallet
          • Personalizando Minitia
        • EJECUTAR EL NODO DE INICIO
          • Ejecutando el nodo de inicio
          • Arrancar un nodo de inicio
          • Con茅ctese a la red Inicial
          • Or谩culo
          • Automatizaci贸n de actualizaciones de software con Cosmovisor
          • Convertirse en un validador
        • RECURSOS
          • Registro de Iniciaci贸n
          • Informaci贸n de la cadena Testnet
          • Par谩metros de cadena
          • Documentaci贸n de la API
          • Documentos API (MiniMove)
          • Documentos API (MiniWasm)
          • Documentos API (MiniEVM)
      • Internet Computer
        • 隆Hola, mundo!
        • Descripci贸n general del ICP
Powered by GitBook
On this page
  • Explicaci贸n
  • Ejemplos
  1. Recursos
  2. Desarrollo
  3. Cosmwasm Documentacion
  4. Tutoriales
  5. Cosmwasm con ejemplos

Creador de mercado autom谩tico de productos constantes (AMM)

Explicaci贸n

Este contrato es un creador de mercado automatizado (AMM) de productos constantes para CosmWasm. Este contrato le permite intercambiar tokens. Los proveedores de liquidez pueden agregar liquidez al mercado y recibir una tarifa determinada por cada transacci贸n que se establece en la instanciaci贸n. El c贸digo tambi茅n incluye varias comprobaciones de validaci贸n y manejo de errores para garantizar la correcci贸n y seguridad de las operaciones. Este tipo de AMM se basa en la funci贸n x*y=k, que establece un rango de precios para dos tokens seg煤n la liquidez disponible de cada token. Cuando la oferta de token X aumenta, la oferta de token de Y debe disminuir, y viceversa, para mantener el producto K constante. Cuando se representa gr谩ficamente, el resultado es una hip茅rbola donde la liquidez siempre est谩 disponible pero a precios cada vez m谩s altos, que se acercan al infinito. en ambos extremos.

Creaci贸n de instancias

El contrato se puede instanciar con los siguientes mensajes

{
    "token1_denom": {"cw20": "<CONTRACT_ADDRESS>"},
    "token2_denom": {"cw20": "<CONTRACT_ADDRESS>"},
}

El nombre del token puede ser cw20 para tokens cw20. Los tokens cw20 tienen una direcci贸n de contrato. CW20_CODE_ID es la identificaci贸n del c贸digo para un binario cw20 b谩sico.

Agregar liquidez

Permite a un usuario agregar liquidez al grupo.

pub fn execute_add_liquidity(
    deps: DepsMut,
    info: &MessageInfo,
    env: Env,
    min_liquidity: Uint128,
    token1_amount: Uint128,
    token2_amount: Uint128,
    expiration: Option<Expiration>,
) -> Result<Response, ContractError> {
    check_expiration(&expiration, &env.block)?;
    let token1 = TOKEN1.load(deps.storage)?;
    let token2 = TOKEN2.load(deps.storage)?;
    let mut token_supply = TOTAL_STORED.load(deps.storage)?;
    let liquidity_amount = token1_amount+token2_amount;
    token_supply+=liquidity_amount;
    TOTAL_STORED.save(deps.storage, &token_supply)?;
    if liquidity_amount < min_liquidity {
        return Err(ContractError::MinLiquidityError {
            min_liquidity,
            liquidity_available: liquidity_amount,
        });
    }
    // Generate cw20 transfer messages if necessary
    let mut transfer_msgs: Vec<CosmosMsg> = vec![];
    if let Cw20(addr) = token1.denom {
        transfer_msgs.push(get_cw20_transfer_from_msg(
            &info.sender,
            &env.contract.address,
            &addr,
            token1_amount,
        )?)
    }
    if let Cw20(addr) = token2.denom.clone() {
        transfer_msgs.push(get_cw20_transfer_from_msg(
            &info.sender,
            &env.contract.address,
            &addr,
            token2_amount,
        )?)
    }
    TOKEN1.update(deps.storage, |mut token1| -> Result<_, ContractError> {
        token1.reserve += token1_amount;
        Ok(token1)
    })?;
    TOKEN2.update(deps.storage, |mut token2| -> Result<_, ContractError> {
        token2.reserve += token2_amount;
        Ok(token2)
    })?;
    Ok(Response::new()
        .add_messages(transfer_msgs)
        .add_attributes(vec![
            attr("token1_amount", token1_amount),
            attr("token2_amount", token2_amount),
            attr("liquidity_received", liquidity_amount),
        ]))
}

Los usuarios pueden agregar liquidez al AMM llamando a la funci贸n ejecutar_add_liquidity. Esta funci贸n toma las cantidades deseadas de dos tokens (token1_amount y token2_amount) y acu帽a la cantidad correspondiente de tokens de liquidez. Los tokens de liquidez representan la participaci贸n del usuario en el fondo de liquidez de AMM. La funci贸n tambi茅n transfiere los tokens de entrada del usuario al contrato.

Eliminar liquidez

Permite a un usuario eliminar liquidez del grupo.

pub fn execute_remove_liquidity(
    deps: DepsMut,
    info: MessageInfo,
    env: Env,
    amount: Uint128,
    min_token1: Uint128,
    min_token2: Uint128,
    expiration: Option<Expiration>,
) -> Result<Response, ContractError> {
    check_expiration(&expiration, &env.block)?;
    let total_token_supply = TOTAL_STORED.load(deps.storage)?;
    let token1 = TOKEN1.load(deps.storage)?;
    let token2 = TOKEN2.load(deps.storage)?;
    if amount > total_token_supply {
        return Err(ContractError::InsufficientLiquidityError {
            requested: amount,
            available: total_token_supply,
        });
    }
    let token1_amount = amount
        .checked_mul(token1.reserve)
        .map_err(StdError::overflow)?
        .checked_div(total_token_supply)
        .map_err(StdError::divide_by_zero)?;
    if token1_amount < min_token1 {
        return Err(ContractError::MinToken1Error {
            requested: min_token1,
            available: token1_amount,
        });
    }
    let token2_amount = amount
        .checked_mul(token2.reserve)
        .map_err(StdError::overflow)?
        .checked_div(total_token_supply)
        .map_err(StdError::divide_by_zero)?;
    if token2_amount < min_token2 {
        return Err(ContractError::MinToken2Error {
            requested: min_token2,
            available: token2_amount,
        });
    }
    TOKEN1.update(deps.storage, |mut token1| -> Result<_, ContractError> {
        token1.reserve = token1
            .reserve
            .checked_sub(token1_amount)
            .map_err(StdError::overflow)?;
        Ok(token1)
    })?;
    TOKEN2.update(deps.storage, |mut token2| -> Result<_, ContractError> {
        token2.reserve = token2
            .reserve
            .checked_sub(token2_amount)
            .map_err(StdError::overflow)?;
        Ok(token2)
    })?;
    let token1_transfer_msg = match token1.denom {
        Denom::Cw20(addr) => get_cw20_transfer_to_msg(&info.sender, &addr, token1_amount)?,
        Denom::Native(_denom) => {unimplemented!()},
    };
    let token2_transfer_msg = match token2.denom {
        Denom::Cw20(addr) => get_cw20_transfer_to_msg(&info.sender, &addr, token2_amount)?,
        Denom::Native(_denom) => {unimplemented!()},
    };
    Ok(Response::new()
        .add_messages(vec![
            token1_transfer_msg,
            token2_transfer_msg,
        ])
        .add_attributes(vec![
            attr("liquidity_burned", amount),
            attr("token1_returned", token1_amount),
            attr("token2_returned", token2_amount),
        ]))
}

Los proveedores de liquidez pueden eliminar su liquidez llamando a la funci贸n ejecutar_remove_liquidity. Especifican la cantidad de tokens de liquidez (monto) que quieren quemar y la funci贸n calcula las cantidades proporcionales de los tokens subyacentes (token1_amount y token2_amount). La funci贸n transfiere los tokens correspondientes al usuario y reduce las reservas de tokens en consecuencia.

Swap

Cambiar un activo por otro

pub fn execute_swap(
    deps: DepsMut,
    info: &MessageInfo,
    input_amount: Uint128,
    _env: Env,
    input_token_enum: TokenSelect,
    recipient: String,
    min_token: Uint128,
    expiration: Option<Expiration>,
) -> Result<Response, ContractError> {
    check_expiration(&expiration, &_env.block)?;
    let input_token_item = match input_token_enum {
        TokenSelect::Token1 => TOKEN1,
        TokenSelect::Token2 => TOKEN2,
    };
    let input_token = input_token_item.load(deps.storage)?;
    let output_token_item = match input_token_enum {
        TokenSelect::Token1 => TOKEN2,
        TokenSelect::Token2 => TOKEN1,
    };
    let output_token = output_token_item.load(deps.storage)?;
    let fees = FEES.load(deps.storage)?;
    let total_fee_percent = fees.lp_fee_percent + fees.protocol_fee_percent;
    let token_bought = get_input_price(
        input_amount,
        input_token.reserve,
        output_token.reserve,
        total_fee_percent,
    )?;
    if min_token > token_bought {
        return Err(ContractError::SwapMinError {
            min: min_token,
            available: token_bought,
        });
    }
    // Calculate fees
    let protocol_fee_amount = get_protocol_fee_amount(input_amount, fees.protocol_fee_percent)?;
    let input_amount_minus_protocol_fee = input_amount - protocol_fee_amount;
    let mut msgs = match input_token.denom.clone() {
        Denom::Cw20(addr) => vec![get_cw20_transfer_from_msg(
            &info.sender,
            &_env.contract.address,
            &addr,
            input_amount_minus_protocol_fee,
        )?],
        Denom::Native(_) => vec![],
    };
    // Send protocol fee to protocol fee recipient
    if !protocol_fee_amount.is_zero() {
        msgs.push(get_fee_transfer_msg(
            &info.sender,
            &fees.protocol_fee_recipient,
            &input_token.denom,
            protocol_fee_amount,
        )?)
    }
    let recipient = deps.api.addr_validate(&recipient)?;
    // Create transfer to message
    msgs.push(match output_token.denom {
        Denom::Cw20(addr) => get_cw20_transfer_to_msg(&recipient, &addr, token_bought)?,
        Denom::Native(_denom) => {unimplemented!()},
    });
    input_token_item.update(
        deps.storage,
        |mut input_token| -> Result<_, ContractError> {
            input_token.reserve = input_token
                .reserve
                .checked_add(input_amount_minus_protocol_fee)
                .map_err(StdError::overflow)?;
            Ok(input_token)
        },
    )?;
    output_token_item.update(
        deps.storage,
        |mut output_token| -> Result<_, ContractError> {
            output_token.reserve = output_token
                .reserve
                .checked_sub(token_bought)
                .map_err(StdError::overflow)?;
            Ok(output_token)
        },
    )?;
    Ok(Response::new().add_messages(msgs).add_attributes(vec![
        attr("native_sold", input_amount),
        attr("token_bought", token_bought),
    ]))
}

Los usuarios pueden intercambiar tokens utilizando AMM llamando a la funci贸n ejecutar_swap. Especifican el token de entrada (input_token), la cantidad a intercambiar (input_amount) y la cantidad m铆nima de salida (min_output). La funci贸n calcula la cantidad de salida calculada en la f贸rmula del producto constante y verifica si cumple con el requisito m铆nimo. Si el intercambio es v谩lido, transfiere el token de entrada del usuario al contrato y transfiere el token de salida nuevamente al usuario.

Actualizaci贸n de configuraci贸n

Para actualizar la configuraci贸n de AMM

pub fn execute_update_config(
    deps: DepsMut,
    info: MessageInfo,
    new_owner: Option<String>,
    lp_fee_percent: Decimal,
    protocol_fee_percent: Decimal,
    protocol_fee_recipient: String,
) -> Result<Response, ContractError> {
    let owner = OWNER.load(deps.storage)?;
    if Some(info.sender) != owner {
        return Err(ContractError::Unauthorized {});
    }
    let new_owner_addr = new_owner
        .as_ref()
        .map(|h| deps.api.addr_validate(h))
        .transpose()?;
    OWNER.save(deps.storage, &new_owner_addr)?;
    let total_fee_percent = lp_fee_percent + protocol_fee_percent;
    let max_fee_percent = Decimal::from_str(MAX_FEE_PERCENT)?;
    if total_fee_percent > max_fee_percent {
        return Err(ContractError::FeesTooHigh {
            max_fee_percent,
            total_fee_percent,
        });
    }
    let protocol_fee_recipient = deps.api.addr_validate(&protocol_fee_recipient)?;
    let updated_fees = Fees {
        protocol_fee_recipient: protocol_fee_recipient.clone(),
        lp_fee_percent,
        protocol_fee_percent,
    };
    FEES.save(deps.storage, &updated_fees)?;
    let new_owner = new_owner.unwrap_or_default();
    Ok(Response::new().add_attributes(vec![
        attr("new_owner", new_owner),
        attr("lp_fee_percent", lp_fee_percent.to_string()),
        attr("protocol_fee_percent", protocol_fee_percent.to_string()),
        attr("protocol_fee_recipient", protocol_fee_recipient.to_string()),
    ]))
}

El propietario puede actualizar la configuraci贸n del AMM mediante la funci贸n ejecutar_update_config. El propietario puede cambiar el porcentaje de la tarifa LP (proveedor de liquidez), el porcentaje de la tarifa del protocolo y la direcci贸n del destinatario de la tarifa del protocolo.

Congelamiento de dep贸sitos

Para congelar el dep贸sito a AMM

fn execute_freeze_deposits(
    deps: DepsMut,
    sender: Addr,
    freeze: bool,
) -> Result<Response, ContractError> {
    if let Some(owner) = OWNER.load(deps.storage)? {
        if sender != owner {
            return Err(ContractError::UnauthorizedPoolFreeze {});
        }
    } else {
        return Err(ContractError::UnauthorizedPoolFreeze {});
    }
    FROZEN.save(deps.storage, &freeze)?;
    Ok(Response::new().add_attribute("action", "freezing-contracts"))
}
fn check_expiration(
    expiration: &Option<Expiration>,
    block: &BlockInfo,
) -> Result<(), ContractError> {
    match expiration {
        Some(e) => {
            if e.is_expired(block) {
                return Err(ContractError::MsgExpirationError {});
            }
            Ok(())
        }
        None => Ok(()),
    }
}

El propietario puede congelar los dep贸sitos en AMM llamando a la funci贸n ejecutar_freeze_deposits. Esto evita que los usuarios agreguen liquidez o intercambien tokens. S贸lo el propietario puede congelar o descongelar los dep贸sitos.

Ejemplos

Para crear un AMM con CosmWasm, puede crear los siguientes archivos: lib.rs Integration_tests.rs contract.rs msg.rs error.rs state.rs

lib.rs

pub mod contract;
pub mod error;
mod integration_test;
pub mod msg;
pub mod state;

integration_tests.rs

#![cfg(test)]
use std::borrow::BorrowMut;
use crate::error::ContractError;
use cosmwasm_std::{coins, Addr, Coin, Decimal, Empty, Uint128};
use cw20::{Cw20Coin, Cw20Contract, Cw20ExecuteMsg, Denom};
use cw_multi_test::{App, Contract, ContractWrapper, Executor};
use std::str::FromStr;
use crate::msg::{ExecuteMsg, FeeResponse, InfoResponse, InstantiateMsg, QueryMsg, TokenSelect};
fn mock_app() -> App {
    App::default()
}
pub fn contract_amm() -> Box<dyn Contract<Empty>> {
    let contract = ContractWrapper::new(
        crate::contract::execute,
        crate::contract::instantiate,
        crate::contract::query,
    );
    Box::new(contract)
}
pub fn contract_cw20() -> Box<dyn Contract<Empty>> {
    let contract = ContractWrapper::new(
        cw20_base::contract::execute,
        cw20_base::contract::instantiate,
        cw20_base::contract::query,
    );
    Box::new(contract)
}
fn get_info(router: &App, contract_addr: &Addr) -> InfoResponse {
    router
        .wrap()
        .query_wasm_smart(contract_addr, &QueryMsg::Info {})
        .unwrap()
}
fn get_fee(router: &App, contract_addr: &Addr) -> FeeResponse {
    router
        .wrap()
        .query_wasm_smart(contract_addr, &QueryMsg::Fee {})
        .unwrap()
}
fn create_amm(
    router: &mut App,
    owner: &Addr,
    token1_denom: Denom,
    token2_denom: Denom,
    lp_fee_percent: Decimal,
    protocol_fee_percent: Decimal,
    protocol_fee_recipient: String,
) -> Addr {
    // set up amm contract
    let amm_id = router.store_code(contract_amm());
    let msg = InstantiateMsg {
        token1_denom,
        token2_denom,
        owner: Some(owner.to_string()),
        lp_fee_percent,
        protocol_fee_percent,
        protocol_fee_recipient,
    };
    router
        .instantiate_contract(amm_id, owner.clone(), &msg, &[], "amm", None)
        .unwrap()
}
// CreateCW20 create new cw20 with given initial balance belonging to owner
fn create_cw20(
    router: &mut App,
    owner: &Addr,
    name: String,
    symbol: String,
    balance: Uint128,
) -> Cw20Contract {
    // set up cw20 contract with some tokens
    let cw20_id = router.store_code(contract_cw20());
    let msg = cw20_base::msg::InstantiateMsg {
        name,
        symbol,
        decimals: 6,
        initial_balances: vec![Cw20Coin {
            address: owner.to_string(),
            amount: balance,
        }],
        mint: None,
        marketing: None,
    };
    let addr = router
        .instantiate_contract(cw20_id, owner.clone(), &msg, &[], "CASH", None)
        .unwrap();
    Cw20Contract(addr)
}
fn bank_balance(router: &mut App, addr: &Addr, denom: String) -> Coin {
    router
        .wrap()
        .query_balance(addr.to_string(), denom)
        .unwrap()
}
#[test]
// receive cw20 tokens and release upon approval
fn test_instantiate() {
    let mut router = mock_app();
    const NATIVE_TOKEN_DENOM: &str = "juno";
    let owner = Addr::unchecked("owner");
    let funds = coins(2000, NATIVE_TOKEN_DENOM);
    router.borrow_mut().init_modules(|router, _, storage| {
        router.bank.init_balance(storage, &owner, funds).unwrap()
    });
    let cw20_token = create_cw20(
        &mut router,
        &owner,
        "token".to_string(),
        "CWTOKEN".to_string(),
        Uint128::new(5000),
    );
    let lp_fee_percent = Decimal::from_str("0.3").unwrap();
    let protocol_fee_percent = Decimal::zero();
    let amm_addr = create_amm(
        &mut router,
        &owner,
        Denom::Native(NATIVE_TOKEN_DENOM.into()),
        Denom::Cw20(cw20_token.addr()),
        lp_fee_percent,
        protocol_fee_percent,
        owner.to_string(),
    );
    assert_ne!(cw20_token.addr(), amm_addr);
    let _info = get_info(&router, &amm_addr);
    let fee = get_fee(&router, &amm_addr);
    assert_eq!(fee.lp_fee_percent, lp_fee_percent);
    assert_eq!(fee.protocol_fee_percent, protocol_fee_percent);
    assert_eq!(fee.protocol_fee_recipient, owner.to_string());
    assert_eq!(fee.owner.unwrap(), owner.to_string());
    // Test instantiation with invalid fee amount
    let lp_fee_percent = Decimal::from_str("1.01").unwrap();
    let protocol_fee_percent = Decimal::zero();
    let amm_id = router.store_code(contract_amm());
    let msg = InstantiateMsg {
        token1_denom: Denom::Native(NATIVE_TOKEN_DENOM.into()),
        token2_denom: Denom::Cw20(cw20_token.addr()),
        owner: Some(owner.to_string()),
        lp_fee_percent,
        protocol_fee_percent,
        protocol_fee_recipient: owner.to_string(),
    };
    let err = router
        .instantiate_contract(amm_id, owner.clone(), &msg, &[], "amm", None)
        .unwrap_err()
        .downcast()
        .unwrap();
    assert_eq!(
        ContractError::FeesTooHigh {
            max_fee_percent: Decimal::from_str("1").unwrap(),
            total_fee_percent: Decimal::from_str("1.01").unwrap()
        },
        err
    );
}
#[test]
fn update_config() {
    let mut router = mock_app();
    const NATIVE_TOKEN_DENOM: &str = "juno";
    let owner = Addr::unchecked("owner");
    let funds = coins(2000, NATIVE_TOKEN_DENOM);
    router.borrow_mut().init_modules(|router, _, storage| {
        router.bank.init_balance(storage, &owner, funds).unwrap()
    });
    let cw20_token = create_cw20(
        &mut router,
        &owner,
        "token".to_string(),
        "CWTOKEN".to_string(),
        Uint128::new(5000),
    );
    let lp_fee_percent = Decimal::from_str("0.3").unwrap();
    let protocol_fee_percent = Decimal::zero();
    let amm_addr = create_amm(
        &mut router,
        &owner,
        Denom::Native(NATIVE_TOKEN_DENOM.to_string()),
        Denom::Cw20(cw20_token.addr()),
        lp_fee_percent,
        protocol_fee_percent,
        owner.to_string(),
    );
    let lp_fee_percent = Decimal::from_str("0.15").unwrap();
    let protocol_fee_percent = Decimal::from_str("0.15").unwrap();
    let msg = ExecuteMsg::UpdateConfig {
        owner: Some(owner.to_string()),
        protocol_fee_recipient: "new_fee_recpient".to_string(),
        lp_fee_percent,
        protocol_fee_percent,
    };
    let _res = router
        .execute_contract(owner.clone(), amm_addr.clone(), &msg, &[])
        .unwrap();
    let fee = get_fee(&router, &amm_addr);
    assert_eq!(fee.protocol_fee_recipient, "new_fee_recpient".to_string());
    assert_eq!(fee.protocol_fee_percent, protocol_fee_percent);
    assert_eq!(fee.lp_fee_percent, lp_fee_percent);
    assert_eq!(fee.owner.unwrap(), owner.to_string());
    // Try updating config with fee values that are too high
    let lp_fee_percent = Decimal::from_str("1.01").unwrap();
    let protocol_fee_percent = Decimal::zero();
    let msg = ExecuteMsg::UpdateConfig {
        owner: Some(owner.to_string()),
        protocol_fee_recipient: "new_fee_recpient".to_string(),
        lp_fee_percent,
        protocol_fee_percent,
    };
    let err = router
        .execute_contract(owner.clone(), amm_addr.clone(), &msg, &[])
        .unwrap_err()
        .downcast()
        .unwrap();
    assert_eq!(
        ContractError::FeesTooHigh {
            max_fee_percent: Decimal::from_str("1").unwrap(),
            total_fee_percent: Decimal::from_str("1.01").unwrap()
        },
        err
    );
    // Try updating config with invalid owner, show throw unauthoritzed error
    let lp_fee_percent = Decimal::from_str("0.21").unwrap();
    let protocol_fee_percent = Decimal::from_str("0.09").unwrap();
    let msg = ExecuteMsg::UpdateConfig {
        owner: Some(owner.to_string()),
        protocol_fee_recipient: owner.to_string(),
        lp_fee_percent,
        protocol_fee_percent,
    };
    let err = router
        .execute_contract(
            Addr::unchecked("invalid_owner"),
            amm_addr.clone(),
            &msg,
            &[],
        )
        .unwrap_err()
        .downcast()
        .unwrap();
    assert_eq!(ContractError::Unauthorized {}, err);
    // Try updating owner and fee params
    let msg = ExecuteMsg::UpdateConfig {
        owner: Some("new_owner".to_string()),
        protocol_fee_recipient: owner.to_string(),
        lp_fee_percent,
        protocol_fee_percent,
    };
    let _res = router
        .execute_contract(owner.clone(), amm_addr.clone(), &msg, &[])
        .unwrap();
    let fee = get_fee(&router, &amm_addr);
    assert_eq!(fee.protocol_fee_recipient, owner.to_string());
    assert_eq!(fee.protocol_fee_percent, protocol_fee_percent);
    assert_eq!(fee.lp_fee_percent, lp_fee_percent);
    assert_eq!(fee.owner.unwrap(), "new_owner".to_string());
}
#[test]
fn test_pass_through_swap() {
    let mut router = mock_app();
    const NATIVE_TOKEN_DENOM: &str = "juno";
    let owner = Addr::unchecked("owner");
    let funds = coins(2000, NATIVE_TOKEN_DENOM);
    router.borrow_mut().init_modules(|router, _, storage| {
        router.bank.init_balance(storage, &owner, funds).unwrap()
    });
    let token1 = create_cw20(
        &mut router,
        &owner,
        "token1".to_string(),
        "TOKENONE".to_string(),
        Uint128::new(5000),
    );
    let token2 = create_cw20(
        &mut router,
        &owner,
        "token2".to_string(),
        "TOKENTWO".to_string(),
        Uint128::new(5000),
    );
    let lp_fee_percent = Decimal::from_str("0.03").unwrap();
    let protocol_fee_percent = Decimal::zero();
    let amm = create_amm(
        &mut router,
        &owner,
        Denom::Cw20(token1.addr()),
        Denom::Cw20(token2.addr()),
        lp_fee_percent,
        protocol_fee_percent,
        owner.to_string(),
    );
    // Add initial liquidity to both pools
    let allowance_msg = Cw20ExecuteMsg::IncreaseAllowance {
        spender: amm.to_string(),
        amount: Uint128::new(100),
        expires: None,
    };
    let _res = router
        .execute_contract(owner.clone(), token1.addr(), &allowance_msg, &[])
        .unwrap();
    let _res = router
        .execute_contract(owner.clone(), token2.addr(), &allowance_msg, &[])
        .unwrap();
    let add_liquidity_msg = ExecuteMsg::AddLiquidity {
        token1_amount: Uint128::new(100),
        min_liquidity: Uint128::new(100),
        token2_amount: Uint128::new(100),
        expiration: None,
    };
    router
        .execute_contract(
            owner.clone(),
            amm.clone(),
            &add_liquidity_msg,
            &[Coin {
                denom: NATIVE_TOKEN_DENOM.into(),
                amount: Uint128::zero(),
            }],
        )
        .unwrap();
    // Swap token1 for token2
    let allowance_msg = Cw20ExecuteMsg::IncreaseAllowance {
        spender: amm.to_string(),
        amount: Uint128::new(10),
        expires: None,
    };
    let _res = router
        .execute_contract(owner.clone(), token1.addr(), &allowance_msg, &[])
        .unwrap();
    let swap_msg = ExecuteMsg::Swap {
        input_token: TokenSelect::Token1,
        input_amount: Uint128::new(10),
        min_output: Uint128::new(8),
        expiration: None,
    };
    let _res = router
        .execute_contract(owner.clone(), amm.clone(), &swap_msg, &[])
        .unwrap();
    // ensure balances updated
    let token1_balance = token1.balance(&router, owner.clone()).unwrap();
    assert_eq!(token1_balance, Uint128::new(4890));
    let token2_balance = token2.balance(&router, owner.clone()).unwrap();
    assert_eq!(token2_balance, Uint128::new(4909));
    let amm_native_balance = bank_balance(&mut router, &amm, NATIVE_TOKEN_DENOM.to_string());
    assert_eq!(amm_native_balance.amount, Uint128::zero());
    // assert internal state is consistent
    let info_amm: InfoResponse = get_info(&router, &amm);
    println!("{:?}", info_amm);
    let token1_balance = token1.balance(&router, amm.clone()).unwrap();
    let token2_balance = token2.balance(&router, amm.clone()).unwrap();
    println!("{} {}", token1_balance, token2_balance);
    assert_eq!(info_amm.token2_reserve, token2_balance);
    assert_eq!(info_amm.token1_reserve, token1_balance);
}

contract.rs

use cosmwasm_std::{
    attr, entry_point, to_binary, Addr, Binary, BlockInfo, CosmosMsg, Decimal, Deps, DepsMut,
    Env, MessageInfo, Response, StdError, StdResult, Uint128, Uint256, Uint512,
    WasmMsg,
};
use cw2::set_contract_version;
use cw20::Denom::Cw20;
use cw20::{Cw20ExecuteMsg, Denom, Expiration};
use cw20_base::contract::query_balance;
use std::convert::TryInto;
use std::str::FromStr;
use crate::error::ContractError;
use crate::msg::{
    ExecuteMsg, FeeResponse, InfoResponse, InstantiateMsg, QueryMsg, Token1ForToken2PriceResponse,
    Token2ForToken1PriceResponse, TokenSelect,
};
use crate::state::{Fees, Token, FEES, FROZEN, OWNER, TOKEN1, TOKEN2};
// Version info for migration info
pub const CONTRACT_NAME: &str = "crates.io:product-amm";
pub const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
const FEE_SCALE_FACTOR: Uint128 = Uint128::new(10_000);
const MAX_FEE_PERCENT: &str = "1";
const FEE_DECIMAL_PRECISION: Uint128 = Uint128::new(10u128.pow(20));
// Note, you can use StdResult in some functions where you do not
// make use of the custom errors
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn instantiate(
    deps: DepsMut,
    _env: Env,
    _info: MessageInfo,
    msg: InstantiateMsg,
) -> Result<Response, ContractError> {
    set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
    let token1 = Token {
        reserve: Uint128::zero(),
        denom: msg.token1_denom.clone(),
    };
    TOKEN1.save(deps.storage, &token1)?;
    let token2 = Token {
        denom: msg.token2_denom.clone(),
        reserve: Uint128::zero(),
    };
    TOKEN2.save(deps.storage, &token2)?;
    let owner = msg.owner.map(|h| deps.api.addr_validate(&h)).transpose()?;
    OWNER.save(deps.storage, &owner)?;
    let protocol_fee_recipient = deps.api.addr_validate(&msg.protocol_fee_recipient)?;
    let total_fee_percent = msg.lp_fee_percent + msg.protocol_fee_percent;
    let max_fee_percent = Decimal::from_str(MAX_FEE_PERCENT)?;
    if total_fee_percent > max_fee_percent {
        return Err(ContractError::FeesTooHigh {
            max_fee_percent,
            total_fee_percent,
        });
    }
    let fees = Fees {
        lp_fee_percent: msg.lp_fee_percent,
        protocol_fee_percent: msg.protocol_fee_percent,
        protocol_fee_recipient,
    };
    FEES.save(deps.storage, &fees)?;
    // Depositing is not frozen by default
    FROZEN.save(deps.storage, &false)?;
    
    Ok(Response::new().add_attribute("key", "instantiate"))
}
// And declare a custom Error variant for the ones where you will want to make use of it
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    msg: ExecuteMsg,
) -> Result<Response, ContractError> {
    match msg {
        ExecuteMsg::AddLiquidity {
            token1_amount,
            min_liquidity,
            expiration, token2_amount } => {
            if FROZEN.load(deps.storage)? {
                return Err(ContractError::FrozenPool {});
            }
            execute_add_liquidity(
                deps,
                &info,
                env,
                min_liquidity,
                token1_amount,
                token2_amount,
                expiration,
            )
        }
        ExecuteMsg::RemoveLiquidity {
            amount,
            min_token1,
            min_token2,
            expiration,
        } => execute_remove_liquidity(deps, info, env, amount, min_token1, min_token2, expiration),
        ExecuteMsg::Swap {
            input_token,
            input_amount,
            min_output,
            expiration,
            ..
        } => {
            if FROZEN.load(deps.storage)? {
                return Err(ContractError::FrozenPool {});
            }
            execute_swap(
                deps,
                &info,
                input_amount,
                env,
                input_token,
                info.sender.to_string(),
                min_output,
                expiration,
            )
        }
        ExecuteMsg::UpdateConfig {
            owner,
            protocol_fee_recipient,
            lp_fee_percent,
            protocol_fee_percent,
        } => execute_update_config(
            deps,
            info,
            owner,
            lp_fee_percent,
            protocol_fee_percent,
            protocol_fee_recipient,
        ),
        ExecuteMsg::FreezeDeposits { freeze } => execute_freeze_deposits(deps, info.sender, freeze),
    }
}
fn execute_freeze_deposits(
    deps: DepsMut,
    sender: Addr,
    freeze: bool,
) -> Result<Response, ContractError> {
    if let Some(owner) = OWNER.load(deps.storage)? {
        if sender != owner {
            return Err(ContractError::UnauthorizedPoolFreeze {});
        }
    } else {
        return Err(ContractError::UnauthorizedPoolFreeze {});
    }
    FROZEN.save(deps.storage, &freeze)?;
    Ok(Response::new().add_attribute("action", "freezing-contracts"))
}
fn check_expiration(
    expiration: &Option<Expiration>,
    block: &BlockInfo,
) -> Result<(), ContractError> {
    match expiration {
        Some(e) => {
            if e.is_expired(block) {
                return Err(ContractError::MsgExpirationError {});
            }
            Ok(())
        }
        None => Ok(()),
    }
}
pub fn execute_add_liquidity(
    deps: DepsMut,
    info: &MessageInfo,
    env: Env,
    min_liquidity: Uint128,
    token1_amount: Uint128,
    token2_amount: Uint128,
    expiration: Option<Expiration>,
) -> Result<Response, ContractError> {
    check_expiration(&expiration, &env.block)?;
    let token1 = TOKEN1.load(deps.storage)?;
    let token2 = TOKEN2.load(deps.storage)?;
    let liquidity_amount = token1_amount+token2_amount;
    if liquidity_amount < min_liquidity {
        return Err(ContractError::MinLiquidityError {
            min_liquidity,
            liquidity_available: liquidity_amount,
        });
    }
    // Generate cw20 transfer messages if necessary
    let mut transfer_msgs: Vec<CosmosMsg> = vec![];
    if let Cw20(addr) = token1.denom {
        transfer_msgs.push(get_cw20_transfer_from_msg(
            &info.sender,
            &env.contract.address,
            &addr,
            token1_amount,
        )?)
    }
    if let Cw20(addr) = token2.denom.clone() {
        transfer_msgs.push(get_cw20_transfer_from_msg(
            &info.sender,
            &env.contract.address,
            &addr,
            token2_amount,
        )?)
    }
    TOKEN1.update(deps.storage, |mut token1| -> Result<_, ContractError> {
        token1.reserve += token1_amount;
        Ok(token1)
    })?;
    TOKEN2.update(deps.storage, |mut token2| -> Result<_, ContractError> {
        token2.reserve += token2_amount;
        Ok(token2)
    })?;
    Ok(Response::new()
        .add_messages(transfer_msgs)
        .add_attributes(vec![
            attr("token1_amount", token1_amount),
            attr("token2_amount", token2_amount),
            attr("liquidity_received", liquidity_amount),
        ]))
}
fn get_cw20_transfer_from_msg(
    owner: &Addr,
    recipient: &Addr,
    token_addr: &Addr,
    token_amount: Uint128,
) -> StdResult<CosmosMsg> {
    // create transfer cw20 msg
    let transfer_cw20_msg = Cw20ExecuteMsg::TransferFrom {
        owner: owner.into(),
        recipient: recipient.into(),
        amount: token_amount,
    };
    let exec_cw20_transfer = WasmMsg::Execute {
        contract_addr: token_addr.into(),
        msg: to_binary(&transfer_cw20_msg)?,
        funds: vec![],
    };
    let cw20_transfer_cosmos_msg: CosmosMsg = exec_cw20_transfer.into();
    Ok(cw20_transfer_cosmos_msg)
}
pub fn execute_update_config(
    deps: DepsMut,
    info: MessageInfo,
    new_owner: Option<String>,
    lp_fee_percent: Decimal,
    protocol_fee_percent: Decimal,
    protocol_fee_recipient: String,
) -> Result<Response, ContractError> {
    let owner = OWNER.load(deps.storage)?;
    if Some(info.sender) != owner {
        return Err(ContractError::Unauthorized {});
    }
    let new_owner_addr = new_owner
        .as_ref()
        .map(|h| deps.api.addr_validate(h))
        .transpose()?;
    OWNER.save(deps.storage, &new_owner_addr)?;
    let total_fee_percent = lp_fee_percent + protocol_fee_percent;
    let max_fee_percent = Decimal::from_str(MAX_FEE_PERCENT)?;
    if total_fee_percent > max_fee_percent {
        return Err(ContractError::FeesTooHigh {
            max_fee_percent,
            total_fee_percent,
        });
    }
    let protocol_fee_recipient = deps.api.addr_validate(&protocol_fee_recipient)?;
    let updated_fees = Fees {
        protocol_fee_recipient: protocol_fee_recipient.clone(),
        lp_fee_percent,
        protocol_fee_percent,
    };
    FEES.save(deps.storage, &updated_fees)?;
    let new_owner = new_owner.unwrap_or_default();
    Ok(Response::new().add_attributes(vec![
        attr("new_owner", new_owner),
        attr("lp_fee_percent", lp_fee_percent.to_string()),
        attr("protocol_fee_percent", protocol_fee_percent.to_string()),
        attr("protocol_fee_recipient", protocol_fee_recipient.to_string()),
    ]))
}
pub fn execute_remove_liquidity(
    deps: DepsMut,
    info: MessageInfo,
    env: Env,
    amount: Uint128,
    min_token1: Uint128,
    min_token2: Uint128,
    expiration: Option<Expiration>,
) -> Result<Response, ContractError> {
    check_expiration(&expiration, &env.block)?;
    let token1 = TOKEN1.load(deps.storage)?;
    let token2 = TOKEN2.load(deps.storage)?;
    let total_token_supply = token1.reserve+token2.reserve;
    if amount > total_token_supply {
        return Err(ContractError::InsufficientLiquidityError {
            requested: amount,
            available: total_token_supply,
        });
    }
    let token1_amount = amount
        .checked_mul(token1.reserve)
        .map_err(StdError::overflow)?
        .checked_div(total_token_supply)
        .map_err(StdError::divide_by_zero)?;
    if token1_amount < min_token1 {
        return Err(ContractError::MinToken1Error {
            requested: min_token1,
            available: token1_amount,
        });
    }
    let token2_amount = amount
        .checked_mul(token2.reserve)
        .map_err(StdError::overflow)?
        .checked_div(total_token_supply)
        .map_err(StdError::divide_by_zero)?;
    if token2_amount < min_token2 {
        return Err(ContractError::MinToken2Error {
            requested: min_token2,
            available: token2_amount,
        });
    }
    TOKEN1.update(deps.storage, |mut token1| -> Result<_, ContractError> {
        token1.reserve = token1
            .reserve
            .checked_sub(token1_amount)
            .map_err(StdError::overflow)?;
        Ok(token1)
    })?;
    TOKEN2.update(deps.storage, |mut token2| -> Result<_, ContractError> {
        token2.reserve = token2
            .reserve
            .checked_sub(token2_amount)
            .map_err(StdError::overflow)?;
        Ok(token2)
    })?;
    let token1_transfer_msg = match token1.denom {
        Denom::Cw20(addr) => get_cw20_transfer_to_msg(&info.sender, &addr, token1_amount)?,
        Denom::Native(_denom) => {unimplemented!()},
    };
    let token2_transfer_msg = match token2.denom {
        Denom::Cw20(addr) => get_cw20_transfer_to_msg(&info.sender, &addr, token2_amount)?,
        Denom::Native(_denom) => {unimplemented!()},
    };
    Ok(Response::new()
        .add_messages(vec![
            token1_transfer_msg,
            token2_transfer_msg,
        ])
        .add_attributes(vec![
            attr("liquidity_burned", amount),
            attr("token1_returned", token1_amount),
            attr("token2_returned", token2_amount),
        ]))
}
fn get_cw20_transfer_to_msg(
    recipient: &Addr,
    token_addr: &Addr,
    token_amount: Uint128,
) -> StdResult<CosmosMsg> {
    // create transfer cw20 msg
    let transfer_cw20_msg = Cw20ExecuteMsg::Transfer {
        recipient: recipient.into(),
        amount: token_amount,
    };
    let exec_cw20_transfer = WasmMsg::Execute {
        contract_addr: token_addr.into(),
        msg: to_binary(&transfer_cw20_msg)?,
        funds: vec![],
    };
    let cw20_transfer_cosmos_msg: CosmosMsg = exec_cw20_transfer.into();
    Ok(cw20_transfer_cosmos_msg)
}
fn get_fee_transfer_msg(
    sender: &Addr,
    recipient: &Addr,
    fee_denom: &Denom,
    amount: Uint128,
) -> StdResult<CosmosMsg> {
    match fee_denom {
        Denom::Cw20(addr) => get_cw20_transfer_from_msg(sender, recipient, addr, amount),
        Denom::Native(_denom) => {unimplemented!()},
    }
}
fn fee_decimal_to_uint128(decimal: Decimal) -> StdResult<Uint128> {
    let result: Uint128 = decimal
        .atomics()
        .checked_mul(FEE_SCALE_FACTOR)
        .map_err(StdError::overflow)?;
    Ok(result / FEE_DECIMAL_PRECISION)
}
fn get_input_price(
    input_amount: Uint128,
    input_reserve: Uint128,
    output_reserve: Uint128,
    fee_percent: Decimal,
) -> StdResult<Uint128> {
    if input_reserve == Uint128::zero() || output_reserve == Uint128::zero() {
        return Err(StdError::generic_err("No liquidity"));
    };
    let fee_percent = fee_decimal_to_uint128(fee_percent)?;
    let fee_reduction_percent = FEE_SCALE_FACTOR - fee_percent;
    let input_amount_with_fee = Uint512::from(input_amount.full_mul(fee_reduction_percent));
    let numerator = input_amount_with_fee
        .checked_mul(Uint512::from(output_reserve))
        .map_err(StdError::overflow)?;
    let denominator = Uint512::from(input_reserve)
        .checked_mul(Uint512::from(FEE_SCALE_FACTOR))
        .map_err(StdError::overflow)?
        .checked_add(input_amount_with_fee)
        .map_err(StdError::overflow)?;
    Ok(numerator
        .checked_div(denominator)
        .map_err(StdError::divide_by_zero)?
        .try_into()?)
}
fn get_protocol_fee_amount(input_amount: Uint128, fee_percent: Decimal) -> StdResult<Uint128> {
    if fee_percent.is_zero() {
        return Ok(Uint128::zero());
    }
    let fee_percent = fee_decimal_to_uint128(fee_percent)?;
    Ok(input_amount
        .full_mul(fee_percent)
        .checked_div(Uint256::from(FEE_SCALE_FACTOR))
        .map_err(StdError::divide_by_zero)?
        .try_into()?)
}
#[allow(clippy::too_many_arguments)]
pub fn execute_swap(
    deps: DepsMut,
    info: &MessageInfo,
    input_amount: Uint128,
    _env: Env,
    input_token_enum: TokenSelect,
    recipient: String,
    min_token: Uint128,
    expiration: Option<Expiration>,
) -> Result<Response, ContractError> {
    check_expiration(&expiration, &_env.block)?;
    let input_token_item = match input_token_enum {
        TokenSelect::Token1 => TOKEN1,
        TokenSelect::Token2 => TOKEN2,
    };
    let input_token = input_token_item.load(deps.storage)?;
    let output_token_item = match input_token_enum {
        TokenSelect::Token1 => TOKEN2,
        TokenSelect::Token2 => TOKEN1,
    };
    let output_token = output_token_item.load(deps.storage)?;
    let fees = FEES.load(deps.storage)?;
    let total_fee_percent = fees.lp_fee_percent + fees.protocol_fee_percent;
    let token_bought = get_input_price(
        input_amount,
        input_token.reserve,
        output_token.reserve,
        total_fee_percent,
    )?;
    if min_token > token_bought {
        return Err(ContractError::SwapMinError {
            min: min_token,
            available: token_bought,
        });
    }
    // Calculate fees
    let protocol_fee_amount = get_protocol_fee_amount(input_amount, fees.protocol_fee_percent)?;
    let input_amount_minus_protocol_fee = input_amount - protocol_fee_amount;
    let mut msgs = match input_token.denom.clone() {
        Denom::Cw20(addr) => vec![get_cw20_transfer_from_msg(
            &info.sender,
            &_env.contract.address,
            &addr,
            input_amount_minus_protocol_fee,
        )?],
        Denom::Native(_) => vec![],
    };
    // Send protocol fee to protocol fee recipient
    if !protocol_fee_amount.is_zero() {
        msgs.push(get_fee_transfer_msg(
            &info.sender,
            &fees.protocol_fee_recipient,
            &input_token.denom,
            protocol_fee_amount,
        )?)
    }
    let recipient = deps.api.addr_validate(&recipient)?;
    // Create transfer to message
    msgs.push(match output_token.denom {
        Denom::Cw20(addr) => get_cw20_transfer_to_msg(&recipient, &addr, token_bought)?,
        Denom::Native(_denom) => {unimplemented!()},
    });
    input_token_item.update(
        deps.storage,
        |mut input_token| -> Result<_, ContractError> {
            input_token.reserve = input_token
                .reserve
                .checked_add(input_amount_minus_protocol_fee)
                .map_err(StdError::overflow)?;
            Ok(input_token)
        },
    )?;
    output_token_item.update(
        deps.storage,
        |mut output_token| -> Result<_, ContractError> {
            output_token.reserve = output_token
                .reserve
                .checked_sub(token_bought)
                .map_err(StdError::overflow)?;
            Ok(output_token)
        },
    )?;
    Ok(Response::new().add_messages(msgs).add_attributes(vec![
        attr("native_sold", input_amount),
        attr("token_bought", token_bought),
    ]))
}
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
    match msg {
        QueryMsg::Balance { address } => to_binary(&query_balance(deps, address)?),
        QueryMsg::Info {} => to_binary(&query_info(deps)?),
        QueryMsg::Token1ForToken2Price { token1_amount } => {
            to_binary(&query_token1_for_token2_price(deps, token1_amount)?)
        }
        QueryMsg::Token2ForToken1Price { token2_amount } => {
            to_binary(&query_token2_for_token1_price(deps, token2_amount)?)
        }
        QueryMsg::Fee {} => to_binary(&query_fee(deps)?),
    }
}
pub fn query_info(deps: Deps) -> StdResult<InfoResponse> {
    let token1 = TOKEN1.load(deps.storage)?;
    let token2 = TOKEN2.load(deps.storage)?;
  
    // TODO get total supply
    Ok(InfoResponse {
        token1_reserve: token1.reserve,
        token1_denom: token1.denom,
        token2_reserve: token2.reserve,
        token2_denom: token2.denom,
       
    })
}
pub fn query_token1_for_token2_price(
    deps: Deps,
    token1_amount: Uint128,
) -> StdResult<Token1ForToken2PriceResponse> {
    let token1 = TOKEN1.load(deps.storage)?;
    let token2 = TOKEN2.load(deps.storage)?;
    let fees = FEES.load(deps.storage)?;
    let total_fee_percent = fees.lp_fee_percent + fees.protocol_fee_percent;
    let token2_amount = get_input_price(
        token1_amount,
        token1.reserve,
        token2.reserve,
        total_fee_percent,
    )?;
    Ok(Token1ForToken2PriceResponse { token2_amount })
}
pub fn query_token2_for_token1_price(
    deps: Deps,
    token2_amount: Uint128,
) -> StdResult<Token2ForToken1PriceResponse> {
    let token1 = TOKEN1.load(deps.storage)?;
    let token2 = TOKEN2.load(deps.storage)?;
    let fees = FEES.load(deps.storage)?;
    let total_fee_percent = fees.lp_fee_percent + fees.protocol_fee_percent;
    let token1_amount = get_input_price(
        token2_amount,
        token2.reserve,
        token1.reserve,
        total_fee_percent,
    )?;
    Ok(Token2ForToken1PriceResponse { token1_amount })
}
pub fn query_fee(deps: Deps) -> StdResult<FeeResponse> {
    let fees = FEES.load(deps.storage)?;
    let owner = OWNER.load(deps.storage)?.map(|o| o.into_string());
    Ok(FeeResponse {
        owner,
        lp_fee_percent: fees.lp_fee_percent,
        protocol_fee_percent: fees.protocol_fee_percent,
        protocol_fee_recipient: fees.protocol_fee_recipient.into_string(),
    })
}
#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_get_input_price() {
        let fee_percent = Decimal::from_str("0.03").unwrap();
        // Base case
        assert_eq!(
            get_input_price(
                Uint128::new(10),
                Uint128::new(100),
                Uint128::new(100),
                fee_percent
            )
            .unwrap(),
            Uint128::new(9)
        );
        // No input reserve error
        let err = get_input_price(
            Uint128::new(10),
            Uint128::new(0),
            Uint128::new(100),
            fee_percent,
        )
        .unwrap_err();
        assert_eq!(err, StdError::generic_err("No liquidity"));
        // No output reserve error
        let err = get_input_price(
            Uint128::new(10),
            Uint128::new(100),
            Uint128::new(0),
            fee_percent,
        )
        .unwrap_err();
        assert_eq!(err, StdError::generic_err("No liquidity"));
        // No reserve error
        let err = get_input_price(
            Uint128::new(10),
            Uint128::new(0),
            Uint128::new(0),
            fee_percent,
        )
        .unwrap_err();
        assert_eq!(err, StdError::generic_err("No liquidity"));
    }
}

msg.rs

use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use cosmwasm_std::{Decimal, Uint128};
use cw20::{Denom, Expiration};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct InstantiateMsg {
    pub token1_denom: Denom,
    pub token2_denom: Denom,
    pub owner: Option<String>,
    pub protocol_fee_recipient: String,
    // NOTE: Fees percents are out of 100 e.g., 1 = 1%
    pub protocol_fee_percent: Decimal,
    pub lp_fee_percent: Decimal,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub enum TokenSelect {
    Token1,
    Token2,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
    AddLiquidity {
        token1_amount: Uint128,
        token2_amount: Uint128,
        min_liquidity: Uint128,
        expiration: Option<Expiration>,
    },
    RemoveLiquidity {
        amount: Uint128,
        min_token1: Uint128,
        min_token2: Uint128,
        expiration: Option<Expiration>,
    },
    Swap {
        input_token: TokenSelect,
        input_amount: Uint128,
        min_output: Uint128,
        expiration: Option<Expiration>,
    },
    UpdateConfig {
        owner: Option<String>,
        lp_fee_percent: Decimal,
        protocol_fee_percent: Decimal,
        protocol_fee_recipient: String,
    },
    // Freeze adding new deposits
    FreezeDeposits {
        freeze: bool,
    },
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
    /// Implements CW20. Returns the current balance of the given address, 0 if unset.
    Balance {
        address: String,
    },
    Info {},
    Token1ForToken2Price {
        token1_amount: Uint128,
    },
    Token2ForToken1Price {
        token2_amount: Uint128,
    },
    Fee {},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct MigrateMsg {
    pub owner: Option<String>,
    pub protocol_fee_recipient: String,
    pub protocol_fee_percent: Decimal,
    pub lp_fee_percent: Decimal,
    pub freeze_pool: bool,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct InfoResponse {
    pub token1_reserve: Uint128,
    pub token1_denom: Denom,
    pub token2_reserve: Uint128,
    pub token2_denom: Denom,
}
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, JsonSchema)]
pub struct FeeResponse {
    pub owner: Option<String>,
    pub lp_fee_percent: Decimal,
    pub protocol_fee_percent: Decimal,
    pub protocol_fee_recipient: String,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct Token1ForToken2PriceResponse {
    pub token2_amount: Uint128,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct Token2ForToken1PriceResponse {
    pub token1_amount: Uint128,
}

error.rs

use cosmwasm_std::{Decimal, StdError, Uint128};
use thiserror::Error;
#[derive(Error, Debug, PartialEq)]
pub enum ContractError {
    #[error("{0}")]
    Std(#[from] StdError),
    #[error("{0}")]
    Cw20Error(#[from] cw20_base::ContractError),
    #[error("None Error")]
    NoneError {},
    #[error("Unauthorized")]
    Unauthorized {},
    // Add any other custom errors you like here.
    // Look at https://docs.rs/thiserror/1.0.21/thiserror/ for details.
    #[error("Min liquidity error: requested: {min_liquidity}, available: {liquidity_available}")]
    MinLiquidityError {
        min_liquidity: Uint128,
        liquidity_available: Uint128,
    },
    #[error("Max token error: max_token: {max_token}, tokens_required: {tokens_required}")]
    MaxTokenError {
        max_token: Uint128,
        tokens_required: Uint128,
    },
    #[error("Insufficient liquidity error: requested: {requested}, available: {available}")]
    InsufficientLiquidityError {
        requested: Uint128,
        available: Uint128,
    },
    #[error("Min token1 error: requested: {requested}, available: {available}")]
    MinToken1Error {
        requested: Uint128,
        available: Uint128,
    },
    #[error("Min token2 error: requested: {requested}, available: {available}")]
    MinToken2Error {
        requested: Uint128,
        available: Uint128,
    },
    #[error("Incorrect native denom: provided: {provided}, required: {required}")]
    IncorrectNativeDenom { provided: String, required: String },
    #[error("Swap min error: min: {min}, available: {available}")]
    SwapMinError { min: Uint128, available: Uint128 },
    #[error("MsgExpirationError")]
    MsgExpirationError {},
    #[error("Total fee ({total_fee_percent}) percent is higher than max ({max_fee_percent})")]
    FeesTooHigh {
        max_fee_percent: Decimal,
        total_fee_percent: Decimal,
    },
    #[error("InsufficientFunds")]
    InsufficientFunds {},
    #[error("Uknown reply id: {id}")]
    UnknownReplyId { id: u64 },
    #[error("Failed to instantiate lp token")]
    InstantiateLpTokenError {},
    #[error("The output amm provided is invalid")]
    InvalidOutputPool {},
    #[error("Unauthorized pool freeze - sender is not an owner or owner has not been set")]
    UnauthorizedPoolFreeze {},
    #[error("This pools is frozen - you can not deposit or swap tokens")]
    FrozenPool {},
}

state.rs

use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use cosmwasm_std::{Addr, Decimal, Uint128};
use cw20::Denom;
use cw_storage_plus::Item;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct Token {
    pub reserve: Uint128,
    pub denom: Denom,
}
pub const TOKEN1: Item<Token> = Item::new("token1");
pub const TOKEN2: Item<Token> = Item::new("token2");
pub const OWNER: Item<Option<Addr>> = Item::new("owner");
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct Fees {
    pub protocol_fee_recipient: Addr,
    pub protocol_fee_percent: Decimal,
    pub lp_fee_percent: Decimal,
}
pub const FEES: Item<Fees> = Item::new("fees");
pub const FROZEN: Item<bool> = Item::new("frozen");
PreviousToken VaultsNextGuia Celestia

Last updated 1 year ago

馃懡
馃帗