Em um artigo anterior , analisamos vários casos de uso de contas inteligentes nos negócios - incluindo leilões e programas de fidelidade.
Hoje falaremos sobre como contas e ativos inteligentes podem aumentar a transparência e a confiabilidade de instrumentos financeiros, como opções, futuros e faturas.
OpçãoUma opção é um contrato de bolsa de valores que dá ao comprador o direito de comprar um ativo a um determinado preço ou antes de uma determinada data, mas não o obrigando a fazê-lo.
O exercício da opção pode ser o seguinte:
Utilizamos um ativo inteligente para as próprias opções como ferramenta e uma conta inteligente para o participante que atua como a troca e emite opções. O membro da bolsa promete vender uma certa quantia de um determinado ativo pelo preço sellPrice entre as alturas dos blocos expirationStart e expirationEnd).
No código do ativo inteligente, simplesmente verificamos que ele é negociado apenas entre as alturas indicadas e, como não verificamos mais nada, deixaremos toda a responsabilidade de observar as regras do código do participante da bolsa.
Código do ativo inteligente:let expirationStart = 100000 let expirationEnd = 101440 match tx { case some : ExchangeTransaction | TransferTransaction => height > expirationStart && height <= expirationEnd case _ => false }
Assumimos que as ações são as seguintes: o membro da bolsa vende opções para a compra de algum ativo, e o restante dos participantes pode transferir essas opções ou negociá-las. Para exercer seu direito de compra, um potencial comprador deve transferir o número desejado de opções para a conta do vendedor, ou seja, o participante da troca. Em seguida, ele anota as informações sobre a transferência concluída no estado da conta do membro da troca e somente então ExchangeTransaction poderá passar pelas condições especificadas de compra e venda.
No código da conta inteligente, devemos garantir que qualquer ExchangeTransaction que passe por ela para o ato final de compra e venda atenda às condições especificadas e o participante compre exatamente o número de unidades que ele enviou à conta do participante da troca. Um comprador em potencial deve enviar a DataTransaction correta sobre a transferência que ocorreu, para que o membro da troca possa evitar gastos duplos. Nesta DataTransaction, o comprador coloca em uma chave igual ao seu endereço um valor igual ao número de opções transferidas para a conta do participante da bolsa, ou seja, o número de unidades de ativos que ele pode comprar.Código da conta 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 conta inteligenteDiferentemente de uma opção, os futuros (contrato de futuros) não são um direito, mas a obrigação de um comprador de comprar um ativo a um preço fixo em um determinado ponto no futuro.
Em geral, a implementação dos futuros é semelhante à implementação de uma opção. Aqui, um ativo inteligente atua como um futuro.
Você também deve garantir que o comprador e o vendedor assinem o pedido. Futuros é uma obrigação que deve ser cumprida em qualquer caso. Isso significa que, se um vendedor ou um participante recusar suas obrigações, qualquer participante da rede poderá enviar uma transação, executando assim futuros.
O Script de ativo inteligente controla todos os Futuros de transferência TransferTransaction e ExchangeTransaction, aprovando-os apenas se o Membro comprador tiver criado um pedido para a compra futura de ativos futuros do membro Exchange.
Esse pedido deve ser válido e atender às condições em que os futuros são emitidos. Para verificar um pedido, você pode inserir todos os seus campos no estado da conta do comprador, juntamente com a representação em bytes do pedido assinado e validar a partir do exterior.
No momento, o RIDE não contém uma função nativa para analisar bytes de transação, mas inclui todas as ferramentas necessárias para sua implementação. Portanto, os desenvolvedores podem tentar implementar esse recurso por conta própria.
Conta / Custódia Multi-assinadaUma conta com várias assinaturas permite que vários usuários gerenciem ativos em conjunto (por exemplo, transações com ativos somente serão possíveis se três em cada quatro usuários tiverem assinaturas). Para criar contas com várias assinaturas no idioma RIDE, podemos usar provas de transação.
Uma conta com uma assinatura múltipla também pode ser usada para uma conta de garantia, na qual o dinheiro é armazenado até que as partes no contrato cumpram suas obrigações.
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 gerenciado por token (TCR)Em muitas plataformas blockchain, há um problema de ativos tóxicos. Por exemplo, qualquer endereço que pagou uma comissão pode criar um ativo no Waves.
O TCR (Registro Curadoria de Tokens) gerado pelos detentores de tokens ajuda a resolver o problema de proteger os usuários e o blockchain de ativos tóxicos.
Para votar pela adição de um token específico à lista, o detentor faz uma aposta igual à sua parte de tokens do número total de emitidos. Um token é incluído no registro se a maioria de seus titulares tiver votado nele.
Em nosso exemplo, permitimos que o usuário adicione o token à lista para consideração (durante o período de "desafio") pela chave do estado key = asset_name, apenas se o valor atual for count = 0.
Além disso, o usuário na carteira deve ter um saldo diferente de zero desse token. Em seguida, vem o período de votação durante o qual o usuário pode votar em cada ativo em sua carteira, mas apenas uma vez, atribuindo uma classificação de 1 a 10. As vozes dos usuários são representadas por chaves no formato 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 }
Taxa de assinaturaNeste exemplo, consideraremos o uso de contas inteligentes para efetuar pagamentos regulares de um produto ou serviço em intervalos predeterminados - uma "taxa mensal".
Se um usuário fornecer uma conta inteligente (por meio de provas de transação) uma ID TransferTransaction com a quantidade necessária de fundos transferida, ele poderá escrever {key: address, value:
true } no estado da conta.
Isso significa que o usuário confirma a assinatura do produto ou serviço. Quando a assinatura expira, qualquer usuário da rede pode definir a chave correspondente no status como
false .
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 }
VotaçãoContas inteligentes podem ser usadas para implementar a votação no blockchain. Um exemplo seria a votação do melhor relatório de embaixador no âmbito do programa de embaixadores. O estado da conta é usado como plataforma para registrar votos em uma ou outra opção.
Neste exemplo, a votação é permitida apenas para aqueles que adquiriram tokens especiais de "votação". O participante envia uma DataTransaction antecipadamente com um par de (chave, valor) = (purchaseTransactionId, buyTransactionId). É proibido definir um valor diferente para esta chave. Usando seu endereço e opção de votação, você pode instalar o DataEntry apenas uma vez. A votação é possível apenas durante o período estabelecido.
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 câmbioUma letra de câmbio é uma obrigação por escrito segundo a qual uma parte deve pagar à outra uma quantia fixa no momento da solicitação ou em uma data predeterminada.
No nosso exemplo, é usada uma conta inteligente, cuja data de vencimento corresponde à data de pagamento da fatura.
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 - colocação de fundos em um banco em determinadas condições (prazo, porcentagem).
No nosso exemplo, a função do banco é desempenhada por uma conta inteligente. Após um certo número de blocos, que corresponde ao prazo do depósito, o usuário pode devolver seu dinheiro com uma porcentagem. O script define a altura do bloco (finalHeight), após o qual o usuário pode retirar dinheiro da conta.
heightUnit - o número de blocos em uma unidade de tempo (por exemplo, mês, ano etc.). Primeiro, verificamos uma entrada com um par (chave, valor) = (initialTransferTransaction, futureDataTransaction). Em seguida, o usuário deve enviar a TransferTransaction com as informações corretas sobre o valor do depósito e os juros acumulados durante o período do depósito. Essas informações são comparadas com a TransferTransaction original contida na prova atual da TransferTransaction. depositDivisor é o número inverso à parte do depósito (se o depósito for aceito em 10%, a parte do depósito será 0,1 e 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) }
No terceiro e último artigo desta série, examinaremos mais opções para o uso de ativos inteligentes, incluindo congelamento e restrição de transações para endereços específicos.