Skip to content

Instantly share code, notes, and snippets.

@cryptcoin-junkey
Last active October 4, 2020 06:31
Show Gist options
  • Save cryptcoin-junkey/8c280835d038cf47b8ecafec7aeb3e09 to your computer and use it in GitHub Desktop.
Save cryptcoin-junkey/8c280835d038cf47b8ecafec7aeb3e09 to your computer and use it in GitHub Desktop.
Monaparty スマコンでレンディングしてみる思考実験

これ is 何 ?

構想中の Monaparty スマコンでレンディングのプラットフォームが作れるかどうかの思考実験。処理系は、まだ無い。当然。

前提知識

Monaparty スマコンでは、誰かが投げた Monaparty メッセージにより発火が起こる。

発火のあと、契約内容のチェックが走る。検証用言語は BitcoinCash 版 Script からの独自拡張。

契約が成立すると、Monaparty メッセージを投げられる。メッセージは事前に埋め込んでもいいし、検証用言語を使って動的に作っても良い。

コントラクトは、一つの Monacoin アドレスにつき複数デプロイできる。

同一の TxIndex であっても、条件さえ合致すれば、同じ Moancoin アドレスにデプロイされた複数のコントラクトが発火される。 (下記シナリオでは xmp2monana と clone-mona2xmp が同じ TxIndex で実行されている)

思考実験のシナリオ

登場人物

  • "MSourceAddress" 借り手
  • "MDestinationAddress" 貸し手。スマコン。
  • "MONANA" 貸し出されるアセット
  • "XMP" 担保アセット

初期条件

下記擬似コードから生成されたコントラクト monana2xmp xmp2monana clone-xmp2monana が "MDestinationAddress" からデプロイされている。

貸し出し

"MSourceAddress" は、"MONANA" を借りるため、担保となる "XMP" を "MDestinationAddress" へ send する。

まず、コントラクト xmp2monana が発火。パラメータのチェックを行ったあと、"MSourceAddress" へ "MONANA" を send する (貸し出す)。

返却のための準備

次に、コントラクト clone-monana2xmp が発火。パラメータのチェックを行った後、monana2xmp のクローンを作成。 このクローンには、"MSourceAddress" がコントラクト実行時の初期スタックとして設定される。

返却

"MSourceAddress" は返却を行うため、"MONANA" を "MDestinationAddress" へ send する。

クローンされた monana2xmp が発火。下記条件を満たす場合に、"XMP" を "MDestinationAddress" へ send する。

  • 返却期日を過ぎていない。
  • クローン時に埋め込まれたアドレス (コード例では "EmbeddedAddress" ) と "MSourceAddress" が一致する。
  • 自分宛ての send である。
  • 貸し出したアセットが送られてきている。
  • 利息分を差し引いても残高がある。

上記条件を満たさない場合、コントラクトは "XMP" を send しない(無視する)。

結論

  • 先日の検討 には無かった、"コントラクトのクローン" という機能が要る。 クローン自体は実装が難しいものではない。オブジェクト指向的に正しいものでもあり、導入には前向き。
  • 構想の初期段階でここまで記述可能になるとは。これ意外と DeFi できてしまっているのでは?
  • 2017 年くらいから断続的ながらも考え続けてきたことなので、当然と言えは当然でもある。
