¿Qué tipo de parámetro debo usar para los métodos de contrato que especifican montos de punto flotante?

En mi dApp, el usuario establece la tarifa de entrada para el juego que está creando. La tarifa de entrada para los juegos suele oscilar entre $ 5 USD y $ 50 USD. ¿Qué unidad debo usar para el método de contrato que acepta el pago del juego (es decir, el tipo para introducir el parámetro de método relevante)? ¿Debo usar: wei, gwei, eth, etc.?

Además, ¿qué tipo de solidez debo usar internamente en mi contrato que haga una buena cantidad de cálculos numéricos cuando llegue el momento de pagar a los jugadores? ¿Supongo que un tipo de punto fijo como uint* no encaja bien? Estoy haciendo esta pregunta tanto para el almacenamiento como para las variables de memoria.

Supongo que para los porcentajes solo puedo usar uint y dividir por 100 internamente. Pero estoy haciendo las preguntas anteriores para los parámetros que recibirán números de punto flotante en general.

Es razonable usar un número fijo de decimales (como 10^18wei siendo 1éter), o puede usar un número racional explícito con un numerador y un denominador separados (por ejemplo, (7, 100)significa 0.07). Este último es el enfoque adoptado aquí: programtheblockchain.com/posts/2018/02/27/… .
Para su primera pregunta, probablemente quiera aceptar una cantidad en wei, y el tipo apropiado para el parámetro es uint256.
@smarx Gracias. Ahora todo lo que tengo que hacer es encontrar una API confiable que me dé una cotización en USD para Eth, y otra para convertir entre una moneda fiduciaria y otra para poder mostrarle al usuario un valor monetario amigable.

Respuestas (3)

En mi opinión, es preferible adaptarse al uso de números enteros de EVM cuando sea posible. Casi siempre es posible.

Por ejemplo, aquí hay un patrón simple para manejar un porcentaje con dos números enteros de alta precisión (uno podría ser un tipo de cambio y el otro un volumen de transacciones). Primero, convierta cada entrada a un entero de 18 decimales. Entonces 1.0 sería 1 * 10 ** 18. 87% es 0.870,000,000,000,000,000, o como un número entero 870000000000000000.

Cuando multiplicas dos enteros grandes, obtienes un entero aún mayor, ya que (10 ** 18) * (10 ** 18) es 10 ** 36. Tendrás los dígitos significativos correctos y solo necesitas ajustar la posición decimal para interpretación correcta .

Considere este patrón:

pragma solidity ^0.6.6;

contract Precision {
    
    uint constant PRECISION = 10 ** 18;
    uint constant demonstrateRatio = 87 * 10 ** 16;
    
    function percentOf(uint baseValue) public pure returns(uint result) {
        return ( baseValue * demonstrateRatio ) / PRECISION;
    }
}

Consejo: Siempre multiplique antes de dividir para evitar la pérdida de precisión.

Por ejemplo, reescribe lo siguiente:

x = ( a / b ) * PRECISION

como

x = ( a * PRECISION ) / b

Esto se debe a que 100/200 = 0 (con truncamiento) y 0 * PRECISIÓN = 0. Por otro lado, (100 * PRECISIÓN) / 200 da un resultado distinto de cero que se puede devolver después de ajustar la posición decimal con / PRECISION.

Si desea un redondeo correcto, puede agregar 5 al denominador antes de dividir, lo que redondeará (correctamente) o truncará el resultado (correctamente).

x = ( a * PRECISION + 5 ) / b

Espero eso ayude.

Solidity no admite variables de punto flotante porque es más difícil ser determinista con ellas y no son las más seguras. La versión más común de decimales es tener un uint que no es un solo ETH o USD, sino 1/10^18 de uno.

Puede usar la biblioteca ABDK Math 64.64 . Opera con números binarios de punto fijo (64 dígitos binarios después del punto) y contiene todas las operaciones matemáticas básicas. Utiliza int128el tipo para representar el número de punto fijo.