From 54810943275ccf22b797128a83762350053b7fdf Mon Sep 17 00:00:00 2001
From: Virgil <25692529+virgil-serbanuta@users.noreply.github.com>
Date: Thu, 26 Sep 2024 23:24:05 +0300
Subject: [PATCH] Implement the send() function for contracts (#102)
---
.../main/expression/rust-to-mx.md | 2 +
mx-rust-semantics/main/glue.md | 2 +
mx-rust-semantics/main/modules.md | 2 +
mx-rust-semantics/main/modules/address.md | 2 +-
mx-rust-semantics/main/modules/proxy.md | 5 -
mx-rust-semantics/main/modules/send.md | 122 ++++++++++++++++++
mx-rust-semantics/main/preprocessing.md | 2 +
.../main/preprocessing/contract.md | 59 +++++++++
.../main/preprocessing/methods.md | 2 +-
mx-rust-semantics/main/representation.md | 5 +
tests/mx-rust-contracts/send.1.args | 0
tests/mx-rust-contracts/send.1.run | 42 ++++++
tests/mx-rust-contracts/send.rs | 18 +++
13 files changed, 256 insertions(+), 7 deletions(-)
create mode 100644 mx-rust-semantics/main/modules/send.md
create mode 100644 mx-rust-semantics/main/preprocessing/contract.md
create mode 100644 tests/mx-rust-contracts/send.1.args
create mode 100644 tests/mx-rust-contracts/send.1.run
create mode 100644 tests/mx-rust-contracts/send.rs
diff --git a/mx-rust-semantics/main/expression/rust-to-mx.md b/mx-rust-semantics/main/expression/rust-to-mx.md
index 1cb6e56..ae0a6b5 100644
--- a/mx-rust-semantics/main/expression/rust-to-mx.md
+++ b/mx-rust-semantics/main/expression/rust-to-mx.md
@@ -25,6 +25,8 @@ module MX-RUST-EXPRESSION-RUST-TO-MX
Values:Map
[owise]
rule rustToMx(S:String => mxStringValue(S))
+ rule rustToMx(V:Value => mxIntValue({valueToInteger(V)}:>Int))
+ requires notBool isSemanticsError(valueToInteger(V))
rule rustToMx(tuple(V:ValueList)) => rustValuesToMxListValue(V, .MxValueList)
syntax RustMxInstruction ::= rustValuesToMxListValue(ValueListOrError, MxValueList)
diff --git a/mx-rust-semantics/main/glue.md b/mx-rust-semantics/main/glue.md
index 8bcbd0e..704d5ea 100644
--- a/mx-rust-semantics/main/glue.md
+++ b/mx-rust-semantics/main/glue.md
@@ -65,6 +65,8 @@ module MX-RUST-GLUE
rule rustValueToMx(V:Value) => mxIntValue({valueToInteger(V)}:>Int)
requires notBool isSemanticsError(valueToInteger(V))
+ rule mxIntValue(0) ~> mxRustCheckMxStatus => .K
+
endmodule
```
diff --git a/mx-rust-semantics/main/modules.md b/mx-rust-semantics/main/modules.md
index 4d00581..5415bc8 100644
--- a/mx-rust-semantics/main/modules.md
+++ b/mx-rust-semantics/main/modules.md
@@ -4,6 +4,7 @@ requires "modules/address.md"
requires "modules/biguint.md"
requires "modules/hooks.md"
requires "modules/proxy.md"
+requires "modules/send.md"
requires "modules/storage.md"
requires "modules/token-identifier.md"
@@ -12,6 +13,7 @@ module MX-RUST-MODULES
imports private MX-RUST-MODULES-BIGUINT
imports private MX-RUST-MODULES-HOOKS
imports private MX-RUST-MODULES-PROXY
+ imports private MX-RUST-MODULES-SEND
imports private MX-RUST-MODULES-STORAGE
imports private MX-RUST-MODULES-TOKEN-IDENTIFIER
endmodule
diff --git a/mx-rust-semantics/main/modules/address.md b/mx-rust-semantics/main/modules/address.md
index 81f4371..0297393 100644
--- a/mx-rust-semantics/main/modules/address.md
+++ b/mx-rust-semantics/main/modules/address.md
@@ -28,7 +28,7 @@ module MX-RUST-MODULES-ADDRESS
( struct
( #token("ManagedAddress", "Identifier"):Identifier
, #token("mx_address_value", "Identifier"):Identifier |-> AddressValueId:Int
- _:Map
+ .Map
)
)
=> ptr(AddressValueId) ~> rustValueToMx
diff --git a/mx-rust-semantics/main/modules/proxy.md b/mx-rust-semantics/main/modules/proxy.md
index d048867..1d639db 100644
--- a/mx-rust-semantics/main/modules/proxy.md
+++ b/mx-rust-semantics/main/modules/proxy.md
@@ -88,8 +88,6 @@ module MX-RUST-MODULES-PROXY
ProxyType
MethodName
- syntax MxOrRustValueOrInstruction ::= MxOrRustValue | MxRustInstruction
-
syntax RustMxInstruction ::= rustMxManagedExecuteOnDestContext
( destination: MxOrRustValueOrInstruction // MxOrRustValue
, egldValue: MxOrRustValueOrInstruction // MxOrRustValue
@@ -225,9 +223,6 @@ module MX-RUST-MODULES-PROXY
...
- syntax MxInstructions ::= "mxRustCheckMxStatus"
- rule mxIntValue(0) ~> mxRustCheckMxStatus => .K
-
rule implicitCast
( struct(#token("MxRust#Proxy", "Identifier"):Identifier, _) #as V
, T
diff --git a/mx-rust-semantics/main/modules/send.md b/mx-rust-semantics/main/modules/send.md
new file mode 100644
index 0000000..9a03a1f
--- /dev/null
+++ b/mx-rust-semantics/main/modules/send.md
@@ -0,0 +1,122 @@
+```k
+
+module MX-RUST-MODULES-SEND
+ imports private COMMON-K-CELL
+ imports private MX-COMMON-SYNTAX
+ imports private MX-RUST-REPRESENTATION
+ imports private MX-RUST-REPRESENTATION-CONVERSIONS
+ imports private RUST-EXECUTION-CONFIGURATION
+ imports private RUST-SHARED-SYNTAX
+
+ syntax Identifier ::= "MxRust#Send" [token]
+
+ syntax MxRustStructType ::= "sendType" [function, total]
+ rule sendType
+ => rustStructType
+ ( MxRust#Send
+ , .MxRustStructFields
+ )
+
+ rule
+ normalizedMethodCall
+ ( MxRust#Send
+ , #token("new", "Identifier"):Identifier
+ , .PtrList
+ )
+ => mxRustNewStruct
+ ( sendType
+ , .CallParamsList
+ )
+
+ rule
+
+ normalizedMethodCall
+ ( MxRust#Send
+ , #token("direct_esdt", "Identifier"):Identifier
+ , ( ptr(_SelfId:Int)
+ , ptr(AddressId:Int)
+ , ptr(TokenIdId:Int)
+ , ptr(NonceId:Int)
+ , ptr(AmountId:Int)
+ , .PtrList
+ )
+ )
+ => rustMxDirectEsdt
+ (... destination: Address
+ , tokenId: TokenId
+ , nonce: Nonce
+ , amount: Amount
+ )
+ ~> mxRustCheckMxStatus
+ ~> ptrValue(null, ())
+ ...
+
+
+ AddressId |-> Address:Value
+ TokenIdId |-> TokenId:Value
+ NonceId |-> Nonce:Value
+ AmountId |-> Amount:Value
+ ...
+
+
+ syntax RustMxInstruction ::= rustMxDirectEsdt
+ ( destination: MxOrRustValueOrInstruction // MxOrRustValue
+ , tokenId: MxOrRustValueOrInstruction // MxOrRustValue
+ , nonce: MxOrRustValueOrInstruction // MxOrRustValue
+ , amount: MxOrRustValueOrInstruction // MxOrRustValue
+ )
+ context rustMxDirectEsdt
+ (... destination: HOLE:MxOrRustValue => rustToMx(HOLE)
+ , tokenId: _:MxOrRustValue
+ , nonce: _:MxOrRustValue
+ , amount: _:MxOrRustValue
+ )
+ [result(MxValue)]
+ context rustMxDirectEsdt
+ (... destination: Destination:MxOrRustValue
+ , tokenId: HOLE:MxOrRustValue => rustToMx(HOLE)
+ , nonce: _:MxOrRustValue
+ , amount: _:MxOrRustValue
+ )
+ requires isMxValue(Destination)
+ [result(MxValue)]
+ context rustMxDirectEsdt
+ (... destination: Destination:MxOrRustValue
+ , tokenId: TokenId:MxOrRustValue
+ , nonce: HOLE:MxOrRustValue => rustToMx(HOLE)
+ , amount: _:MxOrRustValue
+ )
+ requires isMxValue(Destination)
+ andBool isMxValue(TokenId)
+ [result(MxValue)]
+ context rustMxDirectEsdt
+ (... destination: Destination:MxOrRustValue
+ , tokenId: TokenId:MxOrRustValue
+ , nonce: Nonce:MxOrRustValue
+ , amount: HOLE:MxOrRustValue => rustToMx(HOLE)
+ )
+ requires isMxValue(Destination)
+ andBool isMxValue(TokenId)
+ andBool isMxValue(Nonce)
+ [result(MxValue)]
+
+ rule rustMxDirectEsdt
+ (... destination: mxListValue(Destination:MxValue , .MxValueList)
+ , tokenId: mxListValue(mxStringValue(TokenId:String) , .MxValueList)
+ , nonce: mxIntValue(Nonce:Int)
+ , amount: mxIntValue(Amount:Int)
+ )
+ => MX#managedMultiTransferESDTNFTExecute
+ ( Destination
+ , mxTransfersValue
+ ( mxTransferValue(... token:TokenId, nonce:Nonce, value: Amount)
+ , .MxEsdtTransferList
+ )
+ , mxIntValue(0) // TODO: Use some gas value
+ , mxStringValue("")
+ , mxListValue(.MxValueList)
+ )
+
+endmodule
+
+```
diff --git a/mx-rust-semantics/main/preprocessing.md b/mx-rust-semantics/main/preprocessing.md
index 53598b5..2acaf98 100644
--- a/mx-rust-semantics/main/preprocessing.md
+++ b/mx-rust-semantics/main/preprocessing.md
@@ -1,10 +1,12 @@
```k
+requires "preprocessing/contract.md"
requires "preprocessing/methods.md"
requires "preprocessing/proxy.md"
requires "preprocessing/traits.md"
module MX-RUST-PREPROCESSING
+ imports private MX-RUST-PREPROCESSING-CONTRACT
imports private MX-RUST-PREPROCESSING-METHODS
imports private MX-RUST-PREPROCESSING-PROXY
imports private MX-RUST-PREPROCESSING-TRAITS
diff --git a/mx-rust-semantics/main/preprocessing/contract.md b/mx-rust-semantics/main/preprocessing/contract.md
new file mode 100644
index 0000000..53776de
--- /dev/null
+++ b/mx-rust-semantics/main/preprocessing/contract.md
@@ -0,0 +1,59 @@
+```k
+
+module MX-RUST-PREPROCESSING-CONTRACT
+ imports COMMON-K-CELL
+ imports MX-RUST-REPRESENTATION
+ imports RUST-PREPROCESSING-CONFIGURATION
+
+ syntax MxRustInstruction ::= rustMxAddContractSend(TypePath)
+
+ rule rustMxAddContractMethods(Trait:TypePath)
+ => rustMxAddContractSend(Trait:TypePath)
+
+ rule
+
+ rustMxAddContractSend(Trait:TypePath)
+ => error
+ ( "send already exists for trait"
+ , ListItem(Trait)
+ )
+ ...
+
+ Trait
+ #token("send", "Identifier")
+ [priority(50)]
+
+ rule
+
+ rustMxAddContractSend(Trait:TypePath)
+ => .K
+ ...
+
+ Trait
+ ( .Bag
+ =>
+ #token("send", "Identifier")
+ self : $selftype , .NormalizedFunctionParameterList
+ #token("MxRust#CallReturnType", "Identifier")
+
+ block({
+ .InnerAttributes
+ (
+ (
+ ( #token("MxRust#Send", "Identifier")
+ :: (#token("new", "Identifier"):PathExprSegment)
+ :: .PathExprSegments
+ )
+ ( .CallParamsList )
+ ):Expression
+ ):Statements
+ })
+
+ `emptyOuterAttributes`(.KList):OuterAttributes
+
+ )
+ [priority(100)]
+
+endmodule
+
+```
diff --git a/mx-rust-semantics/main/preprocessing/methods.md b/mx-rust-semantics/main/preprocessing/methods.md
index e3beff1..127dca2 100644
--- a/mx-rust-semantics/main/preprocessing/methods.md
+++ b/mx-rust-semantics/main/preprocessing/methods.md
@@ -64,7 +64,7 @@ module MX-RUST-PREPROCESSING-METHODS
T
MethodNames:List
- rule mxRustPreprocessMethods(_:TypePath, contract, .List) => .K
+ rule mxRustPreprocessMethods(Trait:TypePath, contract, .List) => rustMxAddContractMethods(Trait)
rule mxRustPreprocessMethods(Trait:TypePath, proxy, .List) => rustMxAddProxyMethods(Trait)
rule mxRustPreprocessMethods
diff --git a/mx-rust-semantics/main/representation.md b/mx-rust-semantics/main/representation.md
index c28c7a1..629aa5f 100644
--- a/mx-rust-semantics/main/representation.md
+++ b/mx-rust-semantics/main/representation.md
@@ -9,6 +9,7 @@ module MX-RUST-REPRESENTATION
syntax MxRustInstruction ::= "mxRustPreprocessTraits"
| mxRustPreprocessMethods(TypePath, TraitType)
+ | rustMxAddContractMethods(TypePath)
| rustMxAddProxyMethods(TypePath)
| mxRustCreateAccount(String)
| mxRustCreateContract
@@ -28,12 +29,15 @@ module MX-RUST-REPRESENTATION
| mxRustGetStringFromId(Int)
| mxRustNewStruct(MxRustStructType, CallParamsList)
[strict(2), result(ValueWithPtr)]
+ | "mxRustCheckMxStatus"
syntax TraitType ::= "contract" | "proxy"
syntax MxRustType ::= "noType" | rustType(Type)
syntax MxRustTypeOrError ::= MxRustType | SemanticsError
syntax Value ::= MxRustType
+ syntax MxOrRustValueOrInstruction ::= MxOrRustValue | MxRustInstruction
+
syntax Expression ::= concatString(Expression, Expression) [seqstrict]
| toString(Expression) [strict]
| rawValue(Value)
@@ -77,6 +81,7 @@ module MX-RUST-REPRESENTATION-CONVERSIONS
syntax MxOrRustValueListOrError ::= MxOrRustValueList | SemanticsError
syntax MxRustInstruction ::= mxToRustTyped(MxRustType)
+ // TODO: Merge rustToMx and rustValueToMx
syntax MxRustInstruction ::= rustToMx(MxOrRustValue)
| "rustToMx"
endmodule
diff --git a/tests/mx-rust-contracts/send.1.args b/tests/mx-rust-contracts/send.1.args
new file mode 100644
index 0000000..e69de29
diff --git a/tests/mx-rust-contracts/send.1.run b/tests/mx-rust-contracts/send.1.run
new file mode 100644
index 0000000..6688261
--- /dev/null
+++ b/tests/mx-rust-contracts/send.1.run
@@ -0,0 +1,42 @@
+addAccount("Caller");
+setBalance("TestContract", "MyToken", 0, 1234);
+setCallee("Caller");
+
+push mxIntValue(0);
+push mxStringValue("MyToken");
+push mxStringValue("Caller");
+call 3 MX#bigIntGetESDTExternalBalance;
+get_big_int;
+check_eq mxIntValue(0);
+
+push mxIntValue(0);
+push mxStringValue("MyToken");
+push mxStringValue("TestContract");
+call 3 MX#bigIntGetESDTExternalBalance;
+get_big_int;
+check_eq mxIntValue(1234);
+
+push mxListValue(mxStringValue("Caller"), mxStringValue("MyToken"), mxIntValue(10));
+push mxStringValue("sendTo");
+push mxIntValue(0);
+push mxTransfersValue();
+push mxIntValue(0);
+push mxStringValue("TestContract");
+call 6 MX#managedExecuteOnDestContext;
+get_big_int;
+check_eq mxIntValue(0);
+
+push mxIntValue(0);
+push mxStringValue("MyToken");
+push mxStringValue("Caller");
+call 3 MX#bigIntGetESDTExternalBalance;
+get_big_int;
+check_eq mxIntValue(10);
+
+push mxIntValue(0);
+push mxStringValue("MyToken");
+push mxStringValue("TestContract");
+call 3 MX#bigIntGetESDTExternalBalance;
+get_big_int;
+check_eq mxIntValue(1224)
+
diff --git a/tests/mx-rust-contracts/send.rs b/tests/mx-rust-contracts/send.rs
new file mode 100644
index 0000000..616673b
--- /dev/null
+++ b/tests/mx-rust-contracts/send.rs
@@ -0,0 +1,18 @@
+#![no_std]
+
+#[allow(unused_imports)]
+use multiversx_sc::imports::*;
+
+#[multiversx_sc::contract]
+pub trait Storage {
+ #[init]
+ fn init(&self) {}
+
+ #[upgrade]
+ fn upgrade(&self) {}
+
+ #[endpoint(sendTo)]
+ fn send_to(&self, address: ManagedAddress, token: TokenIdentifier, amount: BigUint) {
+ self.send().direct_esdt(address, token, 0_u64, amount);
+ }
+}