contract: {
majorVersion: 1,
minorVersion: 0,
triggerType: send;
// stack is [ "MSourceAddress", "MDestinationAddress", "XMP", 1000, "memo" ]
script: [
// Address check.
3,
OP_PICK, // result: [ "MSourceAddress", "MDestinationAddress", "XMP", 1000, "memo", "MDestinationAddress" ]
OPX_MYADDRESS, // result: [ "MSourceAddress", "MDestinationAddress", "XMP", 1000, "memo", "MDestinationAddress", "MDestinationAddress" ]
OP_EQUALVERIFY, // Fail if the destination address is not me.
// Drop memo.
OP_DROP, // result: [ "MSourceAddress", "MDestinationAddress", "XMP", 1000 ]
// Asset check.
OP_SWAP, // result: [ "MSourceAddress", "MDestinationAddress", 1000, "XMP" ]
"XMP", // result: [ "MSourceAddress", "MDestinationAddress", 1000, "XMP", "XMP" ]
OP_EQUALVERIFY, // result: [ "MSourceAddress", "MDestinationAddress", 1000 ] or fail
// Build contract message.
OP_2DROP, // result: [ "MSourceAddress" ]
1, 2, 1234, OP_5, // result: [ "MSourceAddress", 1, 2, 0, 1234, OP_5 ] // pseodo. building contract clone message.
OPX_BUILDMESSAGE, // result: [ ]
OP_1 // result: [ OP_1 ] // means success.
message: {} // will be built on the script.
}
contract: {
majorVersion: 1,
minorVersion: 0,
triggerType: send;
// stack is [ "EmbeddedAddress" "MSourceAddress", "MDestinationAddress", "MONANA", 1000, "memo" ]
// "EmbeddedAddress" was stored in the contract itself by "clone" contract.
script: [
// Return period check.
0,
OPX_CURRENTBLOCK, // result: [ ..., 0, 100 ]
OPX_BEGINBLOCK, // result: [ ..., 0, 100, 10 ]
130, // result: [ ..., 0, 100, 10, 130 ] // period
OP_ADD, OP_SUB, // result: [ ..., 0, -40 ]
OP_GREATERTHAN, // result: [ ..., OP_1 ]
OP_VERIFY // result: [ ... ] or fail
// Source address check.
5, 4,
OP_PICK, OP_PICK, // result [ "EmbeddedAddress", "MSourceAddress", "MDestinationAddress", "MONANA", 1000, "memo", "EmbeddedAddress", "MSourceAddress" ]
OP_EQUALVERIFY, // result: [ "EmbeddedAddress", "MSourceAddress", "MDestinationAddress", "MONANA", 1000, "memo" ] or fail
//// "EmbeddedAddress" can be ignored in following results.
// Destination address check.
3,
OP_PICK, // result: [ "MSourceAddress", "MDestinationAddress", "MONANA", 1000, "memo", "MDestinationAddress" ]
OPX_MYADDRESS, // result: [ "MSourceAddress", "MDestinationAddress", "MONANA", 1000, "memo", "MDestinationAddress", "MDestinationAddress" ]
OP_EQUALVERIFY, // Fail if the destination address is not me.
OP_DROP, // result: [ "MSourceAddress", "MDestinationAddress", "MONANA", 1000 ]
// Asset check
OP_SWAP, // result: [ "MSourceAddress", "MDestinationAddress", 1000, "MONANA" ]
"MONANA", // result: [ "MSourceAddress", "MDestinationAddress", 1000, "MONANA", "MONANA" ]
OP_EQUALVERIFY, // result: [ "MSourceAddress", "MDestinationAddress", 1000 ] or fail
// Return "XMP"
"XMP", // result: [ "MSourceAddress", "MDestinationAddress", 1000, "XMP" ]
OP_SWAP, // result: [ "MSourceAddress", "MDestinationAddress", "XMP", 1000 ]
// Decrease. Take interest. (the logic is an example. Should be redesigned.)
OPX_CURRENTBLOCK, // result: [ "MSourceAddress", "MDestinationAddress", "XMP", 1000, 100 ]
OPX_BEGINBLOCK, // result: [ "MSourceAddress", "MDestinationAddress", "XMP", 1000, 100, 10 ]
OP_NEGATE, // result: [ "MSourceAddress", "MDestinationAddress", "XMP", 1000, 100, -10 ]
OP_ADD, // result: [ "MSourceAddress", "MDestinationAddress", "XMP", 1000, 90 ]
OP_NEGATE, // result: [ "MSourceAddress", "MDestinationAddress", "XMP", 1000, -90 ]
OP_ADD, // result: [ "MSourceAddress", "MDestinationAddress", "XMP", 990 ]
// Balance check.
OP_DUP, // result: [ "MSourceAddress", "MDestinationAddress", "XMP", 990, 990 ]
0, // result: [ "MSourceAddress", "MDestinationAddress", "XMP", 990, 990, 0 ]
OP_GRATERTHAN, // result: [ "MSourceAddress", "MDestinationAddress", "XMP", 990, OP_1 ]
OP_EQUALVERIFY, // result: [ "MSourceAddress", "MDestinationAddress", "XMP", 990, OP_1 ] or fail
// Build message
"MONANA" // result: [ "MSourceAddress", "MDestinationAddress", 1000, "XMP" ]
OP_SWAP, // result: [ "MSourceAddress", "MDestinationAddress", "XMP", 1000 ]
OP_2SWAP, // result: [ "XMP", 1000, "MSourceAddress", "MDestinationAddress" ]
OP_SWAP, // result: [ "XMP", 1000, "MDestinationAddress", "MSourceAddress" ]
OP_2SWAP, // result: [ "MDestinationAddress", "MSourceAddress", "XMP", 1000 ]
OP_1, // result: [ "MDestinationAddress", "MSourceAddress", "XMP", 1000, OP_1 ] // OP_1 means "send"
OPX_BUILDMESSAGE, // result [ ]
OP_1 // result: [ OP_1 ] // means success.
],
message: {} // will be built on the script.
}
contract: {
majorVersion: 1,
minorVersion: 0,
triggerType: send;
// stack is [ "MSourceAddress", "MDestinationAddress", "XMP", 1000, "memo" ]
script: [
// Address check.
3,
OP_PICK, // result: [ "MSourceAddress", "MDestinationAddress", "XMP", 1000, "memo", "MDestinationAddress" ]
OPX_MYADDRESS, // result: [ "MSourceAddress", "MDestinationAddress", "XMP", 1000, "memo", "MDestinationAddress", "MDestinationAddress" ]
OP_EQUALVERIFY, // Fail if the destination address is not me.
OP_DROP, // result: [ "MSourceAddress", "MDestinationAddress", "XMP", 1000 ]
// Asset check.
OP_SWAP, // result: [ "MSourceAddress", "MDestinationAddress", 1000, "XMP" ]
"XMP", // result: [ "MSourceAddress", "MDestinationAddress", 1000, "XMP", "XMP" ]
OP_EQUALVERIFY, // result: [ "MSourceAddress", "MDestinationAddress", 1000 ] or fail
// Build message
"MONANA" // result: [ "MSourceAddress", "MDestinationAddress", 1000, "MONANA" ]
OP_SWAP, // result: [ "MSourceAddress", "MDestinationAddress", "MONANA", 1000 ]
OP_2SWAP, // result: [ "MONANA", 1000, "MSourceAddress", "MDestinationAddress" ]
OP_SWAP, // result: [ "MONANA", 1000, "MDestinationAddress", "MSourceAddress" ]
OP_2SWAP, // result: [ "MDestinationAddress", "MSourceAddress", "MONANA", 1000 ]
OP_1, // result: [ "MDestinationAddress", "MSourceAddress", "MONANA", 1000, OP_1 ] // OP_1 means "send"
OPX_BUILDMESSAGE, // result [ ] // "send" message is built and stored.
OP_1 // result: [ OP_1 ] // means success.
],
message: {} // will be built on the script.
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment