
Trước đây Chúng tôi đã xem xét một số trường hợp sử dụng tài khoản thông minh trong kinh doanh, bao gồm các chương trình đấu giá và khách hàng thân thiết.
Hôm nay chúng ta sẽ nói về cách tài khoản thông minh và tài sản thông minh có thể cải thiện tính minh bạch và độ tin cậy của các công cụ tài chính như quyền chọn, hợp đồng tương lai và hóa đơn.
Lựa chọn
Quyền chọn là một hợp đồng trao đổi trao cho người mua quyền mua một tài sản ở một mức giá nhất định hoặc trước một ngày nhất định, nhưng không bắt buộc người mua phải làm như vậy.
Việc thực hiện tùy chọn có thể như sau:
Chúng tôi sử dụng tài sản thông minh cho chính các quyền chọn như một công cụ và tài khoản thông minh cho người tham gia đóng vai trò là sàn giao dịch và phát hành quyền chọn. Người tham gia trao đổi hứa rằng anh ta sẽ bán một số lượng nhất định của một tài sản nhất định ở mức giá SellPrice giữa chiều cao khối hết hạn Bắt đầu và hết hạn).
Trong mã tài sản thông minh, chúng tôi sẽ chỉ kiểm tra xem nó chỉ được giao dịch giữa các độ cao được chỉ định và sẽ không kiểm tra bất kỳ điều gì khác; chúng tôi sẽ giao mọi trách nhiệm về việc tuân thủ các quy tắc cho mã của người tham gia trao đổi.
Mã tài sản thông minh:
let expirationStart = 100000
let expirationEnd = 101440
match tx {
case some : ExchangeTransaction | TransferTransaction =>
height > expirationStart && height <= expirationEnd
case _ => false
}
Chúng tôi sẽ giả định rằng các hành động diễn ra như sau: một người tham gia trao đổi bán các quyền chọn để mua một số tài sản và những người tham gia khác có thể chuyển tiếp các quyền chọn này hoặc giao dịch chúng. Để thực hiện quyền mua của mình, người mua tiềm năng phải chuyển số lượng quyền chọn mong muốn vào tài khoản của người bán, tức là người tham gia trao đổi. Tiếp theo, anh ta viết thông tin về quá trình chuyển khoản đã hoàn thành vào tài khoản trạng thái của người tham gia trao đổi và chỉ khi đó ExchangeTransaction mới có thể tiến hành theo các điều kiện mua bán đã chỉ định.
Trong mã tài khoản thông minh, chúng tôi phải đảm bảo rằng bất kỳ Giao dịch Exchange nào đi qua nó để thực hiện hành động mua và bán cuối cùng đều đáp ứng các điều kiện đã chỉ định và người tham gia mua chính xác số lượng đơn vị mà anh ta đã gửi vào tài khoản của người tham gia trao đổi. Người mua tiềm năng phải gửi DataTransaction chính xác về việc chuyển khoản để người tham gia trao đổi có thể tránh chi tiêu gấp đôi. Trong DataTransaction này, người mua đặt, theo khóa bằng địa chỉ của mình, một giá trị bằng số lượng tùy chọn được chuyển vào tài khoản của người tham gia trao đổi, tức là số lượng đơn vị tài sản mà anh ta có thể mua.
Mã tài khoản thông minh:
#владелец аккаунта дает обязательство продать определенное количество юнитов ассета
#по цене 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
}
Hợp đồng tương lai trên tài khoản thông minh
Không giống như quyền chọn, hợp đồng tương lai (hợp đồng tương lai) không phải là một quyền mà là nghĩa vụ của người mua trong việc mua một tài sản ở mức giá được hợp đồng ấn định tại một thời điểm nhất định trong tương lai.
Nói chung, viết một hợp đồng tương lai cũng tương tự như viết một quyền chọn. Ở đây tài sản thông minh hoạt động như một tương lai.
Bạn cũng cần đảm bảo rằng cả người mua và người bán đều ký vào đơn đặt hàng. Tương lai là một nghĩa vụ phải được thực hiện trong mọi trường hợp. Điều này có nghĩa là nếu người bán hoặc người tham gia từ chối nghĩa vụ của họ thì bất kỳ người tham gia nào trong mạng đều có thể gửi giao dịch, từ đó thực hiện giao dịch trong tương lai.
Tập lệnh tài sản thông minh kiểm soát tất cả Giao dịch chuyển nhượng và Giao dịch trao đổi của tài sản tương lai, chỉ phê duyệt chúng nếu người tham gia người mua đã tạo đơn đặt hàng mua tài sản tương lai trong tương lai từ người tham gia trao đổi.
Lệnh này phải hợp lệ và đáp ứng các điều kiện mà hợp đồng tương lai được phát hành. Để xác thực đơn hàng, bạn có thể nhập tất cả các trường của đơn hàng vào trạng thái tài khoản của người mua cùng với biểu diễn byte của đơn hàng đã ký và sau đó thực hiện xác thực bên ngoài.
Hiện tại, RIDE không có chức năng gốc để phân tích các byte giao dịch nhưng bao gồm tất cả các công cụ cần thiết để triển khai nó. Do đó, các nhà phát triển có thể thử tự mình triển khai tính năng này.
Tài khoản đa chữ ký/Ký quỹ
Tài khoản nhiều chữ ký cho phép nhiều người dùng cùng quản lý tài sản (ví dụ: giao dịch với tài sản chỉ có thể thực hiện được nếu ba trong số bốn người dùng có chữ ký). Để tạo tài khoản đa chữ ký bằng ngôn ngữ RIDE, chúng ta có thể sử dụng bằng chứng giao dịch.
Tài khoản nhiều chữ ký cũng có thể được sử dụng làm tài khoản ký quỹ trong đó tiền được giữ cho đến khi các bên tham gia hợp đồng hoàn thành nghĩa vụ của mình.
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
Cơ quan đăng ký quản lý mã thông báo (TCR)
Nhiều nền tảng blockchain gặp vấn đề với các tài sản độc hại. Ví dụ: bất kỳ địa chỉ nào đã trả hoa hồng đều có thể tạo nội dung trên Waves.
Vấn đề bảo vệ người dùng và chính blockchain khỏi các tài sản độc hại có thể được giải quyết bằng cơ quan đăng ký quản lý mã thông báo (TCR) do chủ sở hữu mã thông báo tạo ra.
Để bỏ phiếu cho một mã thông báo cụ thể sẽ được thêm vào danh sách, chủ sở hữu đặt giá thầu bằng với phần của mình trong tổng số mã thông báo được phát hành. Mã thông báo sẽ được đưa vào sổ đăng ký nếu đa số người nắm giữ nó bỏ phiếu cho nó.
Trong ví dụ của chúng tôi, chúng tôi cho phép người dùng thêm mã thông báo vào danh sách để xem xét (trong khoảng thời gian “thử thách”) bằng cách sử dụng khóa trạng thái = assets_name, chỉ khi giá trị hiện tại của count = 0.
Ngoài ra, người dùng phải có số dư khác 1 của mã thông báo này trong ví của mình. Sau đó là thời gian bỏ phiếu, trong đó người dùng có thể bỏ phiếu cho từng nội dung trong ví của mình nhưng chỉ một lần, đưa ra xếp hạng từ 10 đến XNUMX. Phiếu bầu của người dùng được biểu thị bằng các khóa có dạng 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
}
Phí đăng ký
Trong ví dụ này, chúng ta sẽ xem xét việc sử dụng tài khoản thông minh để thực hiện thanh toán thường xuyên cho một sản phẩm hoặc dịch vụ theo những khoảng thời gian xác định - “phí đăng ký”.
Nếu người dùng cung cấp cho tài khoản thông minh (thông qua bằng chứng giao dịch) ID giao dịch chuyển khoản với số tiền được chuyển cần thiết, anh ta có thể ghi {key: address, value:) vào trạng thái tài khoản đúng}.
Điều này có nghĩa là người dùng xác nhận đăng ký của họ với sản phẩm hoặc dịch vụ. Khi đăng ký hết hạn, bất kỳ người dùng mạng nào cũng có thể đặt giá trị bên cạnh khóa tương ứng ở trạng thái sai.
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
}
Bỏ phiếu
Tài khoản thông minh có thể được sử dụng để thực hiện bỏ phiếu trên blockchain. Một ví dụ sẽ là bình chọn cho báo cáo đại sứ xuất sắc nhất trong chương trình đại sứ. Trạng thái tài khoản được sử dụng làm nền tảng để ghi lại phiếu bầu cho một tùy chọn cụ thể.
Trong ví dụ này, chỉ những người đã mua mã thông báo “bỏ phiếu” đặc biệt mới được phép bỏ phiếu. Người tham gia gửi trước DataTransaction với cặp (key, value) = (purchaseTransactionId, buyTransactionId). Việc đặt giá trị khác cho khóa này bị cấm. Bằng cách sử dụng địa chỉ và tùy chọn biểu quyết, bạn chỉ có thể đặt DataEntry một lần. Chỉ có thể bỏ phiếu trong khoảng thời gian được chỉ định.
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
}
Lá phiếu
Giấy nợ là một nghĩa vụ bằng văn bản yêu cầu một bên phải trả cho bên kia một số tiền cố định theo yêu cầu hoặc vào một ngày định trước.
Trong ví dụ của chúng tôi, chúng tôi sử dụng tài khoản thông minh, ngày hết hạn tương ứng với ngày thanh toán hóa đơn.
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
}
Tiền gửi
Tiền gửi là việc gửi tiền vào ngân hàng với những điều kiện nhất định (thời hạn, lãi suất).
Trong ví dụ của chúng tôi, chức năng của ngân hàng được thực hiện bởi một tài khoản thông minh. Sau một số khối nhất định, tương ứng với thời gian gửi tiền, người dùng có thể trả lại tiền của mình cùng với lãi suất. Tập lệnh chỉ định chiều cao khối (finalHeight), sau khi đạt đến mức này người dùng có thể rút tiền từ tài khoản.
HeightUnit - số khối trong một đơn vị thời gian (ví dụ: tháng, năm, v.v.). Trước tiên, chúng tôi kiểm tra mục nhập có cặp (key, value) = (initialTransferTransaction, FutureDataTransaction). Sau đó, người dùng phải gửi Giao dịch chuyển khoản với thông tin chính xác về số tiền gửi và tiền lãi tích lũy trong thời gian gửi tiền. Thông tin này được kiểm tra dựa trên TransferTransaction ban đầu, có trong bằng chứng TransferTransaction hiện tại. DepositDivisor là số nghịch đảo của phần tiền gửi (nếu khoản tiền gửi được chấp nhận ở mức 10% thì phần tiền gửi là 0,1 và DepositDevisor = 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)
}
Trong bài viết thứ ba và cũng là bài viết cuối cùng của loạt bài này, chúng ta sẽ xem xét nhiều cách sử dụng tài sản thông minh hơn, bao gồm cả việc đóng băng và hạn chế giao dịch đối với các địa chỉ cụ thể.
Nguồn: www.habr.com
