
이전 우리는 경매 및 로열티 프로그램을 포함하여 비즈니스에서 스마트 계정을 사용하는 여러 사례를 살펴보았습니다.
오늘 우리는 스마트 계좌와 스마트 자산이 옵션, 선물, 청구서 등 금융 상품의 투명성과 신뢰성을 어떻게 향상시킬 수 있는지에 대해 이야기하겠습니다.
선택권
옵션은 구매자에게 특정 가격이나 특정 날짜 이전에 자산을 구매할 수 있는 권리를 부여하지만 그렇게 할 의무는 없는 교환 계약입니다.
옵션 구현은 다음과 같습니다.
우리는 옵션 자체를 도구로 사용하는 스마트 자산과 교환 역할을 하고 옵션을 발행하는 참가자를 위한 스마트 계정을 사용합니다. 교환 참가자는 ExpirationStart 및 ExpirationEnd 블록 높이 사이의 SellPrice 가격으로 특정 자산의 일정량을 판매할 것을 약속합니다.
스마트 자산 코드에서는 지정된 높이 사이에서만 거래된다는 것만 확인하고, 그 외의 사항은 확인하지 않을 것이며, 규칙 준수에 대한 모든 책임은 교환 참가자의 코드에 맡길 것입니다.
스마트 자산 코드:
let expirationStart = 100000
let expirationEnd = 101440
match tx {
case some : ExchangeTransaction | TransferTransaction =>
height > expirationStart && height <= expirationEnd
case _ => false
}
우리는 해당 작업이 다음과 같이 발생한다고 가정합니다. 교환 참가자는 일부 자산을 구매하기 위해 옵션을 판매하고 다른 참가자는 이러한 옵션을 전달하거나 거래할 수 있습니다. 구매 권리를 행사하려면 잠재적 구매자는 원하는 수의 옵션을 판매자, 즉 교환 참가자의 계정으로 이체해야 합니다. 다음으로, 완료된 이체 정보를 교환 참가자의 주 계정에 기록해야 지정된 구매 및 판매 조건에 따라 ExchangeTransaction이 진행될 수 있습니다.
스마트 계정 코드에서 우리는 구매 및 판매의 최종 행위를 위해 이를 통과하는 모든 ExchangeTransaction이 지정된 조건을 충족하는지 확인해야 하며, 참가자는 거래소 참가자의 계정으로 보낸 수량만큼 정확하게 구매합니다. 잠재적 구매자는 거래 참가자가 이중 지출을 피할 수 있도록 전송에 대한 올바른 DataTransaction을 보내야 합니다. 이 DataTransaction에서 구매자는 자신의 주소와 동일한 키에 따라 교환 참가자의 계정으로 전송된 옵션 수, 즉 구매할 수 있는 자산 단위 수와 동일한 값을 입력합니다.
스마트 계정 코드:
#владелец аккаунта дает обязательство продать определенное количество юнитов ассета
#по цене 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 = 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 exchangeTx : ExchangeTransaction =>
#убеждаемся, что итоговый обмен происходит по указанным заранее правилам
let correctAssetPair = exchangeTx.sellOrder.assetPair.amountAsset == amountAsset &&
exchangeTx.sellOrder.assetPair.priceAsset == priceAsset
let correctPrice = exchangeTx.sellOrder.price == sellPrice
#извлекаем дата-транзакцию из пруфа
let d = transactionById(exchangeTx.proofs[2])
match d{
case dataTx : DataTransaction =>
let buyOrderSender = dataTx.data[0].key
toBase58String(exchangeTx.buyOrder.sender.bytes) == buyOrderSender &&
exchangeTx.amount == extract(getInteger(dataTx.data, buyOrderSender))
case _ => false
} &&
exchangeTx.sellOrder.sender == this &&
correctAssetPair && correctPrice &&
height > expirationStart && height <= expirationEnd
case _ => false
}
스마트 계좌의 선물
옵션과 달리 선물(선물 계약)은 권리가 아니라 미래의 특정 시점에 계약에 의해 고정된 가격으로 자산을 구매해야 하는 구매자의 의무입니다.
일반적으로 미래를 작성하는 것은 옵션을 작성하는 것과 유사합니다. 여기서 스마트 자산은 미래의 역할을 합니다.
또한 구매자와 판매자 모두 구매 주문서에 서명했는지 확인해야 합니다. 미래는 어떤 경우에도 이행되어야 하는 의무입니다. 이는 판매자나 참가자가 의무를 거부하면 모든 네트워크 참가자가 거래를 보내 미래를 실행할 수 있음을 의미합니다.
스마트 자산 스크립트는 선물 자산의 모든 TransferTransactions 및 ExchangeTransactions를 제어하며, 구매자 참가자가 거래소 참가자로부터 향후 선물 자산 구매를 위한 주문을 생성한 경우에만 이를 승인합니다.
이 주문은 유효해야 하며 선물 발행 조건을 충족해야 합니다. 주문을 검증하려면 서명된 주문의 바이트 표현과 함께 구매자 계정 상태에 모든 필드를 입력한 다음 외부 검증을 수행할 수 있습니다.
현재 RIDE에는 트랜잭션 바이트를 구문 분석하는 기본 기능이 포함되어 있지 않지만 구현에 필요한 모든 도구가 포함되어 있습니다. 따라서 개발자는 이 기능을 직접 구현해 볼 수 있습니다.
다중 서명 계정 / 에스크로
다중 서명 계정을 사용하면 여러 사용자가 공동으로 자산을 관리할 수 있습니다(예: 사용자 4명 중 3명이 서명을 한 경우에만 자산 거래가 가능할 수 있음). RIDE 언어로 다중 서명 계정을 생성하기 위해 거래 증명을 사용할 수 있습니다.
다중 서명 계정은 계약 당사자가 의무를 이행할 때까지 자금을 보관하는 에스크로 계정으로도 사용할 수 있습니다.
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
토큰 큐레이트 레지스트리(TCR)
많은 블록체인 플랫폼은 독성 자산에 문제가 있습니다. 예를 들어, 수수료를 지불한 모든 주소는 Waves에서 자산을 생성할 수 있습니다.
사용자와 블록체인 자체를 유해 자산으로부터 보호하는 문제는 토큰 보유자가 생성한 TCR(Token Curated Registry)을 통해 해결할 수 있습니다.
목록에 추가할 특정 토큰에 투표하기 위해 보유자는 발행된 총 토큰 수 중 자신의 몫과 동일한 입찰가를 제시합니다. 토큰 보유자의 대다수가 투표하면 토큰이 등록부에 포함됩니다.
이 예에서는 count의 현재 값이 0인 경우에만 사용자가 상태 키 key = 자산_이름을 사용하여 ("챌린지" 기간 동안) 고려할 목록에 토큰을 추가할 수 있도록 허용합니다.
또한 사용자의 지갑에는 이 토큰의 잔액이 1이 아니어야 합니다. 그런 다음 사용자가 자신의 지갑에 있는 각 자산에 대해 한 번만 투표할 수 있는 투표 기간이 오고 10부터 XNUMX까지 등급을 부여합니다. 사용자 투표는 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
}
가입비
이 예에서는 스마트 계정을 사용하여 지정된 간격으로 제품이나 서비스에 대한 정기적인 결제("가입비")를 수행하는 방법을 살펴보겠습니다.
사용자가 거래 증명을 통해 스마트 계정에 필요한 금액의 이체 자금이 포함된 TransferTransaction ID를 제공하면 계정 상태에 {키: 주소, 값:)을 쓸 수 있습니다. 참된}.
이는 사용자가 제품이나 서비스에 대한 구독을 확인한다는 의미입니다. 구독이 만료되면 모든 네트워크 사용자는 상태의 해당 키 반대편에 값을 설정할 수 있습니다. 그릇된.
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
}
투표
스마트 계정을 사용하여 블록체인에서 투표를 구현할 수 있습니다. 예를 들어 대사 프로그램 내에서 최고의 대사 보고서에 투표하는 것입니다. 계정 상태는 특정 옵션에 대한 투표를 기록하기 위한 플랫폼으로 사용됩니다.
이 예에서는 특별한 "투표" 토큰을 구매한 사람만 투표할 수 있습니다. 참가자는 (key, value) = (purchaseTransactionId, buyTransactionId) 쌍으로 미리 DataTransaction을 보냅니다. 이 키에 다른 값을 설정하는 것은 금지되어 있습니다. 주소와 투표 옵션을 사용하면 DataEntry를 한 번만 설정할 수 있습니다. 투표는 지정된 기간에만 가능합니다.
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
}
환어음
약속어음은 한 당사자가 요구에 따라 또는 미리 정해진 날짜에 고정 금액을 다른 당사자에게 지불하도록 요구하는 서면 의무입니다.
이 예에서는 만료 날짜가 청구서 지불 날짜에 해당하는 스마트 계정을 사용합니다.
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
}
예금
예금은 특정 조건(기간, 이자) 하에서 은행에 자금을 배치하는 것입니다.
이 예에서는 은행의 기능이 스마트 계정에 의해 수행됩니다. 예금 기간에 해당하는 특정 수의 블록이 지나면 사용자는 이자를 포함하여 돈을 반환할 수 있습니다. 스크립트는 사용자가 계정에서 돈을 인출할 수 있는 블록 높이(finalHeight)를 지정합니다.
heightUnit - 한 시간 단위(예: 월, 연도 등)의 블록 수입니다. 먼저 (key, value) = (initialTransferTransaction, futureDataTransaction) 쌍이 있는 항목을 확인합니다. 그런 다음 사용자는 입금액 및 입금액에 대한 올바른 정보와 함께 TransferTransaction을 제출해야 합니다. 이 정보는 현재 TransferTransaction 증명에 포함된 원본 TransferTransaction과 비교하여 확인됩니다. 예금Divisor는 예금 지분의 역수입니다(예금이 10%로 승인되면 예금 지분은 0,1이고, 예금Devisor = 1/0,1 = 10).
let this = extract(tx.sender)
let depositDivisor = 10
let heightUnit = 1000
let finalHeight = 100000
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)
}
이 시리즈의 세 번째이자 마지막 기사에서는 특정 주소에 대한 거래 동결 및 제한을 포함하여 스마트 자산의 더 많은 용도를 살펴보겠습니다.
출처 : habr.com
