Поскольку язык написания контрактов позволяет выполнять вложенные контракты, то существует возможность выполнения такого вложенного контракта без ведома пользователя запустившего внешний контракт, что может привести к подписи пользователем несанкционированных им транзакций, скажем перевода денег со своего счета.
К примеру, пусть имеется контракт перевода денег MoneyTransfer:
contract MoneyTransfer {
data {
Recipient int
Amount money
}
...
}
Если в некотором контракте, запущенном пользователем, будет вписана строка MoneyTransfer(“Recipient,Amount”, 12345, 100), то будет осуществлен перевод 100 монет на кошелек 12345. При этом пользователь, подписывающий внешний контракт, останется не в курсе осуществленной транзакции. Исключить такую ситуацию возможно, если контракт MoneyTransfer будет требовать получения дополнительной подписи пользователя при вызове его из других контрактов. Для этого необходимо:
- Добавить в секцию data контракта MoneyTransfer поле с именем Signature с параметрами optional и hidden, которые позволяют не требовать дополнительной подписи при прямом вызове контракта, поскольку в поле Signature уже будет подпись.
contract MoneyTransfer {
data {
Recipient int
Amount money
Signature string "optional hidden"
}
...
}
- Добавить в таблицу Signatures запись содержащую:
- имя контракта MoneyTransfer,
- имена полей, значения которых будут показываться пользователю, и их текстовое описание,
- текст, который будет выводиться при подтверждении.
В текущем примере достаточно указать два поля Receipient и Amount:
- Title: Are you agree to send money this recipient?
- Parameter: Receipient Text: Wallet ID
- Parameter: Amount Text: Amount (qEGS)
Теперь если вставить вызов контракта MoneyTransfer(“Recipient, Amount”, 12345, 100), то будет получена системная ошибка “Signature is not defined”. Если же контракт будет вызван следующим образом *MoneyTransfer(“Recipient, Amount, Signature”, 12345, 100, ”xxx...xxxxx”), то возникнет ошибка при проверке подписи. При вызове контракта проверяется подпись следующих данных: "“время оригинальной транзакции, id пользователя, значение полей указанных в таблице signatures”", и подделать эту подпись невозможно.
Для того, чтобы пользователь при вызове контракта MoneyTransfer увидел подтверждение на перевод денег, во внешний контракт необходимо добавить поле с произвольным названием и типом string и дополнительным параметром signature:contractname. При вызове вложенного контракта MoneyTransfer необходимо просто передать этот параметр. Также следует иметь в виду, что параметры для вызова защищенного контракта должны также быть описаны в секции data внешнего контракта (они могут быть скрытыми, но они все равно будут отображаться при подтверждении). Например,
contract MyTest {
data {
Recipient int "hidden"
Amount money
Signature string "signature:send_money"
}
func action {
MoneyTransfer("Recipient,Amount,Signature",$Recipient,$Amount,$Signature)
}
}
При отправке контракта MyTest, у пользователя будет запрошено дополнительное подтверждение для перевода суммы на указанный кошелек. Если во вложенном контракте будут указаны другие значения, например MoneyTransfer(“Recipient,Amount,Signature”,$Recipient, $Amount+10, $Signature), то будет получена ошибку, что подпись неверна.