En un artículo anterior , analizamos varios casos de uso de cuentas inteligentes en los negocios, incluidas subastas y programas de fidelización.
Hoy hablaremos sobre cómo las cuentas inteligentes y los activos inteligentes pueden aumentar la transparencia y la confiabilidad de los instrumentos financieros, como opciones, futuros y facturas.
OpcionUna opción es un contrato de bolsa que le da al comprador el derecho de comprar un activo a un precio determinado o antes de una fecha determinada, pero sin obligarlo a hacerlo.
El ejercicio de la opción puede ser el siguiente:
Utilizamos un activo inteligente para las opciones en sí mismas como una herramienta y una cuenta inteligente para el participante que actúa como el intercambio y emite opciones. El participante en el intercambio promete que venderá una cierta cantidad de un determinado activo al precio de venta Precio entre las alturas de los bloques Inicio de vencimiento y Fin de vencimiento).
En el código del activo inteligente, simplemente verificamos que se comercialice solo entre las alturas indicadas, y no verificaremos nada más, dejaremos toda responsabilidad de observar las reglas al código del participante del intercambio.
Código de activo inteligente:let expirationStart = 100000 let expirationEnd = 101440 match tx { case some : ExchangeTransaction | TransferTransaction => height > expirationStart && height <= expirationEnd case _ => false }
Suponemos que las acciones son las siguientes: el miembro de intercambio vende opciones para la compra de algún activo, y el resto de los participantes pueden transferir estas opciones o intercambiarlas. Para ejercer su derecho de compra, un comprador potencial debe transferir el número deseado de opciones a la cuenta del vendedor, es decir, el participante del intercambio. Luego escribe información sobre la transferencia completada al estado de cuenta del miembro de intercambio y solo entonces ExchangeTransaction podrá pasar por las condiciones especificadas de compra y venta.
En el código de la cuenta inteligente, debemos asegurarnos de que cualquier ExchangeTransaction que pase por ella para el acto final de compra y venta cumpla con las condiciones especificadas, y el participante compre exactamente el número de unidades que envió a la cuenta del participante en el intercambio. Un comprador potencial debe enviar la DataTransaction correcta sobre la transferencia que ocurrió, para que el miembro de intercambio pueda evitar el doble gasto. En esta DataTransaction, el comprador pone una clave igual a su dirección, un valor igual al número de opciones transferidas a la cuenta del miembro de intercambio, es decir, el número de unidades de activos que puede comprar.Código de cuenta inteligente: # # sellPrice expirationStart expirationEnd let expirationStart = 100000 let expirationEnd = 101440 let sellPrice = 10000 let amountAsset = base58'8jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf' let priceAsset = base58'9jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf' #ID - let optionsAsset = base58'7jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf' # let this = extract(tx.sender) match tx { case dataTx : DataTransaction => # - (ID ) let units = extract(getInteger(dataTx.data, dataTx.data[0].key)) # - let e = transactionById(dataTx.proofs[2]) # match e { case transferTx : TransferTransaction => #, (transferTx.recipient == this) && #, ID dataTx.data[0].key == toBase58String(transferTx.sender.bytes) && sigVerify(dataTx.bodyBytes, dataTx.proofs[0], transferTx.senderPublicKey) && #, (units == transferTx.amount) && #, - (transferTx.assetId == optionsAsset) case _ => false } && size(dataTx.data) == 1 && !isDefined(getInteger(this, dataTx.data[0].key)) && height > expirationStart && height <= expirationEnd case order : Order => #, let correctAssetPair = order.assetPair.amountAsset == amountAsset && order.assetPair.priceAsset == priceAsset let correctPrice = order.price == sellPrice # - let d = transactionById(order.proofs[2]) match d{ case dataTx : DataTransaction => let buyOrderSender = dataTx.data[0].key toBase58String(order.sender.bytes) == buyOrderSender && order.amount == extract(getInteger(dataTx.data, buyOrderSender)) case _ => false } && order.sender == this && correctAssetPair && correctPrice && height > expirationStart && height <= expirationEnd case _ => false }
Futuros de cuentas inteligentesA diferencia de una opción, los futuros (contrato de futuros) no son un derecho, sino la obligación del comprador de comprar un activo a un precio fijo en un determinado momento en el futuro.
En general, la implementación de futuros es similar a la implementación de una opción. Aquí, un activo inteligente actúa como un futuro.
También debe asegurarse de que tanto el comprador como el vendedor firmen la orden de compra. Los futuros son una obligación que debe cumplirse en cualquier caso. Esto significa que si un vendedor o un participante rechaza sus obligaciones, cualquier participante de la red puede enviar una transacción, ejecutando así futuros.
Smart Asset Script controla todos los Futuros de Activos TransferTransaction y ExchangeTransaction, aprobándolos solo si el Miembro Comprador ha creado un pedido para la futura compra de Futuros de Activos del Miembro de Exchange.
Esta orden debe ser válida y satisfacer las condiciones en que se emiten los futuros. Para verificar un pedido, puede ingresar todos sus campos en el estado de la cuenta del comprador junto con la representación de bytes del pedido firmado y luego validar desde el exterior.
Por el momento, RIDE no contiene una función nativa para analizar bytes de transacción, pero incluye todas las herramientas necesarias para su implementación. Por lo tanto, los desarrolladores pueden intentar implementar esta característica por su cuenta.
Cuenta / fideicomiso con firma múltipleUna cuenta con una firma múltiple permite que varios usuarios administren activos de manera conjunta (por ejemplo, las transacciones con activos solo pueden ser posibles si tres de cada cuatro usuarios tienen firmas). Para crear cuentas con firma múltiple en el idioma RIDE, podemos usar pruebas de transacciones.
Una cuenta con una firma múltiple también se puede utilizar para una cuenta de depósito en garantía, en la que el dinero se almacena hasta que las partes del acuerdo cumplan con sus obligaciones.
let alicePubKey = base58'5AzfA9UfpWVYiwFwvdr77k6LWupSTGLb14b24oVdEpMM' let bobPubKey = base58'2KwU4vzdgPmKyf7q354H9kSyX9NZjNiq4qbnH2wi2VDF' let cooperPubKey = base58'GbrUeGaBfmyFJjSQb9Z8uTCej5GzjXfRDVGJGrmgt5cD' #, let aliceSigned = if(sigVerify(tx.bodyBytes, tx.proofs[0], alicePubKey)) then 1 else 0 let bobSigned = if(sigVerify(tx.bodyBytes, tx.proofs[1], bobPubKey)) then 1 else 0 let cooperSigned = if(sigVerify(tx.bodyBytes, tx.proofs[2], cooperPubKey)) then 1 else 0 # aliceSigned + bobSigned + cooperSigned >= 2
Registro gestionado por tokens (TCR)En muchas plataformas blockchain, hay un problema de activos tóxicos. Por ejemplo, cualquier dirección que haya pagado una comisión puede crear un activo en Waves.
El registro curado de tokens (TCR) generado por los titulares de tokens ayuda a resolver el problema de proteger a los usuarios y la cadena de bloques de los activos tóxicos.
Para votar por agregar un token específico a la lista, el titular hace una apuesta igual a su parte de tokens del número total de emitidos. Se incluye un token en el registro si la mayoría de sus titulares votaron por él.
En nuestro ejemplo, permitimos que el usuario agregue el token a la lista para su consideración (durante el período de "desafío") mediante la clave del estado key = asset_name, solo si el valor actual es count = 0.
Además, el usuario en la billetera debe tener un saldo distinto de cero de este token. Luego viene el período de votación durante el cual el usuario puede emitir un voto por cada activo en su billetera, pero solo una vez, otorgando una calificación de 1 a 10. Los votos de los usuarios están representados por claves de la forma user_address + assetID.
let asset = base58'8jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf' let addingStartHeight = 1000 let votingStartHeight = 2000 let votingEndHeight = 3000 let this = extract(tx.sender) # let address = addressFromPublicKey(tx.proofs[1]) match tx { case t: DataTransaction => if(height > addingStartHeight) then( if(height < votingStartHeight) then( #adding #, let hasTokens = assetBalance(address, asset) > 0 size(t.data) == 1 #, && !isDefined(getInteger(this, toBase58String(asset))) #, - 0 && extract(getInteger(t.data, toBase58String(asset))) == 0 && hasTokens ) else( if(height < votingEndHeight) then ( #voting # let currentAmount = extract(getInteger(this, toBase58String(asset))) let newAmount = extract(getInteger(t.data, toBase58String(asset))) let betString = toBase58String(address.bytes) + toBase58String(asset) #, let noBetBefore = !isDefined(getInteger(this, betString)) let isBetCorrect = extract(getInteger(t.data, betString)) > 0 && extract(getInteger(t.data, betString)) <= 10 #, let hasTokens = assetBalance(address, asset) > 0 # size(t.data) == 2 && isDefined(getInteger(this, toBase58String(asset))) && newAmount == currentAmount + 1 && noBetBefore && isBetCorrect && hasTokens ) else false ) && sigVerify(tx.bodyBytes, tx.proofs[0], tx.proofs[1]) ) else false case _ => false }
Cuota de suscripciónEn este ejemplo, consideraremos el uso de cuentas inteligentes para realizar pagos regulares por un producto o servicio a intervalos predeterminados, una "tarifa mensual".
Si un usuario proporciona una cuenta inteligente (a través de comprobantes de transacciones) con una ID TransferTransaction con la cantidad requerida de fondos transferidos, puede escribir {clave: dirección, valor:
verdadero } en el estado de la cuenta.
Esto significará que el usuario confirma la suscripción al producto o servicio. Cuando la suscripción caduca, cualquier usuario de la red puede establecer la clave correspondiente en el estado en
falso .
let subscriptionPeriod = 44000 let signature = tx.proofs[0] let pk = tx.proofs[1] let requiredAmount = 100000 let this = extract(tx.sender) match tx { case d: DataTransaction => # let lastPaymentHeight = extract(getInteger(this, d.data[0].key + "_lastPayment")) size(d.data) == 1 && d.data[0].value == "false" && lastPaymentHeight + subscriptionPeriod < height || ( let address = d.data[0].key # - ID, let ttx = transactionById(d.proofs[0]) size(d.data) == 2 && d.data[0].value == "true" && d.data[1].key == address + "_lastPayment" && match ttx { case purchase : TransferTransaction => d.data[1].value == transactionHeightById(purchase.id) && toBase58String(purchase.sender.bytes) == address && purchase.amount == requiredAmount && purchase.recipient == this #, waves && !isDefined(purchase.assetId) case _ => false } ) case _ => false }
VotarLas cuentas inteligentes se pueden usar para implementar la votación en la cadena de bloques. Un ejemplo sería una votación para el mejor informe del embajador en el marco del programa de embajadores. El estado de la cuenta se utiliza como plataforma para registrar votos para una u otra opción.
En este ejemplo, la votación está permitida solo para aquellos que compraron tokens especiales de "votación". El participante envía una DataTransaction por adelantado con un par de (clave, valor) = (buyTransactionId, buyTransactionId). Está prohibido establecer un valor diferente para esta clave. Usando su dirección y opción de votación, puede instalar DataEntry solo una vez. La votación solo es posible durante el período establecido.
let asset = base58'8jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf' let address = addressFromPublicKey(tx.proofs[1]) let votingStartHeight = 2000 let votingEndHeight = 3000 let this = extract(tx.sender) match tx { case t: DataTransaction => (height > votingStartHeight && height < votingEndHeight) && #, sigVerify(tx.bodyBytes, tx.proofs[0], tx.proofs[1]) && #, if (t.data[0].key == toBase58String(address.bytes)) then ( # let purchaseTx = transactionById(t.proofs[7]) match purchaseTx { case purchase : TransferTransaction => let correctSender = purchase.sender == t.sender let correctAsset = purchase.assetId == asset let correctPrice = purchase.amount == 1 let correctProof = extract(getBinary(this, toBase58String(purchase.id))) == t.id correctSender && correctAsset && correctPrice && correctProof case _ => false } ) else size(t.data) == 1 && !isDefined(getBinary(this, t.data[0].key)) case _ => false }
Letra de cambioUna letra de cambio es una obligación por escrito según la cual una parte debe pagar a la otra una cantidad fija en el momento de la solicitud o en una fecha predeterminada.
En nuestro ejemplo, se utiliza una cuenta inteligente, cuya fecha de vencimiento corresponde a la fecha de pago de la factura.
let expiration = 100000 let amount = 10 let asset = base58'9jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf' let Bob = Address(base58'3NBVqYXrapgJP9atQccdBPAgJPwHDKkh6A8') let Alice = Address(base58'3PNX6XwMeEXaaP1rf5MCk8weYeF7z2vJZBg') match tx { case t: TransferTransaction => (t.assetId == asset)&& (t.amount == amount)&& (t.sender == Bob)&& (t.recipient == Alice)&& (sigVerify(t.bodyBytes, t.proofs[0], t.senderPublicKey))&& (height >= expiration) case _ => false }
DepositarDepósito: colocación de fondos en un banco en determinadas condiciones (plazo, porcentaje).
En nuestro ejemplo, la función del banco es realizada por una cuenta inteligente. Después de un cierto número de bloques, que corresponde al plazo del depósito, el usuario puede devolver su dinero con un porcentaje. El script establece la altura del bloque (finalHeight), después de lo cual el usuario puede retirar dinero de la cuenta.
heightUnit: la cantidad de bloques en una unidad de tiempo (por ejemplo, mes, año, etc.). Primero, buscamos una entrada con un par (clave, valor) = (initialTransferTransaction, futureDataTransaction). Luego, el usuario debe enviar TransferTransaction con la información correcta sobre el monto del depósito y los intereses devengados por el período del depósito. Esta información se compara con la TransferTransaction original contenida en la prueba de TransferTransaction actual. depositDivisor es el número inverso a la parte del depósito (si el depósito se acepta al 10%, la parte del depósito es 0.1 y depositDevisor = 1 / 0.1 = 10).
let depositDivisor = 10 let heightUnit = 1000 let finalHeight = 100000 let this = extract(tx.sender) match tx { case e : TransferTransaction => # ID let depositHeight = extract(transactionHeightById(e.proofs[7])) # let purchaseTx = transactionById(e.proofs[7]) match purchaseTx { case deposit : TransferTransaction => let correctSender = deposit.sender == e.sender #, + let correctAmount = deposit.amount + deposit.amount / depositDivisor * (height - depositHeight) / heightUnit == e.amount let correctProof = extract(getBinary(this, toBase58String(deposit.id))) == e.id correctSender && correctProof && correctAmount case _ => false } && finalHeight <= height case _ => sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey) }
En el tercer y último artículo de esta serie, analizaremos más opciones para usar activos inteligentes, incluidas la congelación y restricción de transacciones para direcciones específicas.