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); + } +}