diff --git a/src/neo/SmartContract/ApplicationEngine.Runtime.cs b/src/neo/SmartContract/ApplicationEngine.Runtime.cs index 674a0cea9e..5c8f1dc79c 100644 --- a/src/neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/neo/SmartContract/ApplicationEngine.Runtime.cs @@ -1,6 +1,7 @@ using Neo.Cryptography.ECC; using Neo.IO; using Neo.Network.P2P.Payloads; +using Neo.SmartContract.Manifest; using Neo.SmartContract.Native; using Neo.SmartContract.Native.Oracle; using Neo.VM.Types; @@ -187,6 +188,39 @@ protected internal void SendNotification(UInt160 hash, string eventName, Array s Notify?.Invoke(this, notification); notifications ??= new List(); notifications.Add(notification); + + // React to transfer event + + if (eventName == "Transfer") + { + if (state.Count < 3) throw new ArgumentException("Wrong Transfer definition"); + + var to = state[1].GetSpan(); + if (to.Length != UInt160.Length) throw new ArgumentException("Wrong Transfer definition"); + + var contract = Snapshot.Contracts.TryGet(new UInt160(to)); + if (contract == null) return; + if (!contract.Payable) throw new InvalidOperationException("Not payable contract"); + + // Validate + + var method = contract.Manifest.Abi.GetMethod("_onPaymentReceived"); + if (method == null) return; + + ContractManifest currentManifest = Snapshot.Contracts.TryGet(CurrentScriptHash)?.Manifest; + if (currentManifest != null && !currentManifest.CanCall(contract.Manifest, method.Name)) + throw new InvalidOperationException($"Cannot Call Method {method} Of Contract {contract.ScriptHash} From Contract {CurrentScriptHash}"); + + // Call _fallback method + + CallContractInternal(contract, method, new Array(ReferenceCounter) + { + CurrentScriptHash.ToArray() /* Token */, + state[0].GetSpan().ToArray() /* From */, + state[2].GetInteger() /* Amount */ + }, + CallFlags.All, CheckReturnType.EnsureIsEmpty); + } } protected internal NotifyEventArgs[] GetNotifications(UInt160 hash)