├── .github └── FUNDING.yml ├── .gitignore ├── .gitmodules ├── Build ├── Build_JSONRPC_Framework.dpr ├── Build_JSONRPC_Framework.dproj └── Build_JSONRPC_Framework.res ├── Client ├── Aptos │ ├── JSONRPC.AptosClient.dpr │ ├── JSONRPC.AptosClient.dproj │ ├── JSONRPC.AptosClient.res │ ├── JSONRPC.TransportWrapper.AptosHTTP.pas │ └── JSONRPC.Web3.AptosClient.Impl.pas ├── Ethereum │ ├── JSONRPC.EthereumClient.dpr │ ├── JSONRPC.EthereumClient.dproj │ └── JSONRPC.EthereumClient.res ├── JSONRPC.User.SomeTypes.Impl.pas └── README.md ├── Common ├── JSONRPC.Common.Consts.pas ├── JSONRPC.Common.FixBuggyNativeTypes.pas ├── JSONRPC.Common.RecordHandlers.pas ├── JSONRPC.Common.Types.pas ├── JSONRPC.HTTPTransportWrapper.pas ├── JSONRPC.InvokeRegistry.pas ├── JSONRPC.JsonUtils.pas ├── JSONRPC.RIO.pas ├── JSONRPC.TransportWrapper.HTTP.pas ├── JSONRPC.TransportWrapper.TCP.pas ├── JSONRPC.TransportWrapper.pas ├── JSONRPC.User.SomeTypes.pas └── README.md ├── JSONRPC_Group.groupproj ├── LICENSE.txt ├── README.dpr ├── README.dproj ├── README.md ├── Server ├── JSONRPC.CustomServerIdHTTP.Runner.pas ├── JSONRPC.Server.Consts.pas ├── JSONRPC.Server.Dispatcher.pas ├── JSONRPC.Server.JSONRPCHTTPServer.pas ├── JSONRPC.Server.Runner.pas ├── JSONRPC.ServerBase.Runner.pas ├── JSONRPC.ServerIdTCP.Runner.pas ├── JSONRPC.ServerNetHTTP.Runner.pas ├── JSONRPC.ServerTCP.Runner.pas ├── JSONRPC.ServerWebBroker.Runner.pas ├── JSONRPC.WebBrokerJSONRPC.pas ├── JSONRPCWebModule.dfm ├── JSONRPCWebModule.pas ├── README.md ├── WebModuleUnit1.dfm └── WebModuleUnit1.pas ├── Tests ├── TestJSONDictionaryConverter.Converters.pas ├── TestJSONDictionaryConverter.Types.pas ├── TestJSONDictionaryConverter.dpr ├── TestJSONDictionaryConverter.dproj ├── TestJSONDictionaryConverter.res ├── TestJSONDictionaryConverter1.Converters.pas ├── TestJSONDictionaryConverter1.dpr ├── TestJSONDictionaryConverter1.dproj ├── TestJSONDictionaryConverter2.Converters.pas ├── TestJSONDictionaryConverter2.dpr ├── TestJSONDictionaryConverter2.dproj ├── TestJSONDictionaryConverter2.res ├── TestJSONRPCGUI.dpr ├── TestJSONRPCGUI.dproj └── TestJSONRPCGUI.res ├── ThirdParty └── Neslib.MultiPrecision.RecordHandlers.pas ├── User └── JSONRPC.User.ServerImpl.pas ├── Web3 ├── Aptos │ ├── JSONRPC.AptosClient.dpr │ ├── JSONRPC.AptosClient.dproj │ ├── JSONRPC.AptosClient.res │ ├── JSONRPC.TransportWrapper.AptosHTTP.pas │ ├── JSONRPC.Web3.Aptos.Common.Types.pas │ ├── JSONRPC.Web3.Aptos.RIO.pas │ ├── JSONRPC.Web3.AptosAPI.pas │ ├── JSONRPC.Web3.AptosClient.Impl.pas │ └── Web3.AptosAPI.pas ├── Bitcoin │ ├── JSONRPC.BitcoinClient.dpr │ ├── JSONRPC.BitcoinClient.dproj │ ├── JSONRPC.BitcoinClient.res │ ├── JSONRPC.User.BitcoinRPC.pas │ ├── JSONRPC.User.BitcoinTypes.pas │ ├── JSONRPC.User.Types.BestBlockHash.pas │ ├── JSONRPC.User.Types.BlockDefaultInfo.pas │ ├── JSONRPC.User.Types.BlockInfo.pas │ ├── JSONRPC.User.Types.BlockchainInfo.pas │ ├── JSONRPC.User.Types.MemoryInfo.pas │ └── JSONRPC.User.Types.WalletInfo.pas ├── Ethereum │ ├── JSONRPC.EthereumClient.dpr │ ├── JSONRPC.EthereumClient.dproj │ ├── JSONRPC.EthereumClient.res │ ├── JSONRPC.Web3.Ethereum.Converters.pas │ ├── JSONRPC.Web3.Ethereum.RIO.pas │ ├── JSONRPC.Web3.Ethereum.Serializers.pas │ ├── JSONRPC.Web3.Ethereum.Types.pas │ └── JSONRPC.Web3.EthereumAPI.pas ├── JSONRPC.Web3.Clients.groupproj ├── JSONRPC.Web3.Common.Types.pas ├── JSONRPC.Web3.Serializers.pas ├── Polkadot │ ├── JSONRPC.PolkadotClient.dpr │ ├── JSONRPC.PolkadotClient.dproj │ ├── JSONRPC.PolkadotClient.res │ ├── JSONRPC.Web3.Polkadot.Types.pas │ └── JSONRPC.Web3.PolkadotAPI.pas └── Solana │ ├── JSONRPC.SolanaClient.dpr │ ├── JSONRPC.SolanaClient.dproj │ ├── JSONRPC.SolanaClient.res │ ├── JSONRPC.Web3.Solana.Attributes.pas │ ├── JSONRPC.Web3.Solana.Consts.pas │ ├── JSONRPC.Web3.Solana.Converters.pas │ ├── JSONRPC.Web3.Solana.CustomConverters.pas │ ├── JSONRPC.Web3.Solana.Encoding.pas │ ├── JSONRPC.Web3.Solana.RIO.pas │ ├── JSONRPC.Web3.SolanaAPI.pas │ ├── JSONRPC.Web3.SolanaClient.pas │ ├── JSONRPC.Web3.SolanaTypes.getAccountInfoResultsType.pas │ ├── JSONRPC.Web3.SolanaTypes.getVoteAccountResultsType.pas │ ├── JSONRPC.Web3.SolanaTypes.pas │ └── Solana-README.md └── Wizard ├── JSONRPC.App.Form.dfm ├── JSONRPC.App.Form.pas ├── JSONRPC.App.Wizard.dfm ├── JSONRPC.App.Wizard.pas ├── JSONRPC.AppWizard.dpr ├── JSONRPC.AppWizard.dproj ├── JSONRPC.AppWizard.res ├── JSONRPC.DelphiUnitCreator.pas └── JSONRPC.Wizard.Consts.pas /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: chuacw 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Uncomment these types if you want even more clean repository. But be careful. 2 | # It can make harm to an existing project source. Read explanations below. 3 | # 4 | # Resource files are binaries containing manifest, project icon and version info. 5 | # They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files. 6 | #*.res 7 | # 8 | # Type library file (binary). In old Delphi versions it should be stored. 9 | # Since Delphi 2009 it is produced from .ridl file and can safely be ignored. 10 | #*.tlb 11 | # 12 | # Diagram Portfolio file. Used by the diagram editor up to Delphi 7. 13 | # Uncomment this if you are not using diagrams or use newer Delphi version. 14 | #*.ddp 15 | # 16 | # Visual LiveBindings file. Added in Delphi XE2. 17 | # Uncomment this if you are not using LiveBindings Designer. 18 | #*.vlb 19 | # 20 | # Deployment Manager configuration file for your project. Added in Delphi XE2. 21 | # Uncomment this if it is not mobile development and you do not use remote debug feature. 22 | #*.deployproj 23 | # 24 | # C++ object files produced when C/C++ Output file generation is configured. 25 | # Uncomment this if you are not using external objects (zlib library for example). 26 | #*.obj 27 | # 28 | 29 | # Delphi compiler-generated binaries (safe to delete) 30 | *.exe 31 | *.dll 32 | *.bpl 33 | *.bpi 34 | *.dcp 35 | *.so 36 | *.apk 37 | *.drc 38 | *.map 39 | *.dres 40 | *.rsm 41 | *.tds 42 | *.dcu 43 | *.lib 44 | *.a 45 | *.o 46 | *.ocx 47 | 48 | # Delphi autogenerated files (duplicated info) 49 | *.cfg 50 | *.hpp 51 | *Resource.rc 52 | *.cmds 53 | 54 | # Delphi local files (user-specific info) 55 | *.local 56 | *.identcache 57 | *.projdata 58 | *.tvsconfig 59 | *.dsk 60 | 61 | # Delphi history and backups 62 | __history/ 63 | __recovery/ 64 | *.~* 65 | 66 | # Castalia statistics file (since XE7 Castalia is distributed with Delphi) 67 | *.stat 68 | 69 | # Boss dependency manager vendor folder https://github.com/HashLoad/boss 70 | modules/ 71 | 72 | # Environment 73 | .env 74 | 75 | Win32/ 76 | Win64/ 77 | Linux64/ 78 | Debug/ 79 | Release/ 80 | Android64/ 81 | 82 | TestInsightSettings.ini 83 | dunitx-results.xml 84 | README.res 85 | Examples/ 86 | 87 | *._@emb_.tmp 88 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ThirdParty/Neslib.MultiPrecision"] 2 | path = ThirdParty/Neslib.MultiPrecision 3 | url = https://github.com/neslib/Neslib.MultiPrecision.git 4 | -------------------------------------------------------------------------------- /Build/Build_JSONRPC_Framework.dpr: -------------------------------------------------------------------------------- 1 | {---------------------------------------------------------------------------} 2 | { } 3 | { File: Build_JSONRPC_Framework.dpr } 4 | { Function: Builds the JSON RPC framework } 5 | { } 6 | { Language: Delphi version XE11 or later } 7 | { Author: Chee-Wee Chua } 8 | { Copyright: (c) 2023,2024 Chee-Wee Chua } 9 | {---------------------------------------------------------------------------} 10 | program Build_JSONRPC_Framework; 11 | 12 | {$APPTYPE CONSOLE} 13 | {$WARN DUPLICATE_CTOR_DTOR OFF} 14 | {$R *.res} 15 | 16 | uses 17 | System.SysUtils, 18 | JSONRPC.TransportWrapper.HTTP in '..\Common\JSONRPC.TransportWrapper.HTTP.pas', 19 | JSONRPC.RIO in '..\Common\JSONRPC.RIO.pas', 20 | JSONRPC.JsonUtils in '..\Common\JSONRPC.JsonUtils.pas', 21 | JSONRPC.InvokeRegistry in '..\Common\JSONRPC.InvokeRegistry.pas', 22 | JSONRPC.Common.Types in '..\Common\JSONRPC.Common.Types.pas', 23 | JSONRPC.Common.RecordHandlers in '..\Common\JSONRPC.Common.RecordHandlers.pas', 24 | JSONRPC.Common.Consts in '..\Common\JSONRPC.Common.Consts.pas', 25 | JSONRPC.ServerBase.Runner in '..\Server\JSONRPC.ServerBase.Runner.pas', 26 | JSONRPC.Server.JSONRPCHTTPServer in '..\Server\JSONRPC.Server.JSONRPCHTTPServer.pas', 27 | JSONRPC.Server.Consts in '..\Server\JSONRPC.Server.Consts.pas', 28 | JSONRPC.CustomServerIdHTTP.Runner in '..\Server\JSONRPC.CustomServerIdHTTP.Runner.pas', 29 | JSONRPC.Common.FixBuggyNativeTypes in '..\Common\JSONRPC.Common.FixBuggyNativeTypes.pas'; 30 | 31 | begin 32 | // Just for building all files 33 | end. 34 | -------------------------------------------------------------------------------- /Build/Build_JSONRPC_Framework.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuacw/JSONRPC_Framework/9463b711d858b7fb91051146b757951923aa1441/Build/Build_JSONRPC_Framework.res -------------------------------------------------------------------------------- /Client/Aptos/JSONRPC.AptosClient.dpr: -------------------------------------------------------------------------------- 1 | program JSONRPC.AptosClient; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | {$R *.res} 6 | 7 | uses 8 | System.SysUtils, 9 | System.JSON, 10 | JSONRPC.TransportWrapper.HTTP in '..\..\Common\JSONRPC.TransportWrapper.HTTP.pas', 11 | JSONRPC.RIO in '..\..\Common\JSONRPC.RIO.pas', 12 | JSONRPC.JsonUtils in '..\..\Common\JSONRPC.JsonUtils.pas', 13 | JSONRPC.InvokeRegistry in '..\..\Common\JSONRPC.InvokeRegistry.pas', 14 | JSONRPC.Common.Types in '..\..\Common\JSONRPC.Common.Types.pas', 15 | JSONRPC.Common.Consts in '..\..\Common\JSONRPC.Common.Consts.pas', 16 | JSONRPC.Common.RecordHandlers in '..\..\Common\JSONRPC.Common.RecordHandlers.pas', 17 | JSONRPC.Web3.AptosClient.Impl in 'JSONRPC.Web3.AptosClient.Impl.pas', 18 | JSONRPC.Web3.AptosAPI in '..\..\Web3\Aptos\JSONRPC.Web3.AptosAPI.pas', 19 | JSONRPC.TransportWrapper.AptosHTTP in 'JSONRPC.TransportWrapper.AptosHTTP.pas', 20 | JSONRPC.Web3.Aptos.Common.Types in '..\..\Web3\Aptos\JSONRPC.Web3.Aptos.Common.Types.pas', 21 | Web3.Aptos.RIO in '..\..\Web3\Aptos\Web3.Aptos.RIO.pas'; 22 | 23 | procedure AssignSafeCallException(const AJSONRPC: IAptosJSONRPC); 24 | begin 25 | AssignJSONRPCSafeCallExceptionHandler(AJSONRPC, 26 | function (ExceptObject: TObject; ExceptAddr: Pointer): HResult 27 | var 28 | LExc: EJSONRPCException; 29 | LExcMethod: EJSONRPCMethodException absolute LExc; 30 | begin 31 | if ExceptObject is EJSONRPCException then 32 | begin 33 | LExc := ExceptObject as EJSONRPCException; 34 | WriteLn('Intercepted safecall exception...'); 35 | Write(Format('message: "%s", code: %d', [LExc.Message, LExc.Code])); 36 | if LExc is EJSONRPCMethodException then 37 | begin 38 | Write(Format(', method: "%s"', [LExcMethod.MethodName])); 39 | end; 40 | WriteLn; 41 | WriteLn(StringOfChar('-', 90)); 42 | end else 43 | if ExceptObject is Exception then 44 | begin 45 | var LExcObj := ExceptObject as Exception; 46 | WriteLn('Intercepted safecall exception...'); 47 | WriteLn(Format('message: "%s"', [LExcObj.Message])); 48 | end; 49 | Result := S_OK; // Clear the error otherwise, CheckAutoResult will raise error 50 | end 51 | ); 52 | end; 53 | 54 | function GetAptosClient(const AURL: string): IAptosJSONRPC; 55 | begin 56 | Result := GetAptosJSONRPC(AURL, 57 | procedure(const AJSONRPCRequest: string) 58 | begin 59 | WriteLn('Sending outgoing request: ', AJSONRPCRequest); 60 | end, 61 | procedure(const AJSONRPCResponse: string) 62 | begin 63 | WriteLn('Received incoming response: ', AJSONRPCResponse); 64 | WriteLn(StringOfChar('-', 80)); 65 | WriteLn; 66 | end, 67 | procedure(const AServerURL: string) 68 | begin 69 | WriteLn('Sending request to ', AServerURL); 70 | WriteLn(StringOfChar('-', 80)); 71 | WriteLn; 72 | end 73 | ); 74 | end; 75 | 76 | procedure RunAptosClient; 77 | begin 78 | var LAptosClient := GetAptosClient(AptosMainNet); 79 | var LJSONGetBlocksByVersion := LAptosClient.GetBlocksByVersion(2309044); 80 | var LGetBlocksByHeight := LAptosClient.GetBlocksByHeight(67193037); 81 | var LAccountResource := LAptosClient.GetAccountResource( 82 | '0xe54a8cf97f4a788b0a792654c6fcb02d10250cc2dacb09a424d67f7c48e2533f', 83 | '0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>' 84 | ); 85 | end; 86 | 87 | begin 88 | ReportMemoryLeaksOnShutdown := True; 89 | try 90 | RunAptosClient; 91 | except 92 | on E: Exception do 93 | WriteLn('Ran into some exception: ', E.Message); 94 | end; 95 | end. 96 | -------------------------------------------------------------------------------- /Client/Aptos/JSONRPC.AptosClient.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuacw/JSONRPC_Framework/9463b711d858b7fb91051146b757951923aa1441/Client/Aptos/JSONRPC.AptosClient.res -------------------------------------------------------------------------------- /Client/Aptos/JSONRPC.TransportWrapper.AptosHTTP.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.TransportWrapper.AptosHTTP; 2 | 3 | interface 4 | 5 | uses 6 | JSONRPC.TransportWrapper.HTTP, System.Classes, System.Net.URLClient; 7 | 8 | type 9 | TJSONRPCHTTPTransportAptosWrapper = class(TJSONRPCHTTPTransportWrapper) 10 | public 11 | procedure Post(const AURL: string; const ASource, AResponseContent: TStream; 12 | const AHeaders: TNetHeaders); override; 13 | end; 14 | 15 | implementation 16 | 17 | uses 18 | JSONRPC.Common.Types; 19 | 20 | { TJSONRPCHTTPTransportAptosWrapper } 21 | 22 | procedure TJSONRPCHTTPTransportAptosWrapper.Post(const AURL: string; 23 | const ASource, AResponseContent: TStream; const AHeaders: TNetHeaders); 24 | begin 25 | FClient.Get(AURL, AResponseContent, AHeaders); 26 | end; 27 | 28 | procedure InitTransportWrapperHTTP; 29 | begin 30 | GJSONRPCTransportWrapperClass := TJSONRPCHTTPTransportAptosWrapper; 31 | end; 32 | 33 | initialization 34 | InitTransportWrapperHTTP; 35 | end. 36 | -------------------------------------------------------------------------------- /Client/Aptos/JSONRPC.Web3.AptosClient.Impl.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.Web3.AptosClient.Impl; 2 | 3 | {$ALIGN 16} 4 | {$CODEALIGN 16} 5 | 6 | interface 7 | 8 | uses 9 | JSONRPC.Common.Types, System.Classes, System.JSON.Serializers, 10 | JSONRPC.RIO, JSONRPC.Web3.AptosAPI; 11 | 12 | function GetAptosJSONRPC(const ServerURL: string = ''; 13 | const AOnLoggingOutgoingJSONRequest: TOnLogOutgoingJSONRequest = nil; 14 | const AOnLoggingIncomingJSONResponse: TOnLogIncomingJSONResponse = nil; 15 | const AOnLogServerURL: TOnLogServerURL = nil 16 | ): IAptosJSONRPC; 17 | 18 | implementation 19 | 20 | uses 21 | {$IF DEFINED(TEST) OR DEFINED(DEBUG)} 22 | Winapi.Windows, 23 | {$ENDIF} 24 | JSONRPC.Common.Consts, 25 | System.JSON, System.Rtti, JSONRPC.InvokeRegistry, 26 | JSONRPC.JsonUtils, Web3.Aptos.RIO; 27 | 28 | function GetAptosJSONRPC(const ServerURL: string = ''; 29 | const AOnLoggingOutgoingJSONRequest: TOnLogOutgoingJSONRequest = nil; 30 | const AOnLoggingIncomingJSONResponse: TOnLogIncomingJSONResponse = nil; 31 | const AOnLogServerURL: TOnLogServerURL = nil 32 | ): IAptosJSONRPC; 33 | begin 34 | RegisterJSONRPCWrapper(TypeInfo(IAptosJSONRPC)); 35 | 36 | var LJSONRPCWrapper := TWeb3AptosJSONRPCWrapper.Create(nil); 37 | LJSONRPCWrapper.ServerURL := ServerURL; 38 | 39 | LJSONRPCWrapper.OnLogOutgoingJSONRequest := AOnLoggingOutgoingJSONRequest; 40 | LJSONRPCWrapper.OnLogIncomingJSONResponse := AOnLoggingIncomingJSONResponse; 41 | LJSONRPCWrapper.OnLogServerURL := AOnLogServerURL; 42 | 43 | Result := LJSONRPCWrapper as IAptosJSONRPC; 44 | 45 | {$IF DECLARED(IsDebuggerPresent)} 46 | if IsDebuggerPresent then 47 | begin 48 | LJSONRPCWrapper.SendTimeout := 10*60*1000; 49 | LJSONRPCWrapper.ResponseTimeout := LJSONRPCWrapper.SendTimeout; 50 | {$IF RTLVersion >= TRTLVersion.Delphi120 } 51 | LJSONRPCWrapper.ConnectionTimeout := LJSONRPCWrapper.SendTimeout; 52 | {$ENDIF} 53 | end; 54 | {$ENDIF} 55 | 56 | end; 57 | 58 | end. 59 | -------------------------------------------------------------------------------- /Client/Ethereum/JSONRPC.EthereumClient.dpr: -------------------------------------------------------------------------------- 1 | program JSONRPC.EthereumClient; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | {$R *.res} 6 | 7 | uses 8 | System.Variants, 9 | JSONRPC.RIO in '..\..\Common\JSONRPC.RIO.pas', 10 | System.Classes, 11 | System.Rtti, 12 | System.JSON, 13 | System.SysUtils, 14 | System.TypInfo, 15 | Winapi.Windows, 16 | System.DateUtils, 17 | System.JSON.Writers, 18 | JSONRPC.Common.Consts in '..\..\Common\JSONRPC.Common.Consts.pas', 19 | JSONRPC.InvokeRegistry in '..\..\Common\JSONRPC.InvokeRegistry.pas', 20 | JSONRPC.User.SomeTypes in '..\..\Common\JSONRPC.User.SomeTypes.pas', 21 | JSONRPC.Common.Types in '..\..\Common\JSONRPC.Common.Types.pas', 22 | JSONRPC.JsonUtils in '..\..\Common\JSONRPC.JsonUtils.pas', 23 | JSONRPC.TransportWrapper.HTTP in '..\..\Common\JSONRPC.TransportWrapper.HTTP.pas', 24 | JSONRPC.TransportWrapper.TCP in '..\..\Common\JSONRPC.TransportWrapper.TCP.pas', 25 | System.Net.ClientSocket in '..\..\..\NetSocket\Client\System.Net.ClientSocket.pas', 26 | System.Net.Socket.Common in '..\..\..\NetSocket\Common\System.Net.Socket.Common.pas', 27 | Web3.Common.Types in '..\..\Web3\Web3.Common.Types.pas', 28 | Web3.Serializers in '..\..\Web3\Web3.Serializers.pas', 29 | Web3.JsonUtils in '..\..\Web3\Web3.JsonUtils.pas', 30 | JSONRPC.Common.RecordHandlers in '..\..\Common\JSONRPC.Common.RecordHandlers.pas', 31 | Web3.Ethereum.Types in '..\..\Web3\Ethereum\Web3.Ethereum.Types.pas', 32 | Web3.EtheerumAPI in '..\..\Web3\Ethereum\Web3.EtheerumAPI.pas', 33 | Web3.Ethereum.RIO in '..\..\Web3\Ethereum\Web3.Ethereum.RIO.pas', 34 | Web3.Ethereum.Serializers in '..\..\Web3\Ethereum\Web3.Ethereum.Serializers.pas'; 35 | 36 | procedure AssignSafeCallException(const AJSONRPC: IEthereumJSONRPC); 37 | begin 38 | AssignJSONRPCSafeCallExceptionHandler(AJSONRPC, 39 | function (ExceptObject: TObject; ExceptAddr: Pointer): HResult 40 | var 41 | LExc: EJSONRPCException; 42 | LExcMethod: EJSONRPCMethodException absolute LExc; 43 | begin 44 | if ExceptObject is EJSONRPCException then 45 | begin 46 | LExc := ExceptObject as EJSONRPCException; 47 | WriteLn('Intercepted safecall exception...'); 48 | Write(Format('message: "%s", code: %d', [LExc.Message, LExc.Code])); 49 | if LExc is EJSONRPCMethodException then 50 | begin 51 | Write(Format(', method: "%s"', [LExcMethod.MethodName])); 52 | end; 53 | WriteLn; 54 | WriteLn(StringOfChar('-', 90)); 55 | end else 56 | if ExceptObject is Exception then 57 | begin 58 | var LExcObj := ExceptObject as Exception; 59 | WriteLn('Intercepted safecall exception...'); 60 | WriteLn(Format('message: "%s"', [LExcObj.Message])); 61 | end; 62 | Result := S_OK; // Clear the error otherwise, CheckAutoResult will raise error 63 | end 64 | ); 65 | end; 66 | 67 | procedure Main; 68 | begin 69 | 70 | var EthereumJSONRPC := GetEthereumJSONRPC('https://rpc.ankr.com/eth_goerli'); 71 | AssignSafeCallException(EthereumJSONRPC); 72 | var LEthSyncing := EthereumJSONRPC.eth_syncing; 73 | var LgetBlockByHashResult := EthereumJSONRPC.eth_getBlockByHash('0x7c081ccbb9fa8db1fd68d093389391c72c649e26a77ae7a2c5b92546c8782ad3', false); 74 | 75 | // var Signature := EthereumJSONRPC.eth_sign( 76 | // '0x9b2055d370f73ec7d8a03e965129118dc8f5bf83', 77 | // '0xdeadbeaf' 78 | // ); 79 | // var blockNumber := EthereumJSONRPC.eth_blockNumber; 80 | // var LBytes: TBytes := [$68, $65, $6c, $6c, $6f, $20, $77, $6f, $72, $6c, $64]; 81 | var Lweb3_sha3Hash := EthereumJSONRPC.web3_sha3('0x68656c6c6f20776f726c64'); 82 | var Lweb3_clientVersion := EthereumJSONRPC.web3_clientVersion; 83 | var Lnetversion := EthereumJSONRPC.net_version; 84 | var Lnetlistening := EthereumJSONRPC.net_listening; 85 | // var LnetPeerCount := EthereumJSONRPC.net_peerCount; // doesn't exist 86 | var LProtocolVersion := EthereumJSONRPC.eth_protocolVersion; 87 | var transactionReceipt := EthereumJSONRPC.eth_getTransactionReceipt('0x85d995eba9763907fdf35cd2034144dd9d53ce32cbec21349d4b12823c6860c5'); 88 | 89 | var balance := EthereumJSONRPC.eth_getBalance('0x407d73d8a49eeb85d32cf465507dd71d507100c1', 90 | TBlockNumber.latest); 91 | var tranObj: TransactionObject; 92 | tranObj.from := '0xb60e8dd61c5d32be8058bb8eb970870f07233155'; 93 | tranObj.&to := '0xd46e8dd67c5d32be8058bb8eb970870f07244567'; 94 | tranObj.gas := '0x76c0'; 95 | tranObj.gasPrice := '0x9184e72a000'; 96 | tranObj.value := '0x9184e72a'; 97 | tranObj.data := '0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675'; 98 | var tranObjHash := EthereumJSONRPC.eth_sendTransaction(tranObj); 99 | EthereumJSONRPC := nil; 100 | end; 101 | 102 | begin 103 | try 104 | ReportMemoryLeaksOnShutdown := True; 105 | Main; 106 | finally 107 | Write('Press enter to terminate...'); 108 | ReadLn; 109 | end; 110 | end. 111 | -------------------------------------------------------------------------------- /Client/Ethereum/JSONRPC.EthereumClient.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuacw/JSONRPC_Framework/9463b711d858b7fb91051146b757951923aa1441/Client/Ethereum/JSONRPC.EthereumClient.res -------------------------------------------------------------------------------- /Client/JSONRPC.User.SomeTypes.Impl.pas: -------------------------------------------------------------------------------- 1 | {---------------------------------------------------------------------------} 2 | { } 3 | { File: JSONRPC.User.SomeTypes.pas } 4 | { Function: Example client implementation of getting JSON RPC interface } 5 | { } 6 | { Language: Delphi version XE11 or later } 7 | { Author: Chee-Wee Chua } 8 | { Copyright: (c) 2023,2024 Chee-Wee Chua } 9 | {---------------------------------------------------------------------------} 10 | unit JSONRPC.User.SomeTypes.Impl; 11 | 12 | {$ALIGN 16} 13 | {$CODEALIGN 16} 14 | 15 | interface 16 | 17 | uses 18 | JSONRPC.Common.Types, System.Classes, System.JSON.Serializers, 19 | JSONRPC.RIO, JSONRPC.User.SomeTypes; 20 | 21 | function GetSomeJSONRPC(const ServerURL: string = ''; 22 | const AOnLoggingOutgoingJSONRequest: TOnLogOutgoingJSONRequest = nil; 23 | const AOnLoggingIncomingJSONResponse: TOnLogIncomingJSONResponse = nil; 24 | const AWrapperType: TTransportWrapperType = twtHTTP; 25 | const AOnBeforeParse: TOnBeforeParseEvent = nil; 26 | const AOnSyncProc: TOnSyncEvent = nil; 27 | const AUseDefaultProcs: Boolean = True 28 | ): ISomeJSONRPC; 29 | 30 | implementation 31 | 32 | uses 33 | {$IF (DEFINED(TEST) OR DEFINED(DEBUG)) AND DEFINED(MSWINDOWS)} 34 | Winapi.Windows, 35 | {$ENDIF} 36 | JSONRPC.Common.Consts, 37 | System.JSON, System.Rtti, JSONRPC.InvokeRegistry, 38 | JSONRPC.JsonUtils; 39 | 40 | function GetSomeJSONRPC( 41 | const ServerURL: string = ''; 42 | const AOnLoggingOutgoingJSONRequest: TOnLogOutgoingJSONRequest = nil; 43 | const AOnLoggingIncomingJSONResponse: TOnLogIncomingJSONResponse = nil; 44 | const AWrapperType: TTransportWrapperType = twtHTTP; 45 | const AOnBeforeParse: TOnBeforeParseEvent = nil; 46 | const AOnSyncProc: TOnSyncEvent = nil; 47 | const AUseDefaultProcs: Boolean = True 48 | ): ISomeJSONRPC; 49 | begin 50 | {$IF DEFINED(TEST)} 51 | // Developed to send rubbish data to check server tolerance 52 | RegisterJSONRPCWrapper(TypeInfo(ISomeExtendedJSONRPC)); 53 | {$ENDIF} 54 | 55 | RegisterJSONRPCWrapper(TypeInfo(ISomeJSONRPC)); 56 | 57 | var LJSONRPCWrapper := TJSONRPCWrapper.Create(nil); 58 | LJSONRPCWrapper.ServerURL := ServerURL; 59 | 60 | LJSONRPCWrapper.OnLogOutgoingJSONRequest := AOnLoggingOutgoingJSONRequest; 61 | LJSONRPCWrapper.OnLogIncomingJSONResponse := AOnLoggingIncomingJSONResponse; 62 | 63 | Result := LJSONRPCWrapper as ISomeJSONRPC; 64 | 65 | {$IF DECLARED(IsDebuggerPresent)} 66 | if IsDebuggerPresent then 67 | begin 68 | var LTimeout := 10*60*1000; 69 | LJSONRPCWrapper.SendTimeout := LTimeout; 70 | LJSONRPCWrapper.ResponseTimeout := LTimeout; 71 | {$IF RTLVersion >= TRTLVersion.Delphi120 } 72 | LJSONRPCWrapper.ConnectionTimeout := LTimeout; 73 | {$ENDIF} 74 | end; 75 | {$ENDIF} 76 | 77 | {$IF DEFINED(TEST)} 78 | // OnSync is typically not used, unless you're testing something, 79 | // in this case, just copy the request into the response 80 | if ServerURL = '' then 81 | begin 82 | if UseDefaultProcs then 83 | begin 84 | LJSONRPCWrapper.OnSync := procedure (ARequest, AResponse: TStream) 85 | begin 86 | AResponse.CopyFrom(ARequest); 87 | end; 88 | 89 | LJSONRPCWrapper.OnBeforeParse := procedure (const AContext: TInvContext; 90 | AMethNum: Integer; const AMethMD: TIntfMethEntry; const AMethodID: Int64; 91 | AJSONResponse: TStream) 92 | begin 93 | // This is where the client can pretend to be a server, look at the response, 94 | // which is actually the request, and then clear the response stream and 95 | // write its actual response into it... 96 | if (AJSONResponse.Size <> 0) and (AMethMD.Name = 'AddSomeXY') then 97 | begin 98 | AJSONResponse.Position := 0; 99 | 100 | var LBytes: TArray; 101 | SetLength(LBytes, AJSONResponse.Size); 102 | AJSONResponse.Read(LBytes[0], AJSONResponse.Size); 103 | // var LJSONResponseStr := TEncoding.UTF8.GetString(LBytes); 104 | 105 | // THIS BUG WILL KILL / HANG THE DEBUGGER, on exit of this method 106 | // var LJSONResponseStr := ''; 107 | // AJSONResponse.Read(LJSONResponseStr, AJSONResponse.Size); 108 | 109 | var LJSONObj := TJSONObject.ParseJSONValue(LBytes, 0); 110 | try 111 | var LX: Integer := LJSONObj.GetValue('params.X'); 112 | var LY: Integer := LJSONObj.GetValue('params.Y'); 113 | var LValue: TValue := LX + LY; 114 | AJSONResponse.Size := 0; 115 | WriteJSONResult(AMethNum, AMethMD.ResultInfo, AMethodID, LValue, AJSONResponse); 116 | finally 117 | LJSONObj.Free; 118 | end; 119 | end; 120 | end; 121 | 122 | end else 123 | begin 124 | LJSONRPCWrapper.OnSync := AOnSyncProc; 125 | LJSONRPCWrapper.OnBeforeParse := AOnBeforeParse; 126 | end; 127 | 128 | // Do anything to the JSON response stream, before parsing starts... 129 | // Since there's no server, write response data into the server response, so that it can be parsed 130 | 131 | end; 132 | {$ENDIF} 133 | 134 | end; 135 | 136 | initialization 137 | InvRegistry.RegisterInterface(TypeInfo(ISomeJSONRPC)); 138 | {$IF DEFINED(TEST)} 139 | // Developed to send rubbish data to check server tolerance 140 | InvRegistry.RegisterInterface(TypeInfo(ISomeExtendedJSONRPC)); 141 | {$ENDIF} 142 | end. 143 | -------------------------------------------------------------------------------- /Client/README.md: -------------------------------------------------------------------------------- 1 | This directory contains code that should only be implemented/used on the client side. 2 | 3 | To centralize exception handling, ie, use a single assigned exception handler, 4 | mark all methods with a safecall directive. 5 | To support exception handling with "try ... except", surround the method call with 6 | the exception handler, and do not mark the concerned method with a safecall directive. 7 | -------------------------------------------------------------------------------- /Common/JSONRPC.Common.FixBuggyNativeTypes.pas: -------------------------------------------------------------------------------- 1 | {---------------------------------------------------------------------------} 2 | { } 3 | { File: JSONRPC.Common.FixBuggyNativeTypes.pas } 4 | { Function: Fixes FloatToJson } 5 | { } 6 | { Language: Delphi version XE11 or later } 7 | { Author: Chee-Wee Chua } 8 | { Copyright: (c) 2023,2024 Chee-Wee Chua } 9 | {---------------------------------------------------------------------------} 10 | unit JSONRPC.Common.FixBuggyNativeTypes; 11 | 12 | {$ALIGN 16} 13 | {$CODEALIGN 16} 14 | 15 | interface 16 | 17 | const 18 | DelphiAthens = 36.0; 19 | Delphi120 = 36.0; 20 | 21 | function FixedFloatToJson(const Value: Extended): string; 22 | {$IF RTLVersion >= Delphi120 } 23 | inline; 24 | {$ENDIF} 25 | 26 | implementation 27 | 28 | uses 29 | {$IF RTLVersion < Delphi120 } 30 | System.SysUtils, 31 | {$ENDIF} 32 | System.JSON; 33 | 34 | function FixedFloatToJson(const Value: Extended): string; 35 | {$IF RTLVersion < Delphi120 } // System 36 | var 37 | Buffer: array[0..63] of Char; 38 | L: Integer; 39 | begin 40 | L := FloatToText(Buffer, Value, fvExtended, ffGeneral, 17, 0, GetJSONFormat); 41 | Buffer[L] := #0; 42 | if StrScan(Buffer, '.') = nil then 43 | begin 44 | Buffer[L] := '.'; 45 | Buffer[L + 1] := '0'; 46 | Inc(L, 2); 47 | end; 48 | SetString(Result, Buffer, L); 49 | {$ELSE} 50 | begin 51 | Result := System.JSON.FloatToJson(Value); 52 | {$ENDIF} 53 | end; 54 | 55 | end. 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | // chuacw, Jun 2023 92 | 93 | -------------------------------------------------------------------------------- /Common/JSONRPC.HTTPTransportWrapper.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.HTTPTransportWrapper; 2 | 3 | interface 4 | 5 | uses 6 | JSONRPC.Common.Types, System.Classes, 7 | System.Net.HttpClient, System.Net.URLClient; 8 | 9 | type 10 | 11 | TJSONRPCHTTPTransportWrapper = class(TJSONRPCTransportWrapper) 12 | protected 13 | FClient: THTTPClient; 14 | 15 | function GetConnectionTimeout: Integer; override; 16 | function GetResponseTimeout: Integer; override; 17 | function GetSendTimeout: Integer; override; 18 | procedure SetConnectionTimeout(const Value: Integer); override; 19 | procedure SetResponseTimeout(const Value: Integer); override; 20 | procedure SetSendTimeout(const Value: Integer); override; 21 | public 22 | constructor Create; override; 23 | destructor Destroy; override; 24 | procedure Post(const AURL: string; const ASource, AResponseContent: TStream; 25 | const AHeaders: TNetHeaders); override; 26 | end; 27 | 28 | implementation 29 | 30 | { TJSONRPCHTTPTransportWrapper } 31 | 32 | constructor TJSONRPCHTTPTransportWrapper.Create; 33 | begin 34 | inherited; 35 | FClient := THTTPClient.Create; 36 | end; 37 | 38 | destructor TJSONRPCHTTPTransportWrapper.Destroy; 39 | begin 40 | FClient.Free; 41 | inherited; 42 | end; 43 | 44 | function TJSONRPCHTTPTransportWrapper.GetConnectionTimeout: Integer; 45 | begin 46 | Result := FClient.ConnectionTimeout; 47 | end; 48 | 49 | function TJSONRPCHTTPTransportWrapper.GetResponseTimeout: Integer; 50 | begin 51 | Result := FClient.ResponseTimeout; 52 | end; 53 | 54 | function TJSONRPCHTTPTransportWrapper.GetSendTimeout: Integer; 55 | begin 56 | Result := FClient.SendTimeout; 57 | end; 58 | 59 | procedure TJSONRPCHTTPTransportWrapper.Post(const AURL: string; const ASource, 60 | AResponseContent: TStream; const AHeaders: TNetHeaders); 61 | begin 62 | FClient.Post(AURL, ASource, AResponseContent, AHeaders); 63 | end; 64 | 65 | procedure TJSONRPCHTTPTransportWrapper.SetConnectionTimeout( 66 | const Value: Integer); 67 | begin 68 | FClient.ConnectionTimeout := Value; 69 | end; 70 | 71 | procedure TJSONRPCHTTPTransportWrapper.SetResponseTimeout(const Value: Integer); 72 | begin 73 | FClient.ResponseTimeout := Value; 74 | end; 75 | 76 | procedure TJSONRPCHTTPTransportWrapper.SetSendTimeout(const Value: Integer); 77 | begin 78 | FClient.SendTimeout := Value; 79 | end; 80 | 81 | end. 82 | -------------------------------------------------------------------------------- /Common/JSONRPC.TransportWrapper.TCP.pas: -------------------------------------------------------------------------------- 1 | {---------------------------------------------------------------------------} 2 | { } 3 | { File: JSONRPC.TransportWrapper.TCP.pas } 4 | { Function: TCP tranport wrapper for JSON RPC } 5 | { } 6 | { Language: Delphi version XE11 or later } 7 | { Author: Chee-Wee Chua } 8 | { Copyright: (c) 2023,2024 Chee-Wee Chua } 9 | {---------------------------------------------------------------------------} 10 | unit JSONRPC.TransportWrapper.TCP; 11 | 12 | interface 13 | 14 | uses 15 | JSONRPC.Common.Types, System.Classes, 16 | System.Net.URLClient, 17 | System.Net.ClientSocket, System.Net.Socket.Common, System.SysUtils, 18 | JSONRPC.Common.Consts; 19 | 20 | type 21 | 22 | TJSONRPCTCPTransportWrapper = class(TJSONRPCTransportWrapper) 23 | protected 24 | // FSocket: TSocket; 25 | FSocket: TClientSocket; 26 | // FSocket: TIdTCPClient; 27 | FServerURL: string; 28 | FEndpoint: TNetEndpoint; 29 | 30 | function GetConnected: Boolean; override; 31 | procedure ParseURL; 32 | 33 | function GetRequestStream: TStream; override; 34 | function GetResponseStream: TStream; override; 35 | 36 | {$IF RTLVersion >= TRTLVersion.Delphi120 } 37 | function GetConnectionTimeout: Integer; override; 38 | procedure SetConnectionTimeout(const Value: Integer); override; 39 | {$ENDIF} 40 | 41 | function GetResponseTimeout: Integer; override; 42 | procedure SetResponseTimeout(const Value: Integer); override; 43 | 44 | function GetSendTimeout: Integer; override; 45 | procedure SetSendTimeout(const Value: Integer); override; 46 | 47 | function GetEncoding: TEncoding; 48 | public 49 | procedure Connect; override; 50 | 51 | constructor Create; override; 52 | destructor Destroy; override; 53 | procedure Post(const AURL: string; const ASource, AResponseContent: TStream; 54 | const AHeaders: TNetHeaders); override; 55 | 56 | property Connected; 57 | property Encoding: TEncoding read GetEncoding; 58 | end; 59 | 60 | procedure InitTransportWrapperTCP; 61 | 62 | implementation 63 | 64 | uses 65 | {$IF DEFINED(DEBUG)} 66 | Winapi.Windows, 67 | {$ENDIF} 68 | System.Net.Socket, 69 | Winapi.Winsock2; 70 | 71 | { TJSONRPCTCPTransportWrapper } 72 | 73 | procedure TJSONRPCTCPTransportWrapper.Connect; 74 | begin 75 | try 76 | FSocket.Connect(FEndpoint); 77 | except 78 | // 79 | end; 80 | // FSocket.Connect(FEndpoint.Address.Address, FEndpoint.Port); 81 | end; 82 | 83 | constructor TJSONRPCTCPTransportWrapper.Create; 84 | begin 85 | inherited; 86 | // FSocket := System.Net.Socket.TSocket.Create(TSocketType.TCP, TEncoding.UTF8); 87 | FSocket := TClientSocket.Create; 88 | // FSocket := TIdTCPClient.Create(nil); 89 | end; 90 | 91 | destructor TJSONRPCTCPTransportWrapper.Destroy; 92 | begin 93 | FSocket.Free; 94 | inherited; 95 | end; 96 | 97 | function TJSONRPCTCPTransportWrapper.GetConnected: Boolean; 98 | begin 99 | if not Assigned(FSocket) then 100 | Exit(False); 101 | Result := FSocket.State * [TSocketState.Connected] <> []; 102 | // Result := FSocket.Connected; 103 | end; 104 | 105 | {$IF RTLVersion >= RTLVersionDelphi120 } 106 | function TJSONRPCTCPTransportWrapper.GetConnectionTimeout: Integer; 107 | begin 108 | Result := FSocket.ConnectTimeout; 109 | end; 110 | 111 | procedure TJSONRPCTCPTransportWrapper.SetConnectionTimeout( 112 | const Value: Integer); 113 | begin 114 | FSocket.ConnectTimeout := Value; 115 | end; 116 | {$ENDIF} 117 | 118 | function TJSONRPCTCPTransportWrapper.GetEncoding: TEncoding; 119 | begin 120 | Result := FSocket.Encoding; 121 | end; 122 | 123 | function TJSONRPCTCPTransportWrapper.GetRequestStream: TStream; 124 | begin 125 | if not Assigned(FRequestStream) then 126 | FRequestStream := TTrackedMemoryStream.Create(CheckStream); 127 | if FRequestStream.Size <> 0 then 128 | FRequestStream.Size := 0; 129 | Result := FRequestStream; 130 | end; 131 | 132 | function TJSONRPCTCPTransportWrapper.GetResponseStream: TStream; 133 | begin 134 | if not Assigned(FResponseStream) then 135 | FResponseStream:= TTrackedMemoryStream.Create(CheckStream); 136 | if FResponseStream.Size <> 0 then 137 | FResponseStream.Size := 0; 138 | Result := FResponseStream; 139 | end; 140 | 141 | function TJSONRPCTCPTransportWrapper.GetResponseTimeout: Integer; 142 | begin 143 | Result := FSocket.ReceiveTimeout; 144 | // Result := FSocket.ReadTimeout; 145 | end; 146 | 147 | function TJSONRPCTCPTransportWrapper.GetSendTimeout: Integer; 148 | begin 149 | Result := FSocket.SendTimeout; 150 | end; 151 | 152 | procedure TJSONRPCTCPTransportWrapper.ParseURL; 153 | var 154 | LURI: TURI; 155 | begin 156 | LURI := TURI.Create(FServerURL); 157 | if FEndpoint.Family = 0 then 158 | FEndpoint.Family := AF_INET; 159 | FEndpoint.Port := LURI.Port; 160 | FEndpoint.SetAddress(LURI.Host); 161 | end; 162 | 163 | procedure TJSONRPCTCPTransportWrapper.Post(const AURL: string; const ASource, 164 | AResponseContent: TStream; const AHeaders: TNetHeaders); 165 | var 166 | LSendBuffer, LReceivedBuffer: TBytes; 167 | LLen: Integer; 168 | begin 169 | 170 | if not Connected then 171 | begin 172 | if FServerURL <> AURL then 173 | begin 174 | FServerURL := AURL; 175 | ParseURL; 176 | end; 177 | Connect; 178 | end; 179 | 180 | ASource.Position := 0; 181 | SetLength(LSendBuffer, ASource.Size); 182 | // Send outgoing client data 183 | ASource.Read(LSendBuffer, Length(LSendBuffer)); 184 | LLen := FSocket.Send(LSendBuffer); 185 | 186 | // Read incoming server response on client side 187 | SetLength(LReceivedBuffer, LLen); 188 | FSocket.Receive(LReceivedBuffer, Length(LReceivedBuffer), []); 189 | {$IF DEFINED(DEBUG)} 190 | var LReceivedString := StringOf(LReceivedBuffer); 191 | OutputDebugString(PChar(LReceivedString)); 192 | {$ENDIF} 193 | AResponseContent.Size := 0; 194 | AResponseContent.Write(LReceivedBuffer, Length(LReceivedBuffer)); 195 | end; 196 | 197 | procedure TJSONRPCTCPTransportWrapper.SetResponseTimeout(const Value: Integer); 198 | begin 199 | FSocket.ReceiveTimeout := Value; 200 | end; 201 | 202 | procedure TJSONRPCTCPTransportWrapper.SetSendTimeout(const Value: Integer); 203 | begin 204 | FSocket.SendTimeout := Value; 205 | end; 206 | 207 | procedure InitTransportWrapperTCP; 208 | begin 209 | GJSONRPCTransportWrapperClass := TJSONRPCTCPTransportWrapper; 210 | end; 211 | 212 | initialization 213 | if not Assigned(GJSONRPCTransportWrapperClass) then 214 | InitTransportWrapperTCP; 215 | end. 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | // chuacw, Jun 2023 252 | 253 | -------------------------------------------------------------------------------- /Common/JSONRPC.TransportWrapper.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.TransportWrapper; 2 | 3 | interface 4 | 5 | uses 6 | System.Classes, System.Net.URLClient; 7 | 8 | type 9 | 10 | TJSONRPCTransportWrapper = class 11 | private 12 | function GetConnectionTimeout: Integer; virtual; abstract; 13 | function GetResponseTimeout: Integer; virtual; abstract; 14 | function GetSendTimeout: Integer; virtual; abstract; 15 | procedure SetConnectionTimeout(const Value: Integer); virtual; abstract; 16 | procedure SetResponseTimeout(const Value: Integer); virtual; abstract; 17 | procedure SetSendTimeout(const Value: Integer); virtual; abstract; 18 | public 19 | procedure Post(const AURL: string; const ASource, AResponseContent: TStream; 20 | const AHeaders: TNetHeaders); virtual; abstract; 21 | property ConnectionTimeout: Integer read GetConnectionTimeout write SetConnectionTimeout; 22 | property ResponseTimeout: Integer read GetResponseTimeout write SetResponseTimeout; 23 | property SendTimeout: Integer read GetSendTimeout write SetSendTimeout; 24 | end; 25 | 26 | implementation 27 | 28 | end. 29 | -------------------------------------------------------------------------------- /Common/README.md: -------------------------------------------------------------------------------- 1 | This directory contains code that should be common to both the client and server side. -------------------------------------------------------------------------------- /JSONRPC_Group.groupproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {5E2562F9-E3BF-47AF-B6A3-7611A4B49D82} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Default.Personality.12 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | {C9D6BDF0-D1D0-4071-A490-ADD5CFD8C168} 63 | Debug 64 | Linux64;Win32;Win64 65 | True 66 | 67 | 68 | {CAC21F3D-6368-4CD6-8731-D39EE75706D4} 69 | Debug;Release 70 | Win32;Win64 71 | True 72 | 73 | 74 | {14F22B99-AF36-48B9-B792-6201E9E6270C} 75 | Debug;Release 76 | Linux64;Win32;Win64 77 | True 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Commercial use prohibited. 2 | If you're including this library in any commercial application that costs money, please 3 | contact me by opening a discussion on the GitHub repository. 4 | -------------------------------------------------------------------------------- /README.dpr: -------------------------------------------------------------------------------- 1 | program README; 2 | 3 | uses 4 | System.SysUtils, 5 | System.JSON, 6 | System.Rtti, 7 | JSONRPC.Common.Types in 'Common\JSONRPC.Common.Types.pas', 8 | JSONRPC.Common.Consts in 'Common\JSONRPC.Common.Consts.pas', 9 | JSONRPC.Common.RecordHandlers in 'Common\JSONRPC.Common.RecordHandlers.pas', 10 | JSONRPC.JsonUtils in 'Common\JSONRPC.JsonUtils.pas'; 11 | 12 | function get_data: TConstArray; 13 | begin 14 | Result := CreateConstArray(['hello', 5]); 15 | end; 16 | 17 | 18 | procedure Main; 19 | begin 20 | var data := get_data; 21 | var LValue := TValue.From(data); 22 | var LJSONArray := ValueToJSONArray(LValue, TypeInfo(TConstArray)); 23 | try 24 | WriteLn(LJSONArray.ToJSON); 25 | // let's assume it's a TConstArray to simplify conversion 26 | DeserializeJSON(LJSONArray, TypeInfo(TConstArray), LValue); 27 | finally 28 | LJSONArray.Free; 29 | end; 30 | end; 31 | 32 | begin 33 | ReportMemoryLeaksOnShutdown := True; 34 | Main; 35 | end. 36 | -------------------------------------------------------------------------------- /Server/JSONRPC.Server.Consts.pas: -------------------------------------------------------------------------------- 1 | {---------------------------------------------------------------------------} 2 | { } 3 | { File: JSONRPC.Server.Consts.pas } 4 | { Function: Constants for JSON RPC server } 5 | { } 6 | { Language: Delphi version XE11 or later } 7 | { Author: Chee-Wee Chua } 8 | { Copyright: (c) 2023,2024 Chee-Wee Chua } 9 | {---------------------------------------------------------------------------} 10 | unit JSONRPC.Server.Consts; 11 | 12 | interface 13 | 14 | resourcestring 15 | sPortInUse = '- Error: Port %d already in use'; 16 | sPortSSet = '- Port set to %s'; 17 | sPortISet = '- Port set to %d'; 18 | sServerAlreadyRunning = '- The server is already running'; 19 | sServerStarted = '- The server has started on port %d'; 20 | sStartingServer = '- Starting HTTP Server on port %d'; 21 | sStoppingServer = '- Stopping server'; 22 | sServerStopped = '- server stopped'; 23 | sServerNotRunning = '- The server is not running'; 24 | sInvalidCommand = '- Error: Invalid Command'; 25 | sActive = '- Active: '; 26 | sPort = '- Port: '; 27 | sSessionID = '- Session ID CookieName: '; 28 | sCommands = 'Enter a Command: ' + slineBreak + 29 | ' - "start" to start the server'+ slineBreak + 30 | ' - "stop" to stop the server'+ slineBreak + 31 | ' - "set port" to change the default port'+ slineBreak + 32 | ' - "status" for Server status'+ slineBreak + 33 | ' - "help" or "?" to show commands'+ slineBreak + 34 | ' - "exit" to close the application'; 35 | 36 | const 37 | cArrow = '->'; 38 | cCommandStart = 'start'; 39 | cCommandStop = 'stop'; 40 | cCommandStatus = 'status'; 41 | cCommandHelp = 'help'; 42 | cCommandHelpAlt = '?'; 43 | cCommandSetPort = 'set port'; 44 | cCommandExit = 'exit'; 45 | cCommandQUit = 'quit'; 46 | 47 | implementation 48 | 49 | end. 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | // chuacw, Jun 2023 86 | 87 | -------------------------------------------------------------------------------- /Server/JSONRPC.Server.JSONRPCHTTPServer.pas: -------------------------------------------------------------------------------- 1 | {---------------------------------------------------------------------------} 2 | { } 3 | { File: JSONRPC.Server.JSONRPCHTTPServer.pas } 4 | { Function: Constants for JSON RPC HTTP server } 5 | { } 6 | { Language: Delphi version XE11 or later } 7 | { Author: Chee-Wee Chua } 8 | { Copyright: (c) 2023,2024 Chee-Wee Chua } 9 | {---------------------------------------------------------------------------} 10 | unit JSONRPC.Server.JSONRPCHTTPServer; 11 | 12 | {$ALIGN 16} 13 | {$CODEALIGN 16} 14 | 15 | interface 16 | 17 | uses 18 | JSONRPC.CustomServerIdHTTP.Runner; 19 | 20 | type 21 | TJSONRPCServerIdHTTPRunner = class(TCustomJSONRPCServerIdHTTPRunner) 22 | protected 23 | procedure CreateServerWrapper; override; 24 | procedure FreeServerWrapper; override; 25 | end; 26 | 27 | implementation 28 | 29 | uses 30 | JSONRPC.RIO; 31 | 32 | { TJSONRPCServerIdHTTPRunner } 33 | 34 | procedure TJSONRPCServerIdHTTPRunner.CreateServerWrapper; 35 | begin 36 | FServerWrapper := TJSONRPCServerWrapper.Create(nil); 37 | FServerWrapper.Persistent := True; 38 | end; 39 | 40 | procedure TJSONRPCServerIdHTTPRunner.FreeServerWrapper; 41 | begin 42 | FServerWrapper.Free; 43 | end; 44 | 45 | end. 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | // chuacw, Jun 2023 82 | 83 | -------------------------------------------------------------------------------- /Server/JSONRPC.Server.Runner.pas: -------------------------------------------------------------------------------- 1 | {---------------------------------------------------------------------------} 2 | { } 3 | { File: JSONRPC.Server.Runner.pas } 4 | { Function: A JSON RPC server runner } 5 | { } 6 | { Language: Delphi version XE11 or later } 7 | { Author: Chee-Wee Chua } 8 | { Copyright: (c) 2023,2024 Chee-Wee Chua } 9 | {---------------------------------------------------------------------------} 10 | unit JSONRPC.Server.Runner; 11 | 12 | interface 13 | 14 | uses 15 | IdHTTPWebBrokerBridge; 16 | 17 | type 18 | TIdHTTPWebBrokerBridge = IdHTTPWebBrokerBridge.TIdHTTPWebBrokerBridge; 19 | 20 | TJSONRPCServerRunner = class 21 | public 22 | type 23 | TProcNotifyPortSet = reference to procedure(const APort: Integer); 24 | TProcNotifyPortInUse = reference to procedure(const APort: Integer); 25 | TProcNotifyServerIsAlreadyRunning = reference to procedure(const AServer: TJSONRPCServerRunner); 26 | TProcNotifyServerIsActive = reference to procedure(const AServer: TJSONRPCServerRunner); 27 | TProcNotifyServerIsInactive = reference to procedure(const AServer: TJSONRPCServerRunner); 28 | private 29 | function GetActive: Boolean; inline; 30 | procedure SetActive(const Value: Boolean); inline; 31 | protected 32 | FServer: TIdHTTPWebBrokerBridge; 33 | FOnNotifyPortSet: TProcNotifyPortSet; 34 | FOnNotifyPortInUse: TProcNotifyPortInUse; 35 | FOnNotifyServerIsAlreadyRunning: TProcNotifyServerIsAlreadyRunning; 36 | FOnNotifyServerIsActive: TProcNotifyServerIsActive; 37 | FOnNotifyServerIsInactive: TProcNotifyServerIsInactive; 38 | 39 | function BindPort(APort: Integer): Boolean; 40 | 41 | function GetPort: Integer; 42 | procedure SetPort(const APort: Integer); 43 | 44 | procedure DoNotifyPortSet; 45 | procedure DoNotifyPortInUse(const APort: Integer); 46 | procedure DoNotifyServerIsActive; 47 | procedure DoNotifyServerIsInactive; 48 | procedure DoNotifyServerIsAlreadyRunning; 49 | 50 | public 51 | 52 | constructor Create; 53 | destructor Destroy; override; 54 | 55 | function CheckPort(const APort: Integer): Integer; overload; 56 | function CheckPort(const APort: string): Integer; overload; 57 | 58 | procedure StartServer(const APort: Integer = 0); 59 | procedure StopServer; 60 | 61 | property OnNotifyPortSet: TProcNotifyPortSet read FOnNotifyPortSet write 62 | FOnNotifyPortSet; 63 | property OnNotifyPortInUse: TProcNotifyPortInUse read FOnNotifyPortInUse write 64 | FOnNotifyPortInUse; 65 | property OnNotifyServerIsActive: TProcNotifyServerIsActive read 66 | FOnNotifyServerIsActive write FOnNotifyServerIsActive; 67 | property OnNotifyServerIsInactive: TProcNotifyServerIsInactive read 68 | FOnNotifyServerIsInactive write FOnNotifyServerIsInactive; 69 | property OnNotifyServerIsAlreadyRunning: TProcNotifyServerIsAlreadyRunning read 70 | FOnNotifyServerIsAlreadyRunning write FOnNotifyServerIsAlreadyRunning; 71 | 72 | property Active: Boolean read GetActive write SetActive; 73 | property Port: Integer read GetPort write SetPort; 74 | property Server: TIdHTTPWebBrokerBridge read FServer; 75 | end; 76 | 77 | implementation 78 | 79 | uses 80 | IPPeerAPI, System.SysUtils; 81 | 82 | { TJSONRPCServerRunner } 83 | 84 | function TJSONRPCServerRunner.BindPort(APort: Integer): Boolean; 85 | var 86 | LTestServer: IIPTestServer; 87 | begin 88 | Result := True; 89 | try 90 | LTestServer := PeerFactory.CreatePeer('', IIPTestServer) as IIPTestServer; 91 | LTestServer.TestOpenPort(APort, nil); 92 | except 93 | Result := False; 94 | end; 95 | end; 96 | 97 | function TJSONRPCServerRunner.CheckPort(const APort: Integer): Integer; 98 | begin 99 | if BindPort(APort) then 100 | Result := APort 101 | else 102 | Result := 0; 103 | end; 104 | 105 | function TJSONRPCServerRunner.CheckPort(const APort: string): Integer; 106 | begin 107 | Result := CheckPort(APort.ToInteger); 108 | end; 109 | 110 | constructor TJSONRPCServerRunner.Create; 111 | begin 112 | inherited Create; 113 | FServer := TIdHTTPWebBrokerBridge.Create(nil); 114 | end; 115 | 116 | destructor TJSONRPCServerRunner.Destroy; 117 | begin 118 | FServer.StopListening; 119 | FServer.Free; 120 | inherited; 121 | end; 122 | 123 | procedure TJSONRPCServerRunner.DoNotifyPortInUse(const APort: Integer); 124 | begin 125 | if Assigned(FOnNotifyPortInUse) then 126 | FOnNotifyPortInUse(APort); 127 | end; 128 | 129 | procedure TJSONRPCServerRunner.DoNotifyPortSet; 130 | begin 131 | if Assigned(FOnNotifyPortSet) then 132 | FOnNotifyPortSet(FServer.DefaultPort); 133 | end; 134 | 135 | procedure TJSONRPCServerRunner.DoNotifyServerIsActive; 136 | begin 137 | if Assigned(FOnNotifyServerIsActive) then 138 | FOnNotifyServerIsActive(Self); 139 | end; 140 | 141 | procedure TJSONRPCServerRunner.DoNotifyServerIsAlreadyRunning; 142 | begin 143 | if Assigned(FOnNotifyServerIsAlreadyRunning) then 144 | FOnNotifyServerIsAlreadyRunning(Self); 145 | end; 146 | 147 | procedure TJSONRPCServerRunner.DoNotifyServerIsInactive; 148 | begin 149 | if Assigned(FOnNotifyServerIsInactive) then 150 | FOnNotifyServerIsInactive(Self); 151 | end; 152 | 153 | function TJSONRPCServerRunner.GetActive: Boolean; 154 | begin 155 | Result := FServer.Active; 156 | end; 157 | 158 | function TJSONRPCServerRunner.GetPort: Integer; 159 | begin 160 | Result := FServer.DefaultPort; 161 | end; 162 | 163 | procedure TJSONRPCServerRunner.SetActive(const Value: Boolean); 164 | begin 165 | FServer.Active := Value; 166 | end; 167 | 168 | procedure TJSONRPCServerRunner.SetPort(const APort: Integer); 169 | begin 170 | if not FServer.Active then 171 | begin 172 | if CheckPort(APort) > 0 then 173 | begin 174 | FServer.DefaultPort := APort; 175 | DoNotifyPortSet; 176 | end else 177 | begin 178 | DoNotifyPortInUse(APort); 179 | end; 180 | end 181 | end; 182 | 183 | procedure TJSONRPCServerRunner.StartServer(const APort: Integer = 0); 184 | var 185 | LPort: Integer; 186 | begin 187 | if APort <> 0 then 188 | LPort := APort else 189 | LPort := FServer.DefaultPort; 190 | if not FServer.Active then 191 | begin 192 | if CheckPort(LPort) > 0 then 193 | begin 194 | FServer.Bindings.Clear; 195 | FServer.Active := True; 196 | DoNotifyServerIsActive; 197 | end else 198 | begin 199 | DoNotifyPortInUse(LPort); 200 | end; 201 | end else 202 | begin 203 | DoNotifyServerIsAlreadyRunning; 204 | end; 205 | end; 206 | 207 | procedure TJSONRPCServerRunner.StopServer; 208 | begin 209 | FServer.Active := False; 210 | DoNotifyServerIsInactive; 211 | end; 212 | 213 | end. 214 | -------------------------------------------------------------------------------- /Server/JSONRPC.ServerWebBroker.Runner.pas: -------------------------------------------------------------------------------- 1 | {---------------------------------------------------------------------------} 2 | { } 3 | { File: JSONRPC.ServerWebBroker.Runner.pas } 4 | { Function: A JSON RPC web broker runner } 5 | { } 6 | { Language: Delphi version XE11 or later } 7 | { Author: Chee-Wee Chua } 8 | { Copyright: (c) 2023,2024 Chee-Wee Chua } 9 | {---------------------------------------------------------------------------} 10 | unit JSONRPC.ServerWebBroker.Runner; 11 | 12 | {$ALIGN 16} 13 | {$CODEALIGN 16} 14 | 15 | interface 16 | 17 | uses 18 | IdHTTPWebBrokerBridge; 19 | 20 | type 21 | TIdHTTPWebBrokerBridge = IdHTTPWebBrokerBridge.TIdHTTPWebBrokerBridge; 22 | 23 | TJSONRPCServerWebBrokerRunner = class 24 | public 25 | type 26 | TProcNotifyPortSet = reference to procedure(const APort: Integer); 27 | TProcNotifyPortInUse = reference to procedure(const APort: Integer); 28 | TProcNotifyServerIsAlreadyRunning = reference to procedure(const AServer: TJSONRPCServerWebBrokerRunner); 29 | TProcNotifyServerIsActive = reference to procedure(const AServer: TJSONRPCServerWebBrokerRunner); 30 | TProcNotifyServerIsInactive = reference to procedure(const AServer: TJSONRPCServerWebBrokerRunner); 31 | private 32 | function GetActive: Boolean; inline; 33 | procedure SetActive(const Value: Boolean); inline; 34 | protected 35 | FServer: TIdHTTPWebBrokerBridge; 36 | FOnNotifyPortSet: TProcNotifyPortSet; 37 | FOnNotifyPortInUse: TProcNotifyPortInUse; 38 | FOnNotifyServerIsAlreadyRunning: TProcNotifyServerIsAlreadyRunning; 39 | FOnNotifyServerIsActive: TProcNotifyServerIsActive; 40 | FOnNotifyServerIsInactive: TProcNotifyServerIsInactive; 41 | 42 | function BindPort(APort: Integer): Boolean; 43 | 44 | function GetPort: Integer; 45 | procedure SetPort(const APort: Integer); 46 | 47 | procedure DoNotifyPortSet; 48 | procedure DoNotifyPortInUse(const APort: Integer); 49 | procedure DoNotifyServerIsActive; 50 | procedure DoNotifyServerIsInactive; 51 | procedure DoNotifyServerIsAlreadyRunning; 52 | 53 | public 54 | 55 | constructor Create; 56 | destructor Destroy; override; 57 | 58 | function CheckPort(const APort: Integer): Integer; overload; 59 | function CheckPort(const APort: string): Integer; overload; 60 | 61 | procedure StartServer(const APort: Integer = 0); 62 | procedure StopServer; 63 | 64 | property OnNotifyPortSet: TProcNotifyPortSet read FOnNotifyPortSet write 65 | FOnNotifyPortSet; 66 | property OnNotifyPortInUse: TProcNotifyPortInUse read FOnNotifyPortInUse write 67 | FOnNotifyPortInUse; 68 | property OnNotifyServerIsActive: TProcNotifyServerIsActive read 69 | FOnNotifyServerIsActive write FOnNotifyServerIsActive; 70 | property OnNotifyServerIsInactive: TProcNotifyServerIsInactive read 71 | FOnNotifyServerIsInactive write FOnNotifyServerIsInactive; 72 | property OnNotifyServerIsAlreadyRunning: TProcNotifyServerIsAlreadyRunning read 73 | FOnNotifyServerIsAlreadyRunning write FOnNotifyServerIsAlreadyRunning; 74 | 75 | property Active: Boolean read GetActive write SetActive; 76 | property Port: Integer read GetPort write SetPort; 77 | property Server: TIdHTTPWebBrokerBridge read FServer; 78 | end; 79 | 80 | implementation 81 | 82 | uses 83 | IPPeerAPI, System.SysUtils; 84 | 85 | { TJSONRPCServerWebBrokerRunner } 86 | 87 | function TJSONRPCServerWebBrokerRunner.BindPort(APort: Integer): Boolean; 88 | var 89 | LTestServer: IIPTestServer; 90 | begin 91 | Result := True; 92 | try 93 | LTestServer := PeerFactory.CreatePeer('', IIPTestServer) as IIPTestServer; 94 | LTestServer.TestOpenPort(APort, nil); 95 | except 96 | Result := False; 97 | end; 98 | end; 99 | 100 | function TJSONRPCServerWebBrokerRunner.CheckPort(const APort: Integer): Integer; 101 | begin 102 | if BindPort(APort) then 103 | Result := APort 104 | else 105 | Result := 0; 106 | end; 107 | 108 | function TJSONRPCServerWebBrokerRunner.CheckPort(const APort: string): Integer; 109 | begin 110 | Result := CheckPort(APort.ToInteger); 111 | end; 112 | 113 | constructor TJSONRPCServerWebBrokerRunner.Create; 114 | begin 115 | inherited Create; 116 | FServer := TIdHTTPWebBrokerBridge.Create(nil); 117 | end; 118 | 119 | destructor TJSONRPCServerWebBrokerRunner.Destroy; 120 | begin 121 | FServer.StopListening; 122 | FServer.Free; 123 | inherited; 124 | end; 125 | 126 | procedure TJSONRPCServerWebBrokerRunner.DoNotifyPortInUse(const APort: Integer); 127 | begin 128 | if Assigned(FOnNotifyPortInUse) then 129 | FOnNotifyPortInUse(APort); 130 | end; 131 | 132 | procedure TJSONRPCServerWebBrokerRunner.DoNotifyPortSet; 133 | begin 134 | if Assigned(FOnNotifyPortSet) then 135 | FOnNotifyPortSet(FServer.DefaultPort); 136 | end; 137 | 138 | procedure TJSONRPCServerWebBrokerRunner.DoNotifyServerIsActive; 139 | begin 140 | if Assigned(FOnNotifyServerIsActive) then 141 | FOnNotifyServerIsActive(Self); 142 | end; 143 | 144 | procedure TJSONRPCServerWebBrokerRunner.DoNotifyServerIsAlreadyRunning; 145 | begin 146 | if Assigned(FOnNotifyServerIsAlreadyRunning) then 147 | FOnNotifyServerIsAlreadyRunning(Self); 148 | end; 149 | 150 | procedure TJSONRPCServerWebBrokerRunner.DoNotifyServerIsInactive; 151 | begin 152 | if Assigned(FOnNotifyServerIsInactive) then 153 | FOnNotifyServerIsInactive(Self); 154 | end; 155 | 156 | function TJSONRPCServerWebBrokerRunner.GetActive: Boolean; 157 | begin 158 | Result := FServer.Active; 159 | end; 160 | 161 | function TJSONRPCServerWebBrokerRunner.GetPort: Integer; 162 | begin 163 | Result := FServer.DefaultPort; 164 | end; 165 | 166 | procedure TJSONRPCServerWebBrokerRunner.SetActive(const Value: Boolean); 167 | begin 168 | FServer.Active := Value; 169 | end; 170 | 171 | procedure TJSONRPCServerWebBrokerRunner.SetPort(const APort: Integer); 172 | begin 173 | if not FServer.Active then 174 | begin 175 | if CheckPort(APort) > 0 then 176 | begin 177 | FServer.DefaultPort := APort; 178 | DoNotifyPortSet; 179 | end else 180 | begin 181 | DoNotifyPortInUse(APort); 182 | end; 183 | end 184 | end; 185 | 186 | procedure TJSONRPCServerWebBrokerRunner.StartServer(const APort: Integer = 0); 187 | var 188 | LPort: Integer; 189 | begin 190 | if APort <> 0 then 191 | LPort := APort else 192 | LPort := FServer.DefaultPort; 193 | if not FServer.Active then 194 | begin 195 | if CheckPort(LPort) > 0 then 196 | begin 197 | FServer.Bindings.Clear; 198 | FServer.Active := True; 199 | DoNotifyServerIsActive; 200 | end else 201 | begin 202 | DoNotifyPortInUse(LPort); 203 | end; 204 | end else 205 | begin 206 | DoNotifyServerIsAlreadyRunning; 207 | end; 208 | end; 209 | 210 | procedure TJSONRPCServerWebBrokerRunner.StopServer; 211 | begin 212 | FServer.Active := False; 213 | DoNotifyServerIsInactive; 214 | end; 215 | 216 | end. 217 | -------------------------------------------------------------------------------- /Server/JSONRPC.WebBrokerJSONRPC.pas: -------------------------------------------------------------------------------- 1 | {---------------------------------------------------------------------------} 2 | { } 3 | { File: JSONRPC.WebBrokerJSONRPC.pas } 4 | { Function: A JSON RPC web broker } 5 | { } 6 | { Language: Delphi version XE11 or later } 7 | { Author: Chee-Wee Chua } 8 | { Copyright: (c) 2023,2024 Chee-Wee Chua } 9 | {---------------------------------------------------------------------------} 10 | unit JSONRPC.WebBrokerJSONRPC; 11 | 12 | {$ALIGN 16} 13 | {$CODEALIGN 16} 14 | 15 | interface 16 | 17 | uses 18 | System.Classes, System.SysUtils, System.Masks, JSONRPC.Server.Dispatcher, 19 | Web.AutoDisp, Web.HTTPApp, JSONRPC.Common.Types; 20 | 21 | type 22 | TJSONRPCDispatcherException = procedure(Sender: TObject; Request: TWebRequest; 23 | Response: TWebResponse; E: Exception; var Handled: Boolean) of object; 24 | 25 | { Webbroker component that dispatches JSON RPC requests } 26 | TJSONRPCDispatcher = class(TJSONRPCDispatchNode) 27 | protected 28 | FOnException: TJSONRPCDispatcherException; 29 | 30 | function DispatchEnabled: Boolean; 31 | function DispatchRequest(Sender: TObject; Request: TWebRequest; 32 | Response: TWebResponse): Boolean; 33 | public 34 | constructor Create(AOwner: TComponent); override; 35 | destructor Destroy; override; 36 | 37 | property OnDispatchedJSONRPC; 38 | property OnLogIncomingJSONRequest; 39 | property OnLogOutgoingJSONResponse; 40 | 41 | property OnException: TJSONRPCDispatcherException read FOnException write FOnException; 42 | end; 43 | 44 | function GetJSONRPCWebModule: TWebModule; 45 | 46 | procedure SetOnDispatchedJSONRPC(const AProc: TOnDispatchedJSONRPC); 47 | procedure SetOnLogIncomingJSONRequest(const AProc: TOnLogIncomingJSONRequest); 48 | procedure SetOnLogOutgoingJSONResponse(const AProc: TOnLogOutgoingJSONResponse); 49 | 50 | implementation 51 | 52 | uses 53 | System.Math, 54 | Soap.SOAPAttach, 55 | Soap.SOAPConst 56 | ; 57 | 58 | threadvar 59 | JSONRPCWebModule: TWebModule; 60 | 61 | function GetJSONRPCWebModule: TWebModule; 62 | begin 63 | Result := JSONRPCWebModule; 64 | end; 65 | 66 | { TJSONRPCDispatcher } 67 | 68 | constructor TJSONRPCDispatcher.Create(AOwner: TComponent); 69 | begin 70 | inherited Create(AOwner); 71 | FOnDispatchedJSONRPC := GOnDispatchedJSONRPC; 72 | FOnLogIncomingJSONRequest := GOnLogIncomingJSONRequest; 73 | FOnLogOutgoingJSONResponse := GOnLogOutgoingJSONResponse; 74 | end; 75 | 76 | destructor TJSONRPCDispatcher.Destroy; 77 | begin 78 | inherited Destroy; 79 | end; 80 | 81 | function TJSONRPCDispatcher.DispatchEnabled: Boolean; 82 | begin 83 | Result := True; 84 | end; 85 | 86 | function StreamAsTBytes(Stream: TStream): TBytes; 87 | begin 88 | SetLength(Result, Stream.Size); 89 | Stream.Position := 0; 90 | Stream.Read(Result, 0, Length(Result)); 91 | Stream.Position := 0; 92 | end; 93 | 94 | function TJSONRPCDispatcher.DispatchRequest(Sender: TObject; 95 | Request: TWebRequest; Response: TWebResponse): Boolean; 96 | var 97 | LJSONStream, LResponseStream: TMemoryStream; 98 | LRequestStream: TWebRequestStream; 99 | ExceptEnv: string; 100 | 101 | begin 102 | try 103 | if Owner is TWebModule then 104 | JSONRPCWebModule := TWebModule(Owner); 105 | try 106 | try 107 | { Make sure we have a dispatcher } 108 | if not Assigned(FJSONRPCDispatcher) and not ((csDesigning in ComponentState) or (csLoading in ComponentState)) then 109 | raise Exception.Create(SNoDispatcher); 110 | 111 | LJSONStream := TMemoryStream.Create; 112 | try 113 | { Wrap request around a stream } 114 | LRequestStream := TWebRequestStream.Create(Request); 115 | try 116 | LJSONStream.Position := 0; 117 | LResponseStream := TMemoryStream.Create; 118 | try 119 | 120 | FJSONRPCDispatcher.DispatchJSONRPC(LJSONStream, LResponseStream); 121 | 122 | LResponseStream.Position := 0; 123 | 124 | { Here we send back the response to the client } 125 | { Response.SendResponse; } 126 | Result := True; 127 | finally 128 | LResponseStream.Free; 129 | end; 130 | finally 131 | LRequestStream.Free; 132 | end; 133 | finally 134 | LJSONStream.Free; 135 | end; 136 | except 137 | on E: Exception do 138 | begin 139 | 140 | if Assigned(FOnException) then 141 | begin 142 | Result := False; 143 | FOnException(Self, Request, Response, E, Result); 144 | if Result then 145 | Exit; 146 | end; 147 | 148 | { Default to 200, as required by spec. } 149 | Response.StatusCode := 200; 150 | 151 | {$IFNDEF UNICODE} 152 | Response.Content := ExceptEnv; 153 | {$ELSE} 154 | Response.Content := ExceptEnv; 155 | {$ENDIF} 156 | Result := True; 157 | end; 158 | end; 159 | except 160 | { Swallow any unexpected exception, it will bring down some web servers } 161 | Result := False; 162 | end; 163 | finally 164 | { Reset current JSONRPCWebModule } 165 | JSONRPCWebModule := nil; 166 | end; 167 | end; 168 | 169 | procedure SetOnDispatchedJSONRPC(const AProc: TOnDispatchedJSONRPC); 170 | begin 171 | GOnDispatchedJSONRPC := AProc; 172 | end; 173 | 174 | procedure SetOnLogIncomingJSONRequest(const AProc: TOnLogIncomingJSONRequest); 175 | begin 176 | GOnLogIncomingJSONRequest := AProc; 177 | end; 178 | 179 | procedure SetOnLogOutgoingJSONResponse(const AProc: TOnLogOutgoingJSONResponse); 180 | begin 181 | GOnLogOutgoingJSONResponse := AProc; 182 | end; 183 | 184 | 185 | end. 186 | 187 | -------------------------------------------------------------------------------- /Server/JSONRPCWebModule.dfm: -------------------------------------------------------------------------------- 1 | object JSONRPCWebModule1: TJSONRPCWebModule1 2 | Actions = < 3 | item 4 | Default = True 5 | Name = 'DefaultHandler' 6 | PathInfo = '/' 7 | OnAction = WebModule1DefaultHandlerAction 8 | end> 9 | Height = 518 10 | Width = 934 11 | PixelsPerInch = 216 12 | end 13 | -------------------------------------------------------------------------------- /Server/JSONRPCWebModule.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPCWebModule; 2 | 3 | interface 4 | 5 | uses 6 | System.SysUtils, System.Classes, Web.HTTPApp, 7 | System.TypInfo, JSONRPC.Server.Dispatcher, 8 | JSONRPC.WebBrokerJSONRPC, JSONRPC.RIO, JSONRPC.Common.Types; 9 | 10 | type 11 | TJSONRPCWebModule1 = class(TWebModule, IJSONRPCGetSetDispatchEvents) 12 | procedure WebModule1DefaultHandlerAction(Sender: TObject; 13 | Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); 14 | private 15 | { Private declarations } 16 | protected 17 | FJSONRPCDispatcher: TJSONRPCDispatcher; 18 | 19 | function GetOnDispatchedJSONRPC: TOnDispatchedJSONRPC; 20 | function GetOnLogIncomingJSONRequest: TOnLogIncomingJSONRequest; 21 | function GetOnLogOutgoingJSONResponse: TOnLogOutgoingJSONResponse; 22 | 23 | procedure SetOnDispatchedJSONRPC(const AProc: TOnDispatchedJSONRPC); 24 | procedure SetOnLogIncomingJSONRequest(const AProc: TOnLogIncomingJSONRequest); 25 | procedure SetOnLogOutgoingJSONResponse(const AProc: TOnLogOutgoingJSONResponse); 26 | 27 | public 28 | { Public declarations } 29 | constructor Create(AOwner: TComponent); override; 30 | destructor Destroy; override; 31 | 32 | property OnDispatchedJSONRPC: TOnDispatchedJSONRPC read GetOnDispatchedJSONRPC 33 | write SetOnDispatchedJSONRPC; 34 | property OnOnLogIncomingJSONRequest: TOnLogIncomingJSONRequest 35 | read GetOnLogIncomingJSONRequest write SetOnLogIncomingJSONRequest; 36 | property OnLogOutgoingJSONResponse: TOnLogOutgoingJSONResponse 37 | read GetOnLogOutgoingJSONResponse write SetOnLogOutgoingJSONResponse; 38 | end; 39 | 40 | var 41 | WebModuleClass: TComponentClass = TJSONRPCWebModule1; 42 | 43 | implementation 44 | 45 | {%CLASSGROUP 'System.Classes.TPersistent'} 46 | 47 | uses 48 | JSONRPC.Common.Consts; 49 | 50 | {$R *.dfm} 51 | 52 | constructor TJSONRPCWebModule1.Create(AOwner: TComponent); 53 | begin 54 | inherited; 55 | FJSONRPCDispatcher := TJSONRPCDispatcher.Create(Self); 56 | end; 57 | 58 | destructor TJSONRPCWebModule1.Destroy; 59 | begin 60 | inherited; 61 | end; 62 | 63 | function TJSONRPCWebModule1.GetOnDispatchedJSONRPC: TOnDispatchedJSONRPC; 64 | begin 65 | Result := FJSONRPCDispatcher.OnDispatchedJSONRPC; 66 | end; 67 | 68 | function TJSONRPCWebModule1.GetOnLogIncomingJSONRequest: TOnLogIncomingJSONRequest; 69 | begin 70 | Result := FJSONRPCDispatcher.OnLogIncomingJSONRequest; 71 | end; 72 | 73 | function TJSONRPCWebModule1.GetOnLogOutgoingJSONResponse: TOnLogOutgoingJSONResponse; 74 | begin 75 | Result := FJSONRPCDispatcher.OnLogOutgoingJSONResponse; 76 | end; 77 | 78 | procedure TJSONRPCWebModule1.SetOnDispatchedJSONRPC( 79 | const AProc: TOnDispatchedJSONRPC); 80 | begin 81 | FJSONRPCDispatcher.OnDispatchedJSONRPC := AProc; 82 | end; 83 | 84 | procedure TJSONRPCWebModule1.SetOnLogIncomingJSONRequest( 85 | const AProc: TOnLogIncomingJSONRequest); 86 | begin 87 | FJSONRPCDispatcher.OnLogIncomingJSONRequest := AProc; 88 | end; 89 | 90 | procedure TJSONRPCWebModule1.SetOnLogOutgoingJSONResponse(const AProc: TOnLogOutgoingJSONResponse); 91 | begin 92 | FJSONRPCDispatcher.OnLogOutgoingJSONResponse := AProc; 93 | end; 94 | 95 | procedure TJSONRPCWebModule1.WebModule1DefaultHandlerAction(Sender: TObject; 96 | Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); 97 | begin 98 | var LBytes := Request.RawContent; 99 | var LRequestStream := TMemoryStream.Create; 100 | try 101 | LRequestStream.Write(LBytes, Length(LBytes)); 102 | LRequestStream.Position := 0; 103 | var LContentStream := TMemoryStream.Create; // this will be freed automatically 104 | try 105 | FJSONRPCDispatcher.DispatchJSONRPC(LRequestStream, LContentStream); 106 | Response.ContentStream := LContentStream; 107 | Response.ContentType := SApplicationJson; 108 | Handled := True; 109 | except 110 | FreeAndNil(LContentStream); 111 | Response.ContentStream := nil; 112 | end; 113 | finally 114 | LRequestStream.Free; 115 | end; 116 | end; 117 | 118 | end. 119 | -------------------------------------------------------------------------------- /Server/README.md: -------------------------------------------------------------------------------- 1 | This directory contains code that should only be implemented by the server side. 2 | -------------------------------------------------------------------------------- /Server/WebModuleUnit1.dfm: -------------------------------------------------------------------------------- 1 | object WebModule1: TWebModule1 2 | Actions = < 3 | item 4 | Default = True 5 | Name = 'DefaultHandler' 6 | PathInfo = '/' 7 | OnAction = WebModule1DefaultHandlerAction 8 | end> 9 | Height = 575 10 | Width = 1038 11 | PixelsPerInch = 240 12 | object HTTPSoapDispatcher1: THTTPSoapDispatcher 13 | Dispatcher = HTTPSoapPascalInvoker1 14 | WebDispatch.PathInfo = 'soap*' 15 | Left = 150 16 | Top = 28 17 | end 18 | object HTTPSoapPascalInvoker1: THTTPSoapPascalInvoker 19 | Converter.Options = [soSendMultiRefObj, soTryAllSchema, soUTF8InHeader] 20 | Left = 150 21 | Top = 168 22 | end 23 | object WSDLHTMLPublish1: TWSDLHTMLPublish 24 | WebDispatch.MethodType = mtAny 25 | WebDispatch.PathInfo = 'wsdl*' 26 | PublishOptions = [poUTF8ContentType] 27 | Left = 150 28 | Top = 308 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /Server/WebModuleUnit1.pas: -------------------------------------------------------------------------------- 1 | unit WebModuleUnit1; 2 | 3 | interface 4 | 5 | uses 6 | System.SysUtils, System.Classes, Web.HTTPApp, Soap.InvokeRegistry, 7 | Soap.WSDLIntf, System.TypInfo, Soap.WebServExp, Soap.WSDLBind, Xml.XMLSchema, 8 | Soap.WSDLPub, Soap.SOAPPasInv, Soap.SOAPHTTPPasInv, Soap.SOAPHTTPDisp, 9 | Soap.WebBrokerSOAP; 10 | 11 | type 12 | TWebModule1 = class(TWebModule) 13 | HTTPSoapDispatcher1: THTTPSoapDispatcher; 14 | HTTPSoapPascalInvoker1: THTTPSoapPascalInvoker; 15 | WSDLHTMLPublish1: TWSDLHTMLPublish; 16 | procedure WebModule1DefaultHandlerAction(Sender: TObject; 17 | Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); 18 | private 19 | { Private declarations } 20 | public 21 | { Public declarations } 22 | end; 23 | 24 | var 25 | WebModuleClass: TComponentClass = TWebModule1; 26 | 27 | implementation 28 | 29 | {%CLASSGROUP 'System.Classes.TPersistent'} 30 | 31 | {$R *.dfm} 32 | 33 | procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject; 34 | Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); 35 | begin 36 | WSDLHTMLPublish1.ServiceInfo(Sender, Request, Response, Handled); 37 | end; 38 | 39 | end. 40 | -------------------------------------------------------------------------------- /Tests/TestJSONDictionaryConverter.Types.pas: -------------------------------------------------------------------------------- 1 | unit TestJSONDictionaryConverter.Types; 2 | 3 | interface 4 | 5 | uses 6 | System.JSON.Converters, System.Generics.Collections; 7 | 8 | type 9 | 10 | TbyIdentityConverter = TJsonStringDictionaryConverter>; 11 | TbyIdentity = TDictionary>; 12 | 13 | implementation 14 | 15 | end. 16 | -------------------------------------------------------------------------------- /Tests/TestJSONDictionaryConverter.dpr: -------------------------------------------------------------------------------- 1 | program TestJSONDictionaryConverter; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | {$R *.res} 6 | 7 | uses 8 | System.JSON.Serializers, System.JSON, 9 | TestJSONDictionaryConverter.Types in 'TestJSONDictionaryConverter.Types.pas', 10 | TestJSONDictionaryConverter.Converters in 'TestJSONDictionaryConverter.Converters.pas'; 11 | 12 | function SameJson(const AJSON1, AJSON2: string): Boolean; 13 | var 14 | LJSONV1, LJSONV2: TJSONValue; 15 | LJSON1, LJSON2: string; 16 | begin 17 | try 18 | LJSONV1 := TJSONObject.ParseJSONValue(AJSON1); 19 | LJSONV2 := TJSONObject.ParseJSONValue(AJSON2); 20 | LJSON1 := LJSONV1.ToString; 21 | LJSON2 := LJSONV2.ToString; 22 | Result := LJSON1 = LJSON2; 23 | except 24 | Result := False; 25 | end; 26 | end; 27 | 28 | procedure Main; 29 | var 30 | LJSON1, LJSON2: string; 31 | LSerializer: TJsonSerializer; 32 | LResult: TResult; 33 | begin 34 | LJSON1 := '{'#13#10+ 35 | ' "context": {'#13#10+ 36 | ' "slot": 9887'#13#10+ 37 | ' },'#13#10+ 38 | ' "value": {'#13#10+ 39 | ' "byIdentity": {'#13#10+ 40 | ' "85iYT5RuzRTDgjyRa3cP8SYhM2j21fj7NhfJ3peu1DPr": ['#13#10+ 41 | ' 9888,'#13#10+ 42 | ' 9886'#13#10+ 43 | ' ]'#13#10+ 44 | ' },'#13#10+ 45 | ' "range": {'#13#10+ 46 | ' "firstSlot": 0,'#13#10+ 47 | ' "lastSlot": 9887'#13#10+ 48 | ' }'#13#10+ 49 | ' }'#13#10+ 50 | '}'#13#10; 51 | LSerializer := TJsonSerializer.Create; 52 | try 53 | LResult := LSerializer.Deserialize(LJSON1); 54 | LJSON2 := LSerializer.Serialize(LResult); 55 | WriteLn('LJSON1: ', LJSON1); 56 | WriteLn('LJSON2: ', LJSON2); 57 | WriteLn; 58 | 59 | WriteLn('JSON1 is same as JSON2: ', SameJson(LJSON1, LJSON2)); 60 | finally 61 | LSerializer.Free; 62 | end; 63 | end; 64 | 65 | begin 66 | Main; 67 | end. 68 | -------------------------------------------------------------------------------- /Tests/TestJSONDictionaryConverter.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuacw/JSONRPC_Framework/9463b711d858b7fb91051146b757951923aa1441/Tests/TestJSONDictionaryConverter.res -------------------------------------------------------------------------------- /Tests/TestJSONDictionaryConverter1.dpr: -------------------------------------------------------------------------------- 1 | program TestJSONDictionaryConverter1; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | {$R *.res} 6 | 7 | uses 8 | System.JSON.Serializers, 9 | System.JSON, 10 | TestJSONDictionaryConverter.Types in '..\..\Bugs\AttributeEmptyBug\TestJSONDictionaryConverter.Types.pas', 11 | TestJSONDictionaryConverter1.Converters in 'TestJSONDictionaryConverter1.Converters.pas'; 12 | 13 | function SameJson(const AJSON1, AJSON2: string): Boolean; 14 | var 15 | LJSONV1, LJSONV2: TJSONValue; 16 | LJSON1, LJSON2: string; 17 | begin 18 | try 19 | LJSONV1 := TJSONObject.ParseJSONValue(AJSON1); 20 | LJSONV2 := TJSONObject.ParseJSONValue(AJSON2); 21 | LJSON1 := LJSONV1.ToString; 22 | LJSON2 := LJSONV2.ToString; 23 | Result := LJSON1 = LJSON2; 24 | except 25 | Result := False; 26 | end; 27 | end; 28 | 29 | procedure Main; 30 | var 31 | LJSON1, LJSON2: string; 32 | LSerializer: TJsonSerializer; 33 | LResult: TResult; 34 | begin 35 | LJSON1 := '{'#13#10+ 36 | ' "context": {'#13#10+ 37 | ' "slot": 9887'#13#10+ 38 | ' },'#13#10+ 39 | ' "value": {'#13#10+ 40 | ' "byIdentity": {'#13#10+ 41 | ' "85iYT5RuzRTDgjyRa3cP8SYhM2j21fj7NhfJ3peu1DPr": ['#13#10+ 42 | ' 9888,'#13#10+ 43 | ' 9886'#13#10+ 44 | ' ]'#13#10+ 45 | ' },'#13#10+ 46 | ' "range": {'#13#10+ 47 | ' "firstSlot": 0,'#13#10+ 48 | ' "lastSlot": 9887'#13#10+ 49 | ' }'#13#10+ 50 | ' }'#13#10+ 51 | '}'#13#10; 52 | LSerializer := TJsonSerializer.Create; 53 | try 54 | LResult := LSerializer.Deserialize(LJSON1); 55 | LJSON2 := LSerializer.Serialize(LResult); 56 | WriteLn('LJSON1: ', LJSON1); 57 | WriteLn('LJSON2: ', LJSON2); 58 | WriteLn; 59 | 60 | WriteLn('JSON1 is same as JSON2: ', SameJson(LJSON1, LJSON2)); 61 | finally 62 | LSerializer.Free; 63 | end; 64 | end; 65 | 66 | begin 67 | Main; 68 | end. 69 | -------------------------------------------------------------------------------- /Tests/TestJSONDictionaryConverter2.Converters.pas: -------------------------------------------------------------------------------- 1 | unit TestJSONDictionaryConverter2.Converters; 2 | 3 | interface 4 | 5 | uses 6 | System.JSON.Serializers, 7 | System.JSON.Converters, 8 | System.Rtti, 9 | System.TypInfo, 10 | System.JSON.Readers, 11 | System.JSON.Writers, 12 | TestJSONDictionaryConverter.Types; 13 | 14 | type 15 | 16 | TValueRange = record 17 | firstSlot: Integer; 18 | lastSlot: Integer; 19 | end; 20 | 21 | TValueRecord = record 22 | [JsonConverter(TbyIdentityConverter)] 23 | byIdentity: TbyIdentity; 24 | range: TValueRange; 25 | 26 | class operator Assign(var Dest: TValueRecord; const [ref] Src: TValueRecord); 27 | class operator Initialize(out Dest: TValueRecord); 28 | class operator Finalize(var Dest: TValueRecord); 29 | end; 30 | 31 | TResult = record 32 | context: record 33 | slot: Integer; 34 | end; 35 | value: TValueRecord; 36 | class operator Assign(var Dest: TResult; const [ref] Src: TResult); 37 | class operator Initialize(out Dest: TResult); 38 | class operator Finalize(var Dest: TResult); 39 | end; 40 | 41 | implementation 42 | 43 | uses 44 | System.JSON.Types, System.SysUtils; 45 | 46 | class operator TResult.Assign(var Dest: TResult; const [ref] Src: TResult); 47 | begin 48 | Dest.context.slot := Src.context.slot; 49 | Dest.value := Src.value; 50 | end; 51 | 52 | class operator TResult.Initialize(out Dest: TResult); 53 | begin 54 | Dest.context.slot := Default(Integer); 55 | Dest.value := Default(TValueRecord); 56 | end; 57 | 58 | class operator TResult.Finalize(var Dest: TResult); 59 | begin 60 | Dest.context.slot := Default(Integer); 61 | end; 62 | 63 | { TValueRecord } 64 | 65 | class operator TValueRecord.Assign(var Dest: TValueRecord; const [ref] Src: TValueRecord); 66 | begin 67 | Dest.range := Src.range; 68 | for var LPair in Src.byIdentity do 69 | Dest.byIdentity.Add(LPair.Key, Copy(LPair.Value)); 70 | end; 71 | 72 | class operator TValueRecord.Initialize(out Dest: TValueRecord); 73 | begin 74 | Dest.byIdentity := TbyIdentity.Create; 75 | Dest.range := Default(TValueRange); 76 | end; 77 | 78 | class operator TValueRecord.Finalize(var Dest: TValueRecord); 79 | begin 80 | FreeAndNil(Dest.byIdentity); 81 | Dest.range := Default(TValueRange); 82 | end; 83 | 84 | end. 85 | -------------------------------------------------------------------------------- /Tests/TestJSONDictionaryConverter2.dpr: -------------------------------------------------------------------------------- 1 | program TestJSONDictionaryConverter2; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | {$R *.res} 6 | 7 | uses 8 | System.JSON.Serializers, 9 | System.JSON, 10 | TestJSONDictionaryConverter.Types in 'TestJSONDictionaryConverter.Types.pas', 11 | TestJSONDictionaryConverter2.Converters in 'TestJSONDictionaryConverter2.Converters.pas', 12 | JSONRPC.Web3.Solana.Attributes in '..\Web3\Solana\JSONRPC.Web3.Solana.Attributes.pas', 13 | JSONRPC.Web3.Solana.CustomConverters in '..\Web3\Solana\JSONRPC.Web3.Solana.CustomConverters.pas', 14 | JSONRPC.Web3.SolanaTypes.getAccountInfoResultsType in '..\Web3\Solana\JSONRPC.Web3.SolanaTypes.getAccountInfoResultsType.pas', 15 | JSONRPC.Web3.SolanaTypes.getVoteAccountResultsType in '..\Web3\Solana\JSONRPC.Web3.SolanaTypes.getVoteAccountResultsType.pas'; 16 | 17 | function SameJson(const AJSON1, AJSON2: string): Boolean; 18 | var 19 | LJSONV1, LJSONV2: TJSONValue; 20 | LJSON1, LJSON2: string; 21 | begin 22 | try 23 | LJSONV1 := TJSONObject.ParseJSONValue(AJSON1); 24 | LJSONV2 := TJSONObject.ParseJSONValue(AJSON2); 25 | LJSON1 := LJSONV1.ToString; 26 | LJSON2 := LJSONV2.ToString; 27 | Result := LJSON1 = LJSON2; 28 | except 29 | Result := False; 30 | end; 31 | end; 32 | 33 | type 34 | TMyEncoding = record 35 | [JsonConverter(TEncodingEnumConverter)] 36 | testencoding: TEncoding; 37 | end; 38 | 39 | procedure TestEncoding; 40 | var 41 | LJSON1, LJSON2: string; 42 | LSerializer: TJsonSerializer; 43 | LEncoding1, LEncoding2: TMyEncoding; 44 | begin 45 | LJSON1 := '{"testencoding":{"encoding":"jsonParsed"}}'; 46 | LSerializer := TJsonSerializer.Create; 47 | try 48 | LEncoding1.testencoding := base64_zstd; 49 | LJSON2 := LSerializer.Serialize(LEncoding1); 50 | LEncoding2 := LSerializer.Deserialize(LJSON1); 51 | WriteLn('LJSON1: ', LJSON1); 52 | WriteLn('LJSON2: ', LJSON2); 53 | WriteLn; 54 | 55 | WriteLn('JSON1 is same as JSON2: ', SameJson(LJSON1, LJSON2)); 56 | finally 57 | LSerializer.Free; 58 | end; 59 | end; 60 | 61 | procedure Main; 62 | var 63 | LJSON1, LJSON2: string; 64 | LSerializer: TJsonSerializer; 65 | LResult: getAccountInfoResult; 66 | begin 67 | LJSON1 := '{'#13#10+ 68 | ' "context": {'#13#10+ 69 | ' "slot": 9887'#13#10+ 70 | ' },'#13#10+ 71 | ' "value": {'#13#10+ 72 | ' "byIdentity": {'#13#10+ 73 | ' "85iYT5RuzRTDgjyRa3cP8SYhM2j21fj7NhfJ3peu1DPr": ['#13#10+ 74 | ' 9888,'#13#10+ 75 | ' 9886'#13#10+ 76 | ' ]'#13#10+ 77 | ' },'#13#10+ 78 | ' "range": {'#13#10+ 79 | ' "firstSlot": 0,'#13#10+ 80 | ' "lastSlot": 9887'#13#10+ 81 | ' }'#13#10+ 82 | ' }'#13#10+ 83 | '}'#13#10; 84 | LSerializer := TJsonSerializer.Create; 85 | try 86 | LResult := LSerializer.Deserialize(LJSON1); 87 | LJSON2 := LSerializer.Serialize(LResult); 88 | WriteLn('LJSON1: ', LJSON1); 89 | WriteLn('LJSON2: ', LJSON2); 90 | WriteLn; 91 | 92 | WriteLn('JSON1 is same as JSON2: ', SameJson(LJSON1, LJSON2)); 93 | finally 94 | LSerializer.Free; 95 | end; 96 | end; 97 | 98 | begin 99 | TestEncoding; 100 | end. 101 | -------------------------------------------------------------------------------- /Tests/TestJSONDictionaryConverter2.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuacw/JSONRPC_Framework/9463b711d858b7fb91051146b757951923aa1441/Tests/TestJSONDictionaryConverter2.res -------------------------------------------------------------------------------- /Tests/TestJSONRPCGUI.dpr: -------------------------------------------------------------------------------- 1 | program TestJSONRPCGUI; 2 | { 3 | 4 | Delphi DUnit Test Project 5 | ------------------------- 6 | This project contains the DUnit test framework and the GUI/Console test runners. 7 | Add "CONSOLE_TESTRUNNER" to the conditional defines entry in the project options 8 | to use the console test runner. Otherwise the GUI test runner will be used by 9 | default. 10 | 11 | } 12 | 13 | {$IFDEF CONSOLE_TESTRUNNER} 14 | {$APPTYPE CONSOLE} 15 | {$ENDIF} 16 | 17 | uses 18 | DUnitX.TestRunner, 19 | TestJSONRPC.Client in 'TestJSONRPC.Client.pas', 20 | JSONRPC.User.SomeTypes in '..\Common\JSONRPC.User.SomeTypes.pas', 21 | JSONRPC.RIO in '..\Common\JSONRPC.RIO.pas', 22 | JSONRPC.JsonUtils in '..\Common\JSONRPC.JsonUtils.pas', 23 | JSONRPC.InvokeRegistry in '..\Common\JSONRPC.InvokeRegistry.pas', 24 | JSONRPC.Common.Types in '..\Common\JSONRPC.Common.Types.pas', 25 | JSONRPC.Common.Consts in '..\Common\JSONRPC.Common.Consts.pas', 26 | JSONRPC.ServerBase.Runner in '..\Server\JSONRPC.ServerBase.Runner.pas', 27 | JSONRPC.User.SomeTypes.Impl in '..\Client\JSONRPC.User.SomeTypes.Impl.pas', 28 | JSONRPC.Common.RecordHandlers in '..\Common\JSONRPC.Common.RecordHandlers.pas', 29 | JSONRPC.Common.FixBuggyNativeTypes in '..\Common\JSONRPC.Common.FixBuggyNativeTypes.pas', 30 | JSONRPC.CustomServerIdHTTP.Runner in '..\Server\JSONRPC.CustomServerIdHTTP.Runner.pas'; 31 | 32 | {$R *.RES} 33 | 34 | begin 35 | end. 36 | 37 | -------------------------------------------------------------------------------- /Tests/TestJSONRPCGUI.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuacw/JSONRPC_Framework/9463b711d858b7fb91051146b757951923aa1441/Tests/TestJSONRPCGUI.res -------------------------------------------------------------------------------- /ThirdParty/Neslib.MultiPrecision.RecordHandlers.pas: -------------------------------------------------------------------------------- 1 | unit Neslib.MultiPrecision.RecordHandlers; 2 | 3 | interface 4 | 5 | implementation 6 | 7 | uses 8 | JSONRPC.Common.RecordHandlers, Neslib.MultiPrecision, 9 | JSONRPC.Common.Types, System.TypInfo, System.JSON, System.Rtti, 10 | JSONRPC.JsonUtils, JSONRPC.Common.Consts; 11 | 12 | initialization 13 | Neslib.MultiPrecision.MultiPrecisionInit; 14 | RegisterRecordHandler(TypeInfo(QuadDouble), 15 | procedure( 16 | const APassParamByPosOrName: TPassParamByPosOrName; 17 | ATypeInfo: PTypeInfo; 18 | const AParamName: string; 19 | const AParamValuePtr: Pointer; 20 | const AParamsObj: TJSONObject; 21 | const AParamsArray: TJSONArray 22 | ) 23 | // NativeToJSON 24 | var 25 | LJSON: TJSONString; 26 | begin 27 | LJSON := TJSONString.Create(QuadDouble(AParamValuePtr^).ToString); 28 | case APassParamByPosOrName of 29 | tppByName: AParamsObj.AddPair(AParamName, LJSON); 30 | tppByPos: AParamsArray.AddElement(LJSON); 31 | end; 32 | end, 33 | procedure(const AJSONResponseObj: TJSONValue; const APathName: string; AResultP: Pointer) 34 | // JSONToNative 35 | var 36 | LResultValue: string; 37 | begin 38 | AJSONResponseObj.TryGetValue(APathName, LResultValue); 39 | PQuadDouble(AResultP)^.Init(LResultValue); 40 | end, 41 | procedure(const AValue: TValue; ATypeInfo: PTypeInfo; const AJSONObject: TJSONObject) 42 | // TValueToJSON 43 | var 44 | LBigDecimal: QuadDouble; 45 | LJSON: string; 46 | begin 47 | ValueToObj(AValue, ATypeInfo, LBigDecimal); 48 | LJSON := LBigDecimal.ToString; 49 | AJSONObject.AddPair(SRESULT, LJSON); 50 | end, 51 | function(const AJSON: string): TValue 52 | // JSONToTValue 53 | var 54 | LQuadDouble: QuadDouble; 55 | begin 56 | LQuadDouble.Init(AJSON); 57 | Result := TValue.From(LQuadDouble); 58 | end 59 | ); 60 | 61 | // Delphi cannot handle the precision of Extended 62 | // if the client is 32-bit and the server is 64-bit 63 | // so convert to BigDecimal 64 | 65 | RegisterRecordHandler(TypeInfo(DoubleDouble), 66 | // NativeToJSON 67 | procedure( 68 | const APassParamByPosOrName: TPassParamByPosOrName; 69 | ATypeInfo: PTypeInfo; 70 | const AParamName: string; 71 | const AParamValuePtr: Pointer; 72 | const AParamsObj: TJSONObject; 73 | const AParamsArray: TJSONArray 74 | ) 75 | var 76 | LJSON: TJSONString; 77 | begin 78 | LJSON := TJSONString.Create(DoubleDouble(AParamValuePtr^).ToString); 79 | case APassParamByPosOrName of 80 | tppByName: AParamsObj.AddPair(AParamName, LJSON); 81 | tppByPos: AParamsArray.AddElement(LJSON); 82 | end; 83 | end, 84 | // JSONToNative 85 | procedure(const AJSONResponseObj: TJSONValue; const APathName: string; AResultP: Pointer) 86 | var 87 | LResultValue: string; 88 | LDoubleDouble: DoubleDouble; 89 | begin 90 | AJSONResponseObj.TryGetValue(APathName, LResultValue); 91 | DoubleDouble.TryParse(LResultValue, LDoubleDouble); 92 | PDoubleDouble(AResultP)^ := LDoubleDouble; 93 | end, 94 | // TValueToJSON 95 | procedure(const AValue: TValue; ATypeInfo: PTypeInfo; const AJSONObject: TJSONObject) 96 | var 97 | LDoubleDouble: DoubleDouble; 98 | begin 99 | LDoubleDouble := AValue.AsType; 100 | var LJSON := TJSONNumber.Create(LDoubleDouble.ToString); 101 | AJSONObject.AddPair(SRESULT, LJSON); 102 | end, 103 | // JSONToTValue 104 | function(const AJSON: string): TValue 105 | var 106 | LDoubleDouble: DoubleDouble; 107 | begin 108 | DoubleDouble.TryParse(AJSON, LDoubleDouble); 109 | Result := TValue.From(LDoubleDouble); 110 | end 111 | ); 112 | 113 | end. 114 | -------------------------------------------------------------------------------- /Web3/Aptos/JSONRPC.AptosClient.dpr: -------------------------------------------------------------------------------- 1 | program JSONRPC.AptosClient; 2 | 3 | {$APPTYPE CONSOLE} 4 | {$WARN DUPLICATE_CTOR_DTOR OFF} 5 | {$R *.res} 6 | 7 | uses 8 | System.SysUtils, 9 | System.JSON, 10 | JSONRPC.TransportWrapper.HTTP in '..\..\Common\JSONRPC.TransportWrapper.HTTP.pas', 11 | JSONRPC.RIO in '..\..\Common\JSONRPC.RIO.pas', 12 | JSONRPC.JsonUtils in '..\..\Common\JSONRPC.JsonUtils.pas', 13 | JSONRPC.InvokeRegistry in '..\..\Common\JSONRPC.InvokeRegistry.pas', 14 | JSONRPC.Common.Types in '..\..\Common\JSONRPC.Common.Types.pas', 15 | JSONRPC.Common.Consts in '..\..\Common\JSONRPC.Common.Consts.pas', 16 | JSONRPC.Common.RecordHandlers in '..\..\Common\JSONRPC.Common.RecordHandlers.pas', 17 | JSONRPC.Web3.AptosClient.Impl in 'JSONRPC.Web3.AptosClient.Impl.pas', 18 | JSONRPC.Web3.AptosAPI in 'JSONRPC.Web3.AptosAPI.pas', 19 | JSONRPC.TransportWrapper.AptosHTTP in 'JSONRPC.TransportWrapper.AptosHTTP.pas', 20 | JSONRPC.Web3.Aptos.Common.Types in 'JSONRPC.Web3.Aptos.Common.Types.pas', 21 | JSONRPC.Web3.Aptos.RIO in 'JSONRPC.Web3.Aptos.RIO.pas'; 22 | 23 | procedure AssignSafeCallException(const AJSONRPC: IAptosJSONRPC); 24 | begin 25 | AssignJSONRPCSafeCallExceptionHandler(AJSONRPC, 26 | function (ExceptObject: TObject; ExceptAddr: Pointer): HResult 27 | var 28 | LExc: EJSONRPCException; 29 | LExcMethod: EJSONRPCMethodException absolute LExc; 30 | begin 31 | if ExceptObject is EJSONRPCException then 32 | begin 33 | LExc := ExceptObject as EJSONRPCException; 34 | WriteLn('Intercepted safecall exception...'); 35 | Write(Format('message: "%s", code: %d', [LExc.Message, LExc.Code])); 36 | if LExc is EJSONRPCMethodException then 37 | begin 38 | Write(Format(', method: "%s"', [LExcMethod.MethodName])); 39 | end; 40 | WriteLn; 41 | WriteLn(StringOfChar('-', 90)); 42 | end else 43 | if ExceptObject is Exception then 44 | begin 45 | var LExcObj := ExceptObject as Exception; 46 | WriteLn('Intercepted safecall exception...'); 47 | WriteLn(Format('message: "%s"', [LExcObj.Message])); 48 | end; 49 | Result := S_OK; // Clear the error otherwise, CheckAutoResult will raise error 50 | end 51 | ); 52 | end; 53 | 54 | function GetAptosClient(const AURL: string): IAptosJSONRPC; 55 | begin 56 | Result := GetAptosJSONRPC(AURL, 57 | procedure(const AJSONRPCRequest: string) 58 | begin 59 | WriteLn('Sending outgoing request: ', AJSONRPCRequest); 60 | end, 61 | procedure(const AJSONRPCResponse: string) 62 | begin 63 | WriteLn('Received incoming response: ', AJSONRPCResponse); 64 | WriteLn(StringOfChar('-', 80)); 65 | WriteLn; 66 | end, 67 | procedure(const AServerURL: string) 68 | begin 69 | WriteLn('Sending request to ', AServerURL); 70 | WriteLn(StringOfChar('-', 80)); 71 | WriteLn; 72 | end 73 | ); 74 | end; 75 | 76 | procedure RunAptosClient; 77 | begin 78 | var LAptosClient := GetAptosClient(AptosMainNet); 79 | var LJSONGetBlocksByVersion := LAptosClient.GetBlocksByVersion(2309044); 80 | var LGetBlocksByHeight := LAptosClient.GetBlocksByHeight(67193037); 81 | var LAccountResource := LAptosClient.GetAccountResource( 82 | '0xe54a8cf97f4a788b0a792654c6fcb02d10250cc2dacb09a424d67f7c48e2533f', 83 | '0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>' 84 | ); 85 | end; 86 | 87 | begin 88 | ReportMemoryLeaksOnShutdown := True; 89 | try 90 | RunAptosClient; 91 | except 92 | on E: Exception do 93 | WriteLn('Ran into some exception: ', E.Message); 94 | end; 95 | end. 96 | -------------------------------------------------------------------------------- /Web3/Aptos/JSONRPC.AptosClient.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuacw/JSONRPC_Framework/9463b711d858b7fb91051146b757951923aa1441/Web3/Aptos/JSONRPC.AptosClient.res -------------------------------------------------------------------------------- /Web3/Aptos/JSONRPC.TransportWrapper.AptosHTTP.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.TransportWrapper.AptosHTTP; 2 | 3 | interface 4 | 5 | uses 6 | JSONRPC.TransportWrapper.HTTP, System.Classes, System.Net.URLClient; 7 | 8 | type 9 | TJSONRPCAptosClient = class(TJSONRPCHTTPTransportWrapper) 10 | public 11 | procedure Post(const AURL: string; const ASource, AResponseContent: TStream; 12 | const AHeaders: TNetHeaders); override; 13 | end; 14 | 15 | implementation 16 | 17 | uses 18 | JSONRPC.Common.Types; 19 | 20 | { TJSONRPCAptosClient } 21 | 22 | procedure TJSONRPCAptosClient.Post(const AURL: string; 23 | const ASource, AResponseContent: TStream; const AHeaders: TNetHeaders); 24 | begin 25 | FClient.Get(AURL, AResponseContent, AHeaders); 26 | end; 27 | 28 | procedure InitTransportWrapperHTTP; 29 | begin 30 | GJSONRPCTransportWrapperClass := TJSONRPCAptosClient; 31 | end; 32 | 33 | initialization 34 | InitTransportWrapperHTTP; 35 | end. 36 | -------------------------------------------------------------------------------- /Web3/Aptos/JSONRPC.Web3.Aptos.Common.Types.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.Web3.Aptos.Common.Types; 2 | 3 | interface 4 | 5 | uses 6 | System.JSON.Serializers; 7 | 8 | type 9 | [JsonSerialize(TJsonMemberSerialization.Fields)] 10 | TError = record 11 | private 12 | Fcode: Integer; 13 | Fmessage: string; 14 | Fvm_error_code: string; 15 | public 16 | property code: Integer read Fcode write Fcode; 17 | property message: string read Fmessage write Fmessage; 18 | property vm_error_code: string read Fvm_error_code write Fvm_error_code; 19 | end align 16; 20 | 21 | [JsonSerialize(TJsonMemberSerialization.Public)] 22 | TBlocksByHeightResult = record 23 | private 24 | Fblock_height: string; 25 | Fblock_hash: string; 26 | Fblock_timestamp: string; 27 | Ffirst_version: string; 28 | Flast_version: string; 29 | Ftransactions: string; 30 | public 31 | property block_height: string read Fblock_height write Fblock_height; 32 | property block_hash: string read Fblock_hash write Fblock_hash; 33 | property block_timestamp: string read Fblock_timestamp write Fblock_timestamp; 34 | property first_version: string read Ffirst_version write Ffirst_version; 35 | property last_version: string read Flast_version write Flast_version; 36 | property transactions: string read Ftransactions write Ftransactions; 37 | end; 38 | 39 | implementation 40 | 41 | end. 42 | -------------------------------------------------------------------------------- /Web3/Aptos/JSONRPC.Web3.Aptos.RIO.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.Web3.Aptos.RIO; 2 | 3 | interface 4 | 5 | uses 6 | JSONRPC.RIO, System.Classes, System.Net.URLClient, JSONRPC.Common.Types, 7 | JSONRPC.Client.CustomJSONRPCHTTPWrapper; 8 | 9 | type 10 | TWeb3AptosJSONRPCClient = class(TCustomJSONRPCHTTPWrapper) 11 | protected 12 | procedure DoBeforeExecute(const AMethodName: string; AJSONRequest: TStream); override; 13 | 14 | function InitializeHeaders(const ARequestStream: TStream): TNetHeaders; override; 15 | 16 | procedure UpdateServerURL(const AContext: TInvContext; 17 | const AMethMD: TIntfMethEntry; var VServerURL: string); override; 18 | public 19 | constructor Create(AOwner: TComponent); override; 20 | end; 21 | 22 | implementation 23 | 24 | uses 25 | JSONRPC.Common.Consts, System.Rtti, System.SysUtils, 26 | System.TypInfo; 27 | 28 | { TWeb3AptosJSONRPCClient } 29 | 30 | constructor TWeb3AptosJSONRPCClient.Create(AOwner: TComponent); 31 | begin 32 | inherited; 33 | FPassByPosOrName := tppByPos; 34 | end; 35 | 36 | procedure TWeb3AptosJSONRPCClient.DoBeforeExecute(const AMethodName: string; 37 | AJSONRequest: TStream); 38 | begin 39 | // Aptos is a REST server, not a JSON RPC server, so no need to include a JSON RPC request 40 | AJSONRequest.Size := 0; 41 | inherited; 42 | end; 43 | 44 | function TWeb3AptosJSONRPCClient.InitializeHeaders( 45 | const ARequestStream: TStream): TNetHeaders; 46 | begin 47 | Result := [ 48 | TNameValuePair.Create(SHeadersAccept, SApplicationJson), 49 | TNameValuePair.Create(SHeadersContentType, SApplicationJson) 50 | ]; 51 | end; 52 | 53 | procedure TWeb3AptosJSONRPCClient.UpdateServerURL( 54 | const AContext: TInvContext; 55 | const AMethMD: TIntfMethEntry; var VServerURL: string); 56 | var 57 | LMethod: TRttiMethod; 58 | LParamName: string; 59 | LParamTypeInfo: PTypeInfo; 60 | I: Integer; 61 | LParamPointer: Pointer; 62 | begin 63 | if AMethMD.ParamCount > 0 then 64 | begin 65 | I := 0; 66 | for var LParam in AMethMD.Params do 67 | begin 68 | if LParam.Info = nil then 69 | Continue; // Exit better or continue? 70 | LParamName := Format('{%s}', [LParam.Name]); 71 | if VServerURL.Contains(LParamName) then 72 | begin 73 | LParamTypeInfo := AMethMD.Params[I].Info; 74 | LParamPointer := AContext.GetParamPointer(I); 75 | case LParamTypeInfo.Kind of 76 | tkString, tkUString: 77 | VServerURL := StringReplace(VServerURL, LParamName, string(LParamPointer^), [rfReplaceAll]); 78 | tkInteger: begin 79 | var LValue := IntToStr(PInteger(LParamPointer)^); 80 | VServerURL := StringReplace(VServerURL, LParamName, LValue, [rfReplaceAll]); 81 | end; 82 | tkInt64: begin 83 | var LValue := IntToStr(PUInt64(LParamPointer)^); 84 | VServerURL := StringReplace(VServerURL, LParamName, LValue, [rfReplaceAll]); 85 | end; 86 | end; 87 | end; 88 | Inc(I); 89 | end; 90 | end; 91 | end; 92 | 93 | end. 94 | -------------------------------------------------------------------------------- /Web3/Aptos/JSONRPC.Web3.AptosAPI.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.Web3.AptosAPI; 2 | 3 | interface 4 | 5 | uses 6 | JSONRPC.RIO, JSONRPC.Common.Types, System.JSON, 7 | JSONRPC.Web3.Aptos.Common.Types; 8 | 9 | const 10 | AptosMainNet = 'https://fullnode.mainnet.aptoslabs.com/'; 11 | AptosDevNet = 'https://fullnode.devnet.aptoslabs.com/'; 12 | AptosTestNet = 'https://fullnode.testnet.aptoslabs.com/'; 13 | 14 | type 15 | 16 | AptosAddress = string; 17 | 18 | IAptosJSONRPC = interface(IJSONRPCMethods) 19 | ['{A1E94111-1F64-40A3-8544-7D6279EEEA3C}'] 20 | 21 | [UrlSuffix('/v1/accounts/{Address}')] 22 | function GetAccount(const Address: AptosAddress): TJSONObject; safecall; 23 | 24 | [UrlSuffix('/v1/blocks/by_height/{height}')] 25 | function GetBlocksByHeight(const height: UInt64): TBlocksByHeightResult; safecall; 26 | 27 | [UrlSuffix('/v1/blocks/by_version/{version}')] 28 | function GetBlocksByVersion(const version: Integer): TJSONValue; safecall; 29 | 30 | [UrlSuffix('/v1/accounts/{address}/resources')] 31 | function GetAccountResources(const address: AptosAddress): TJSONValue; safecall; 32 | 33 | [UrlSuffix('/v1/accounts/{address}/modules')] 34 | function GetAccountModules(const address: AptosAddress): TJSONValue; safecall; 35 | 36 | [UrlSuffix('/v1/accounts/{address}/resource/{resource_type}')] 37 | function GetAccountResource(const address: AptosAddress; 38 | const resource_type: string): TJSONValue; safecall; 39 | end; 40 | 41 | implementation 42 | 43 | uses 44 | JSONRPC.InvokeRegistry; 45 | 46 | initialization 47 | InvokableRegistry.RegisterInterface(TypeInfo(IAptosJSONRPC)); 48 | end. 49 | -------------------------------------------------------------------------------- /Web3/Aptos/JSONRPC.Web3.AptosClient.Impl.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.Web3.AptosClient.Impl; 2 | 3 | {$ALIGN 16} 4 | {$CODEALIGN 16} 5 | 6 | interface 7 | 8 | uses 9 | JSONRPC.Common.Types, System.Classes, System.JSON.Serializers, 10 | JSONRPC.RIO, JSONRPC.Web3.AptosAPI; 11 | 12 | function GetAptosJSONRPC(const ServerURL: string = ''; 13 | const AOnLoggingOutgoingJSONRequest: TOnLogOutgoingJSONRequest = nil; 14 | const AOnLoggingIncomingJSONResponse: TOnLogIncomingJSONResponse = nil; 15 | const AOnLogServerURL: TOnLogServerURL = nil 16 | ): IAptosJSONRPC; 17 | 18 | implementation 19 | 20 | uses 21 | {$IF DEFINED(TEST) OR DEFINED(DEBUG)} 22 | Winapi.Windows, 23 | {$ENDIF} 24 | JSONRPC.Common.Consts, 25 | System.JSON, System.Rtti, JSONRPC.InvokeRegistry, 26 | JSONRPC.JsonUtils, Web3.Aptos.RIO; 27 | 28 | function GetAptosJSONRPC(const ServerURL: string = ''; 29 | const AOnLoggingOutgoingJSONRequest: TOnLogOutgoingJSONRequest = nil; 30 | const AOnLoggingIncomingJSONResponse: TOnLogIncomingJSONResponse = nil; 31 | const AOnLogServerURL: TOnLogServerURL = nil 32 | ): IAptosJSONRPC; 33 | begin 34 | RegisterJSONRPCWrapper(TypeInfo(IAptosJSONRPC)); 35 | 36 | var LJSONRPCWrapper := TWeb3AptosJSONRPCWrapper.Create(nil); 37 | LJSONRPCWrapper.ServerURL := ServerURL; 38 | 39 | LJSONRPCWrapper.OnLogOutgoingJSONRequest := AOnLoggingOutgoingJSONRequest; 40 | LJSONRPCWrapper.OnLogIncomingJSONResponse := AOnLoggingIncomingJSONResponse; 41 | LJSONRPCWrapper.OnLogServerURL := AOnLogServerURL; 42 | 43 | Result := LJSONRPCWrapper as IAptosJSONRPC; 44 | 45 | {$IF DECLARED(IsDebuggerPresent)} 46 | if IsDebuggerPresent then 47 | begin 48 | LJSONRPCWrapper.SendTimeout := 10*60*1000; 49 | LJSONRPCWrapper.ResponseTimeout := LJSONRPCWrapper.SendTimeout; 50 | {$IF RTLVersion >= TRTLVersion.Delphi120 } 51 | LJSONRPCWrapper.ConnectionTimeout := LJSONRPCWrapper.SendTimeout; 52 | {$ENDIF} 53 | end; 54 | {$ENDIF} 55 | 56 | end; 57 | 58 | end. 59 | -------------------------------------------------------------------------------- /Web3/Aptos/Web3.AptosAPI.pas: -------------------------------------------------------------------------------- 1 | unit Web3.AptosAPI; 2 | 3 | interface 4 | 5 | uses 6 | JSONRPC.RIO, JSONRPC.Common.Types, 7 | System.SysUtils, System.JSON; 8 | 9 | type 10 | 11 | AptosAddress = string; 12 | 13 | IAptosJSONRPC = interface(IJSONRPCMethods) 14 | [UrlSuffix('/v1/accounts/address')] 15 | function GetAccount(const Address: AptosAddress): TJSONObject; 16 | 17 | end; 18 | 19 | implementation 20 | 21 | end. 22 | -------------------------------------------------------------------------------- /Web3/Bitcoin/JSONRPC.BitcoinClient.dpr: -------------------------------------------------------------------------------- 1 | program JSONRPC.BitcoinClient; 2 | 3 | {$APPTYPE CONSOLE} 4 | {$WARN DUPLICATE_CTOR_DTOR OFF} 5 | {$R *.res} 6 | 7 | uses 8 | System.SysUtils, 9 | JSONRPC.TransportWrapper.HTTP in '..\..\Common\JSONRPC.TransportWrapper.HTTP.pas', 10 | JSONRPC.RIO in '..\..\Common\JSONRPC.RIO.pas', 11 | JSONRPC.JsonUtils in '..\..\Common\JSONRPC.JsonUtils.pas', 12 | JSONRPC.InvokeRegistry in '..\..\Common\JSONRPC.InvokeRegistry.pas', 13 | JSONRPC.Common.Types in '..\..\Common\JSONRPC.Common.Types.pas', 14 | JSONRPC.Common.RecordHandlers in '..\..\Common\JSONRPC.Common.RecordHandlers.pas', 15 | JSONRPC.Common.Consts in '..\..\Common\JSONRPC.Common.Consts.pas', 16 | JSONRPC.User.BitcoinRPC in 'JSONRPC.User.BitcoinRPC.pas', 17 | JSONRPC.User.BitcoinTypes in 'JSONRPC.User.BitcoinTypes.pas', 18 | JSONRPC.User.Types.MemoryInfo in 'JSONRPC.User.Types.MemoryInfo.pas', 19 | JSONRPC.User.Types.WalletInfo in 'JSONRPC.User.Types.WalletInfo.pas', 20 | dotenv in '..\..\..\GitHub\dotenv.pas', 21 | JSONRPC.User.Types.BlockchainInfo in 'JSONRPC.User.Types.BlockchainInfo.pas', 22 | JSONRPC.User.Types.BestBlockHash in 'JSONRPC.User.Types.BestBlockHash.pas', 23 | JSONRPC.User.Types.BlockInfo in 'JSONRPC.User.Types.BlockInfo.pas', 24 | JSONRPC.User.Types.BlockDefaultInfo in 'JSONRPC.User.Types.BlockDefaultInfo.pas', 25 | JSONRPC.RttiUtils in '..\..\Common\JSONRPC.RttiUtils.pas', 26 | JSONRPC.Common.FixBuggyNativeTypes in '..\..\Common\JSONRPC.Common.FixBuggyNativeTypes.pas', 27 | JSONRPC.Common.Converters in '..\..\Common\JSONRPC.Common.Converters.pas'; 28 | 29 | procedure BitcoinOutgoingRequest(const AJSONRPCRequest: string); 30 | begin 31 | WriteLn('Outgoing request -----------------------------------------------'); 32 | WriteLn(AJSONRPCRequest); 33 | end; 34 | 35 | procedure BitcoinIncomingResponse(const AJSONRPCResponse: string); 36 | begin 37 | WriteLn('Incoming response ----------------------------------------------'); 38 | WriteLn(AJSONRPCResponse); 39 | end; 40 | 41 | procedure Main; 42 | var 43 | LBitcoinRPCServer: IBitcoinJSONRPC; 44 | LMemoryInfo: MemoryInfoResult; 45 | LWalletInfo: WalletInfoResult; 46 | LServer, LUserName, LPassword: string; 47 | LBlockCount: UInt64; 48 | begin 49 | LUserName := process.env['username']; // Alternatively, process['username'] 50 | LPassword := process.env['password']; // '' process.env['password'] 51 | LServer := process.env['server']; // '' process.env['server'] 52 | 53 | LBitcoinRPCServer := GetBitcoinJSONRPC(LServer, LUserName, LPassword, 54 | BitcoinOutgoingRequest, BitcoinIncomingResponse 55 | ); 56 | var LBestBlockHash := LBitcoinRPCServer.BestBlockHash; 57 | var LBlockHash := LBitcoinRPCServer.BlockHash[1000]; 58 | // The following RPC call will take a long time to return 59 | var LBlock := LBitcoinRPCServer.getblockJSONObject(LBestBlockHash, 1); 60 | // var LBlockJSONObj := LBitcoinRPCServer.getblock(LBestBlockHash, TVerbosity.HexEncodedData); 61 | 62 | LMemoryInfo := LBitcoinRPCServer.MemoryInfo; 63 | LWalletInfo := LBitcoinRPCServer.WalletInfo; 64 | LBlockCount := LBitcoinRPCServer.BlockCount; 65 | var LBlockchainInfo := LBitcoinRPCServer.BlockchainInfo; 66 | end; 67 | 68 | begin 69 | ReportMemoryLeaksOnShutdown := True; 70 | try 71 | try 72 | Main; 73 | except 74 | on E: Exception do 75 | WriteLn(E.Message); 76 | end; 77 | finally 78 | Write('Press enter to close'); 79 | ReadLn; 80 | end; 81 | end. 82 | -------------------------------------------------------------------------------- /Web3/Bitcoin/JSONRPC.BitcoinClient.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuacw/JSONRPC_Framework/9463b711d858b7fb91051146b757951923aa1441/Web3/Bitcoin/JSONRPC.BitcoinClient.res -------------------------------------------------------------------------------- /Web3/Bitcoin/JSONRPC.User.BitcoinRPC.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.User.BitcoinRPC; 2 | 3 | {$ALIGN 16} 4 | {$CODEALIGN 16} 5 | 6 | interface 7 | 8 | uses 9 | JSONRPC.Common.Types, System.Classes, System.JSON.Serializers, 10 | JSONRPC.RIO, JSONRPC.User.BitcoinTypes; 11 | 12 | /// 13 | /// Returns an interface to the Bitcoin JSON RPC 14 | /// 15 | function GetBitcoinJSONRPC( 16 | const AServerURL: string = ''; 17 | const AUserName: string = ''; 18 | const APassword: string = ''; 19 | const AOnLoggingOutgoingJSONRPCRequest: TOnLogOutgoingJSONRPCRequest = nil; 20 | const AOnLoggingIncomingJSONRPCResponse: TOnLogIncomingJSONRPCResponse = nil 21 | ): IBitcoinJSONRPC; 22 | 23 | implementation 24 | 25 | uses 26 | {$IF DEFINED(TEST) OR DEFINED(DEBUG)} 27 | Winapi.Windows, 28 | {$ENDIF} 29 | System.JSON, System.Rtti, JSONRPC.InvokeRegistry, System.TypInfo, 30 | JSONRPC.JsonUtils, System.SysUtils, System.NetEncoding; 31 | 32 | function GetBitcoinJSONRPC( 33 | const AServerURL: string = ''; 34 | const AUserName: string = ''; 35 | const APassword: string = ''; 36 | const AOnLoggingOutgoingJSONRPCRequest: TOnLogOutgoingJSONRPCRequest = nil; 37 | const AOnLoggingIncomingJSONRPCResponse: TOnLogIncomingJSONRPCResponse = nil 38 | ): IBitcoinJSONRPC; 39 | begin 40 | RegisterJSONRPCWrapper(TypeInfo(IBitcoinJSONRPC)); 41 | 42 | var LJSONRPCWrapper := TJSONRPCWrapper.Create; 43 | LJSONRPCWrapper.ServerURL := AServerURL; 44 | LJSONRPCWrapper.PassParamsByPos := True; 45 | 46 | if (AUserName <> '') or (APassword <> '') then 47 | begin 48 | LJSONRPCWrapper.OnBeforeInitializeHeaders := procedure (var VNetHeaders: TNetHeaders) 49 | begin 50 | var LUserNamePassword := Format('%s:%s', [AUserName, APassword]); 51 | VNetHeaders := [TNameValuePair.Create('Authorization', 'Basic ' + 52 | TNetEncoding.Base64String.Encode(LUserNamePassword))]; 53 | end; 54 | end; 55 | 56 | LJSONRPCWrapper.OnParseEnum := function (const ARttiContext: TRttiContext; 57 | const AMethMD: TIntfMethEntry; AParamIndex: Integer; 58 | AParamTypeInfo: PTypeInfo; AParamValuePtr: Pointer; AParamsObj: TJSONObject; 59 | AParamsArray: TJSONArray): Boolean 60 | var 61 | LMethods: TArray; 62 | LIntfType: TRttiType; 63 | LMethType: TRttiMethod; 64 | LParams: TArray; 65 | begin 66 | LIntfType := ARttiContext.GetType(AMethMD.SelfInfo) as TRttiInterfaceType; 67 | LMethods := LIntfType.GetDeclaredMethods; 68 | LMethType := LMethods[AMethMD.Pos-3]; 69 | LParams := LMethType.GetParameters; 70 | Result := LParams[AParamIndex-1].HasAttribute; 71 | end; 72 | 73 | LJSONRPCWrapper.OnLogOutgoingJSONRPCRequest := AOnLoggingOutgoingJSONRPCRequest; 74 | LJSONRPCWrapper.OnLogIncomingJSONRPCResponse := AOnLoggingIncomingJSONRPCResponse; 75 | 76 | Result := LJSONRPCWrapper as IBitcoinJSONRPC; 77 | 78 | {$IF DECLARED(IsDebuggerPresent)} 79 | if IsDebuggerPresent then 80 | begin 81 | var LTimeout := 10*60*1000; 82 | LJSONRPCWrapper.SendTimeout := LTimeout; 83 | LJSONRPCWrapper.ResponseTimeout := LTimeout; 84 | LJSONRPCWrapper.ConnectionTimeout := LTimeout; 85 | end; 86 | {$ENDIF} 87 | 88 | end; 89 | 90 | initialization 91 | InvokableRegistry.RegisterInterface(TypeInfo(IBitcoinJSONRPC)); 92 | end. 93 | -------------------------------------------------------------------------------- /Web3/Bitcoin/JSONRPC.User.BitcoinTypes.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.User.BitcoinTypes; 2 | 3 | interface 4 | 5 | uses 6 | JSONRPC.RIO, JSONRPC.Common.Types, JSONRPC.User.Types.MemoryInfo, 7 | JSONRPC.User.Types.WalletInfo, JSONRPC.User.Types.BlockchainInfo, 8 | JSONRPC.User.Types.BestBlockHash, JSONRPC.User.Types.BlockDefaultInfo; 9 | 10 | type 11 | BlockHash = string; 12 | {$SCOPEDENUMS ON} 13 | TVerbosity = (HexEncodedData, JSONObject, JSONObjectWithTransactionData); 14 | 15 | /// 16 | /// Bitcoin RPC: https://developer.bitcoin.org/reference/rpc/ 17 | /// 18 | IBitcoinJSONRPC = interface(IJSONRPCMethods) 19 | ['{EA7B1DAB-1301-401C-82F5-7A903EA8D898}'] 20 | 21 | // Control RPC 22 | 23 | [JSONMethodName('getblock')] 24 | function getblockJSONObject(const ABlockHash: BlockHash; Verbosity: Word = 1): BlockDefaultResult; overload; 25 | 26 | function getblock(const ABlockHash: BlockHash; 27 | [JSONMarshalAsNumber] 28 | Verbosity: TVerbosity = TVerbosity.JSONObject): BlockDefaultResult; overload; 29 | 30 | function getmemoryinfo: MemoryInfoResult; 31 | 32 | // Wallet RPC 33 | function getwalletinfo: WalletInfoResult; 34 | 35 | // Blockchain RPCs 36 | function getbestblockhash: BestBlockHashResult; 37 | function getblockcount: UInt64; 38 | function getblockchaininfo: BlockchainInfoResult; 39 | function getblockhash(Height: UInt64): string; 40 | 41 | // Rawtransaction RPCs 42 | // function getrawtransaction(const txid: string); 43 | 44 | property BlockHash[Height: UInt64]: string read getblockhash; 45 | property BestBlockHash: BestBlockHashResult read getbestblockhash; 46 | property BlockchainInfo: BlockchainInfoResult read getblockchaininfo; 47 | property BlockCount: UInt64 read getblockcount; 48 | property MemoryInfo: MemoryInfoResult read getmemoryinfo; 49 | property WalletInfo: WalletInfoResult read getwalletinfo; 50 | end; 51 | 52 | implementation 53 | 54 | end. 55 | -------------------------------------------------------------------------------- /Web3/Bitcoin/JSONRPC.User.Types.BestBlockHash.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.User.Types.BestBlockHash; 2 | 3 | interface 4 | 5 | type 6 | BestBlockHashResult = string; 7 | 8 | implementation 9 | 10 | end. 11 | -------------------------------------------------------------------------------- /Web3/Bitcoin/JSONRPC.User.Types.BlockDefaultInfo.pas: -------------------------------------------------------------------------------- 1 | // This unit is autogenerated. Do not edit it manually. 2 | // Source: JSON entered in editor 3 | // Date: 3/11/2023 3:07:35 PM 4 | 5 | unit JSONRPC.User.Types.BlockDefaultInfo; 6 | 7 | interface 8 | 9 | uses 10 | System.JSON.Serializers, System.JSON, JSONRPC.Common.Types; 11 | 12 | type 13 | [JsonSerialize(TJsonMemberSerialization.Fields)] 14 | BlockDefaultResult = record 15 | private 16 | [JsonName('hash')] 17 | Fhash: string; 18 | [JsonName('confirmations')] 19 | Fconfirmations: Integer; 20 | [JsonName('height')] 21 | Fheight: Integer; 22 | [JsonName('version')] 23 | Fversion: Integer; 24 | [JsonName('versionHex')] 25 | FversionHex: string; 26 | [JsonName('merkleroot')] 27 | Fmerkleroot: string; 28 | [JsonName('time')] 29 | Ftime: Integer; 30 | [JsonName('mediantime')] 31 | Fmediantime: Integer; 32 | [JsonName('nonce')] 33 | Fnonce: Int64; 34 | [JsonName('bits'), JsonConverterAttribute(TJsonDelphiHexConverter)] 35 | Fbits: Integer; 36 | [JsonName('difficulty')] 37 | Fdifficulty: Double; 38 | [JsonName('chainwork')] 39 | Fchainwork: string; 40 | [JsonName('nTx')] 41 | FnTx: Integer; 42 | [JsonName('previousblockhash')] 43 | Fpreviousblockhash: string; 44 | [JsonName('strippedsize')] 45 | Fstrippedsize: Integer; 46 | [JsonName('size')] 47 | Fsize: Integer; 48 | [JsonName('weight')] 49 | Fweight: Integer; 50 | [JsonName('tx')] 51 | Ftx: TArray; 52 | public 53 | class function FromJSON(const AValue: TJSONValue): BlockDefaultResult; overload; static; 54 | class function FromJSON(const AValue: string): BlockDefaultResult; overload; static; 55 | function ToJSONObject: TJSONValue; 56 | function ToJSONString: string; 57 | property hash: string read Fhash write Fhash; 58 | property confirmations: Integer read Fconfirmations write Fconfirmations; 59 | property height: Integer read Fheight write Fheight; 60 | property version: Integer read Fversion write Fversion; 61 | property versionHex: string read FversionHex write FversionHex; 62 | property merkleroot: string read Fmerkleroot write Fmerkleroot; 63 | property time: Integer read Ftime write Ftime; 64 | property mediantime: Integer read Fmediantime write Fmediantime; 65 | property nonce: Int64 read Fnonce write Fnonce; 66 | property bits: Integer read Fbits write Fbits; 67 | property difficulty: Double read Fdifficulty write Fdifficulty; 68 | property chainwork: string read Fchainwork write Fchainwork; 69 | property nTx: Integer read FnTx write FnTx; 70 | property previousblockhash: string read Fpreviousblockhash write Fpreviousblockhash; 71 | property strippedsize: Integer read Fstrippedsize write Fstrippedsize; 72 | property size: Integer read Fsize write Fsize; 73 | property weight: Integer read Fweight write Fweight; 74 | property tx: TArray read Ftx write Ftx; 75 | end; 76 | 77 | implementation 78 | 79 | class function BlockDefaultResult.FromJSON(const AValue: TJSONValue): BlockDefaultResult; 80 | begin 81 | Result := TJSONMapper.Default.FromObject(AValue); 82 | end; 83 | 84 | class function BlockDefaultResult.FromJSON(const AValue: string): BlockDefaultResult; 85 | begin 86 | Result := TJSONMapper.Default.FromObject(AValue); 87 | end; 88 | 89 | function BlockDefaultResult.ToJSONObject: TJSONValue; 90 | begin 91 | Result := TJSONMapper.Default.ToObject(Self); 92 | end; 93 | 94 | function BlockDefaultResult.ToJSONString: string; 95 | begin 96 | Result := TJSONMapper.Default.ToString(Self); 97 | end; 98 | 99 | end. 100 | -------------------------------------------------------------------------------- /Web3/Bitcoin/JSONRPC.User.Types.BlockInfo.pas: -------------------------------------------------------------------------------- 1 | // This unit is autogenerated. Do not edit it manually. 2 | // Source: JSON entered in editor 3 | // Date: 3/11/2023 2:54:22 PM 4 | 5 | unit JSONRPC.User.Types.BlockInfo; 6 | 7 | interface 8 | 9 | uses 10 | System.JSON.Serializers, System.JSON; 11 | 12 | type 13 | [JsonSerialize(TJsonMemberSerialization.Fields)] 14 | TScriptSig = record 15 | private 16 | [JsonName('asm')] 17 | Fasm: string; 18 | [JsonName('hex')] 19 | Fhex: string; 20 | public 21 | property &asm: string read Fasm write Fasm; 22 | property hex: string read Fhex write Fhex; 23 | end; 24 | 25 | [JsonSerialize(TJsonMemberSerialization.Fields)] 26 | TScriptPubKey = record 27 | private 28 | [JsonName('asm')] 29 | Fasm: string; 30 | [JsonName('desc')] 31 | Fdesc: string; 32 | [JsonName('hex')] 33 | Fhex: string; 34 | [JsonName('address')] 35 | Faddress: string; 36 | [JsonName('type')] 37 | Ftype: string; 38 | public 39 | property &asm: string read Fasm write Fasm; 40 | property desc: string read Fdesc write Fdesc; 41 | property hex: string read Fhex write Fhex; 42 | property address: string read Faddress write Faddress; 43 | property &type: string read Ftype write Ftype; 44 | end; 45 | 46 | [JsonSerialize(TJsonMemberSerialization.Fields)] 47 | TVin = record 48 | private 49 | [JsonName('coinbase')] 50 | Fcoinbase: string; 51 | [JsonName('txinwitness')] 52 | Ftxinwitness: TArray; 53 | [JsonName('sequence')] 54 | Fsequence: Int64; 55 | [JsonName('txid')] 56 | Ftxid: string; 57 | [JsonName('vout')] 58 | Fvout: Integer; 59 | [JsonName('scriptSig')] 60 | FscriptSig: TScriptSig; 61 | public 62 | property coinbase: string read Fcoinbase write Fcoinbase; 63 | property txinwitness: TArray read Ftxinwitness write Ftxinwitness; 64 | property sequence: Int64 read Fsequence write Fsequence; 65 | property txid: string read Ftxid write Ftxid; 66 | property vout: Integer read Fvout write Fvout; 67 | property scriptSig: TScriptSig read FscriptSig write FscriptSig; 68 | end; 69 | 70 | [JsonSerialize(TJsonMemberSerialization.Fields)] 71 | TVout = record 72 | private 73 | [JsonName('value')] 74 | Fvalue: Double; 75 | [JsonName('n')] 76 | Fn: Integer; 77 | [JsonName('scriptPubKey')] 78 | FscriptPubKey: TScriptPubKey; 79 | public 80 | property value: Double read Fvalue write Fvalue; 81 | property n: Integer read Fn write Fn; 82 | property scriptPubKey: TScriptPubKey read FscriptPubKey write FscriptPubKey; 83 | end; 84 | 85 | [JsonSerialize(TJsonMemberSerialization.Fields)] 86 | TTx = record 87 | private 88 | [JsonName('txid')] 89 | Ftxid: string; 90 | [JsonName('hash')] 91 | Fhash: string; 92 | [JsonName('version')] 93 | Fversion: Integer; 94 | [JsonName('size')] 95 | Fsize: Integer; 96 | [JsonName('vsize')] 97 | Fvsize: Integer; 98 | [JsonName('weight')] 99 | Fweight: Integer; 100 | [JsonName('locktime')] 101 | Flocktime: Integer; 102 | [JsonName('vin')] 103 | Fvin: TArray; 104 | [JsonName('vout')] 105 | Fvout: TArray; 106 | [JsonName('hex')] 107 | Fhex: string; 108 | [JsonName('fee')] 109 | Ffee: Double; 110 | public 111 | property txid: string read Ftxid write Ftxid; 112 | property hash: string read Fhash write Fhash; 113 | property version: Integer read Fversion write Fversion; 114 | property size: Integer read Fsize write Fsize; 115 | property vsize: Integer read Fvsize write Fvsize; 116 | property weight: Integer read Fweight write Fweight; 117 | property locktime: Integer read Flocktime write Flocktime; 118 | property vin: TArray read Fvin write Fvin; 119 | property vout: TArray read Fvout write Fvout; 120 | property hex: string read Fhex write Fhex; 121 | property fee: Double read Ffee write Ffee; 122 | end; 123 | 124 | [JsonSerialize(TJsonMemberSerialization.Fields)] 125 | BlockResult = record 126 | private 127 | [JsonName('hash')] 128 | Fhash: string; 129 | [JsonName('confirmations')] 130 | Fconfirmations: Integer; 131 | [JsonName('height')] 132 | Fheight: Integer; 133 | [JsonName('version')] 134 | Fversion: Integer; 135 | [JsonName('versionHex')] 136 | FversionHex: Integer; 137 | [JsonName('merkleroot')] 138 | Fmerkleroot: string; 139 | [JsonName('time')] 140 | Ftime: Integer; 141 | [JsonName('mediantime')] 142 | Fmediantime: Integer; 143 | [JsonName('nonce')] 144 | Fnonce: Int64; 145 | [JsonName('bits')] 146 | Fbits: Integer; 147 | [JsonName('difficulty')] 148 | Fdifficulty: Double; 149 | [JsonName('chainwork')] 150 | Fchainwork: string; 151 | [JsonName('nTx')] 152 | FnTx: Integer; 153 | [JsonName('previousblockhash')] 154 | Fpreviousblockhash: string; 155 | [JsonName('strippedsize')] 156 | Fstrippedsize: Integer; 157 | [JsonName('size')] 158 | Fsize: Integer; 159 | [JsonName('weight')] 160 | Fweight: Integer; 161 | [JsonName('tx')] 162 | Ftx: TArray; 163 | public 164 | class function FromJSON(const AValue: TJSONValue): BlockResult; overload; static; 165 | class function FromJSON(const AValue: string): BlockResult; overload; static; 166 | function ToJSONObject: TJSONValue; 167 | function ToJSONString: string; 168 | property hash: string read Fhash write Fhash; 169 | property confirmations: Integer read Fconfirmations write Fconfirmations; 170 | property height: Integer read Fheight write Fheight; 171 | property version: Integer read Fversion write Fversion; 172 | property versionHex: Integer read FversionHex write FversionHex; 173 | property merkleroot: string read Fmerkleroot write Fmerkleroot; 174 | property time: Integer read Ftime write Ftime; 175 | property mediantime: Integer read Fmediantime write Fmediantime; 176 | property nonce: Int64 read Fnonce write Fnonce; 177 | property bits: Integer read Fbits write Fbits; 178 | property difficulty: Double read Fdifficulty write Fdifficulty; 179 | property chainwork: string read Fchainwork write Fchainwork; 180 | property nTx: Integer read FnTx write FnTx; 181 | property previousblockhash: string read Fpreviousblockhash write Fpreviousblockhash; 182 | property strippedsize: Integer read Fstrippedsize write Fstrippedsize; 183 | property size: Integer read Fsize write Fsize; 184 | property weight: Integer read Fweight write Fweight; 185 | property tx: TArray read Ftx write Ftx; 186 | end; 187 | 188 | implementation 189 | 190 | class function BlockResult.FromJSON(const AValue: TJSONValue): BlockResult; 191 | begin 192 | Result := TJSONMapper.Default.FromObject(AValue); 193 | end; 194 | 195 | class function BlockResult.FromJSON(const AValue: string): BlockResult; 196 | begin 197 | Result := TJSONMapper.Default.FromObject(AValue); 198 | end; 199 | 200 | function BlockResult.ToJSONObject: TJSONValue; 201 | begin 202 | Result := TJSONMapper.Default.ToObject(Self); 203 | end; 204 | 205 | function BlockResult.ToJSONString: string; 206 | begin 207 | Result := TJSONMapper.Default.ToString(Self); 208 | end; 209 | 210 | end. 211 | -------------------------------------------------------------------------------- /Web3/Bitcoin/JSONRPC.User.Types.BlockchainInfo.pas: -------------------------------------------------------------------------------- 1 | // This unit is autogenerated. Do not edit it manually. 2 | // Source: JSON entered in editor 3 | // Date: 3/11/2023 2:32:52 PM 4 | 5 | unit JSONRPC.User.Types.BlockchainInfo; 6 | 7 | interface 8 | 9 | uses 10 | System.JSON.Serializers, System.JSON; 11 | 12 | type 13 | [JsonSerialize(TJsonMemberSerialization.Fields)] 14 | BlockchainInfoResult = record 15 | private 16 | [JsonName('chain')] 17 | Fchain: string; 18 | [JsonName('blocks')] 19 | Fblocks: Integer; 20 | [JsonName('headers')] 21 | Fheaders: Integer; 22 | [JsonName('bestblockhash')] 23 | Fbestblockhash: string; 24 | [JsonName('difficulty')] 25 | Fdifficulty: Double; 26 | [JsonName('time')] 27 | Ftime: Integer; 28 | [JsonName('mediantime')] 29 | Fmediantime: Integer; 30 | [JsonName('verificationprogress')] 31 | Fverificationprogress: Double; 32 | [JsonName('initialblockdownload')] 33 | Finitialblockdownload: Boolean; 34 | [JsonName('chainwork')] 35 | Fchainwork: string; 36 | [JsonName('size_on_disk')] 37 | Fsize_on_disk: UInt64; 38 | [JsonName('pruned')] 39 | Fpruned: Boolean; 40 | [JsonName('pruneheight')] 41 | Fpruneheight: Integer; 42 | [JsonName('automatic_pruning')] 43 | Fautomatic_pruning: Boolean; 44 | [JsonName('prune_target_size')] 45 | Fprune_target_size: UInt64; 46 | [JsonName('warnings')] 47 | Fwarnings: string; 48 | public 49 | class function FromJSON(const AValue: TJSONValue): BlockchainInfoResult; overload; static; 50 | class function FromJSON(const AValue: string): BlockchainInfoResult; overload; static; 51 | function ToJSONObject: TJSONValue; 52 | function ToJSONString: string; 53 | property chain: string read Fchain write Fchain; 54 | property blocks: Integer read Fblocks write Fblocks; 55 | property headers: Integer read Fheaders write Fheaders; 56 | property bestblockhash: string read Fbestblockhash write Fbestblockhash; 57 | property difficulty: Double read Fdifficulty write Fdifficulty; 58 | property time: Integer read Ftime write Ftime; 59 | property mediantime: Integer read Fmediantime write Fmediantime; 60 | property verificationprogress: Double read Fverificationprogress write Fverificationprogress; 61 | property initialblockdownload: Boolean read Finitialblockdownload write Finitialblockdownload; 62 | property chainwork: string read Fchainwork write Fchainwork; 63 | property size_on_disk: UInt64 read Fsize_on_disk write Fsize_on_disk; 64 | property pruned: Boolean read Fpruned write Fpruned; 65 | property pruneheight: Integer read Fpruneheight write Fpruneheight; 66 | property automatic_pruning: Boolean read Fautomatic_pruning write Fautomatic_pruning; 67 | property prune_target_size: UInt64 read Fprune_target_size write Fprune_target_size; 68 | property warnings: string read Fwarnings write Fwarnings; 69 | end; 70 | 71 | implementation 72 | 73 | class function BlockchainInfoResult.FromJSON(const AValue: TJSONValue): BlockchainInfoResult; 74 | begin 75 | Result := TJSONMapper.Default.FromObject(AValue); 76 | end; 77 | 78 | class function BlockchainInfoResult.FromJSON(const AValue: string): BlockchainInfoResult; 79 | begin 80 | Result := TJSONMapper.Default.FromObject(AValue); 81 | end; 82 | 83 | function BlockchainInfoResult.ToJSONObject: TJSONValue; 84 | begin 85 | Result := TJSONMapper.Default.ToObject(Self); 86 | end; 87 | 88 | function BlockchainInfoResult.ToJSONString: string; 89 | begin 90 | Result := TJSONMapper.Default.ToString(Self); 91 | end; 92 | 93 | end. 94 | -------------------------------------------------------------------------------- /Web3/Bitcoin/JSONRPC.User.Types.MemoryInfo.pas: -------------------------------------------------------------------------------- 1 | // This unit is autogenerated. Do not edit it manually. 2 | // Source: JSON entered in editor 3 | // Date: 3/11/2023 12:18:09 PM 4 | 5 | unit JSONRPC.User.Types.MemoryInfo; 6 | 7 | interface 8 | 9 | {$IF RTLVersion < 36.00} 10 | {$MESSAGE ERROR 'This example requires Delphi 12.0 or later!'} 11 | {$ELSE} 12 | 13 | uses 14 | System.JSON.Serializers, System.JSON; 15 | 16 | type 17 | [JsonSerialize(TJsonMemberSerialization.Fields)] 18 | TMemoryInfo = record 19 | private 20 | [JsonName('used')] 21 | Fused: Integer; 22 | [JsonName('free')] 23 | Ffree: Integer; 24 | [JsonName('total')] 25 | Ftotal: Integer; 26 | [JsonName('locked')] 27 | Flocked: Integer; 28 | [JsonName('chunks_used')] 29 | Fchunks_used: Integer; 30 | [JsonName('chunks_free')] 31 | Fchunks_free: Integer; 32 | public 33 | property used: Integer read Fused write Fused; 34 | property free: Integer read Ffree write Ffree; 35 | property total: Integer read Ftotal write Ftotal; 36 | property locked: Integer read Flocked write Flocked; 37 | property chunks_used: Integer read Fchunks_used write Fchunks_used; 38 | property chunks_free: Integer read Fchunks_free write Fchunks_free; 39 | end; 40 | 41 | [JsonSerialize(TJsonMemberSerialization.Fields)] 42 | MemoryInfoResult = record 43 | private 44 | [JsonName('locked')] 45 | Flocked: TMemoryInfo; 46 | public 47 | class function FromJSON(const AValue: TJSONValue): MemoryInfoResult; overload; static; 48 | class function FromJSON(const AValue: string): MemoryInfoResult; overload; static; 49 | function ToJSONObject: TJSONValue; 50 | function ToJSONString: string; 51 | property locked: TMemoryInfo read Flocked write Flocked; 52 | end; 53 | 54 | // [JsonSerialize(TJsonMemberSerialization.Fields)] 55 | // DataSet = record 56 | // private 57 | // [JsonName('Dataset')] 58 | // FDataset: TArray; 59 | // public 60 | // class function FromJSON(const AValue: TJSONArray): DataSet; overload; static; 61 | // class function FromJSON(const AValue: string): DataSet; overload; static; 62 | // function ToJSONArray: TJSONArray; 63 | // function ToJSONString: string; 64 | // property Dataset: TArray read FDataset write FDataset; 65 | // end; 66 | 67 | {$ENDIF} 68 | 69 | implementation 70 | 71 | {$IF RTLVersion >= 36.00} 72 | class function MemoryInfoResult.FromJSON(const AValue: TJSONValue): MemoryInfoResult; 73 | begin 74 | Result := TJSONMapper.Default.FromObject(AValue); 75 | end; 76 | 77 | class function MemoryInfoResult.FromJSON(const AValue: string): MemoryInfoResult; 78 | begin 79 | Result := TJSONMapper.Default.FromObject(AValue); 80 | end; 81 | 82 | function MemoryInfoResult.ToJSONObject: TJSONValue; 83 | begin 84 | Result := TJSONMapper.Default.ToObject(Self); 85 | end; 86 | 87 | function MemoryInfoResult.ToJSONString: string; 88 | begin 89 | Result := TJSONMapper.Default.ToString(Self); 90 | end; 91 | 92 | //class function DataSet.FromJSON(const AValue: TJSONArray): DataSet; 93 | //begin 94 | // var LArr := TJSONMapper.Default.FromArray(AValue); 95 | // Result.Dataset := LArr; 96 | //end; 97 | // 98 | //class function DataSet.FromJSON(const AValue: string): DataSet; 99 | //begin 100 | // var LArr := TJSONMapper.Default.FromArray(AValue); 101 | // Result.Dataset := LArr; 102 | //end; 103 | // 104 | //function DataSet.ToJSONArray: TJSONArray; 105 | //begin 106 | // Result := TJSONMapper.Default.ToArray(Dataset); 107 | //end; 108 | // 109 | //function DataSet.ToJSONString: string; 110 | //begin 111 | // Result := TJSONMapper.Default.ToString(Dataset); 112 | //end; 113 | 114 | {$ENDIF} 115 | end. 116 | -------------------------------------------------------------------------------- /Web3/Bitcoin/JSONRPC.User.Types.WalletInfo.pas: -------------------------------------------------------------------------------- 1 | // This unit is autogenerated. Do not edit it manually. 2 | // Source: JSON entered in editor 3 | // Date: 3/11/2023 1:37:46 PM 4 | 5 | unit JSONRPC.User.Types.WalletInfo; 6 | 7 | interface 8 | 9 | uses 10 | System.JSON.Serializers, System.JSON; 11 | 12 | type 13 | [JsonSerialize(TJsonMemberSerialization.Fields)] 14 | WalletInfoResult = record 15 | private 16 | [JsonName('walletname')] 17 | Fwalletname: string; 18 | [JsonName('walletversion')] 19 | Fwalletversion: Integer; 20 | [JsonName('format')] 21 | Fformat: string; 22 | [JsonName('balance')] 23 | Fbalance: Double; 24 | [JsonName('unconfirmed_balance')] 25 | Funconfirmed_balance: Double; 26 | [JsonName('immature_balance')] 27 | Fimmature_balance: Double; 28 | [JsonName('txcount')] 29 | Ftxcount: Integer; 30 | [JsonName('keypoololdest')] 31 | Fkeypoololdest: Integer; 32 | [JsonName('keypoolsize')] 33 | Fkeypoolsize: Integer; 34 | [JsonName('unlocked_until')] 35 | Funlocked_until: Integer; 36 | [JsonName('paytxfee')] 37 | Fpaytxfee: Double; 38 | [JsonName('private_keys_enabled')] 39 | Fprivate_keys_enabled: Boolean; 40 | [JsonName('avoid_reuse')] 41 | Favoid_reuse: Boolean; 42 | [JsonName('scanning')] 43 | Fscanning: Boolean; 44 | [JsonName('descriptors')] 45 | Fdescriptors: Boolean; 46 | [JsonName('external_signer')] 47 | Fexternal_signer: Boolean; 48 | public 49 | class function FromJSON(const AValue: TJSONValue): WalletInfoResult; overload; static; 50 | class function FromJSON(const AValue: string): WalletInfoResult; overload; static; 51 | function ToJSONObject: TJSONValue; 52 | function ToJSONString: string; 53 | property walletname: string read Fwalletname write Fwalletname; 54 | property walletversion: Integer read Fwalletversion write Fwalletversion; 55 | property format: string read Fformat write Fformat; 56 | property balance: Double read Fbalance write Fbalance; 57 | property unconfirmed_balance: Double read Funconfirmed_balance write Funconfirmed_balance; 58 | property immature_balance: Double read Fimmature_balance write Fimmature_balance; 59 | property txcount: Integer read Ftxcount write Ftxcount; 60 | property keypoololdest: Integer read Fkeypoololdest write Fkeypoololdest; 61 | property keypoolsize: Integer read Fkeypoolsize write Fkeypoolsize; 62 | property unlocked_until: Integer read Funlocked_until write Funlocked_until; 63 | property paytxfee: Double read Fpaytxfee write Fpaytxfee; 64 | property private_keys_enabled: Boolean read Fprivate_keys_enabled write Fprivate_keys_enabled; 65 | property avoid_reuse: Boolean read Favoid_reuse write Favoid_reuse; 66 | property scanning: Boolean read Fscanning write Fscanning; 67 | property descriptors: Boolean read Fdescriptors write Fdescriptors; 68 | property external_signer: Boolean read Fexternal_signer write Fexternal_signer; 69 | end; 70 | 71 | // [JsonSerialize(TJsonMemberSerialization.Fields)] 72 | // DataSet = record 73 | // private 74 | // [JsonName('Dataset')] 75 | // FDataset: TArray; 76 | // public 77 | // class function FromJSON(const AValue: TJSONArray): DataSet; overload; static; 78 | // class function FromJSON(const AValue: string): DataSet; overload; static; 79 | // function ToJSONArray: TJSONArray; 80 | // function ToJSONString: string; 81 | // property Dataset: TArray read FDataset write FDataset; 82 | // end; 83 | 84 | implementation 85 | 86 | class function WalletInfoResult.FromJSON(const AValue: TJSONValue): WalletInfoResult; 87 | begin 88 | Result := TJSONMapper.Default.FromObject(AValue); 89 | end; 90 | 91 | class function WalletInfoResult.FromJSON(const AValue: string): WalletInfoResult; 92 | begin 93 | Result := TJSONMapper.Default.FromObject(AValue); 94 | end; 95 | 96 | function WalletInfoResult.ToJSONObject: TJSONValue; 97 | begin 98 | Result := TJSONMapper.Default.ToObject(Self); 99 | end; 100 | 101 | function WalletInfoResult.ToJSONString: string; 102 | begin 103 | Result := TJSONMapper.Default.ToString(Self); 104 | end; 105 | 106 | //class function DataSet.FromJSON(const AValue: TJSONArray): DataSet; 107 | //begin 108 | // var LArr := TJSONMapper.Default.FromArray(AValue); 109 | // Result.Dataset := LArr; 110 | //end; 111 | // 112 | //class function DataSet.FromJSON(const AValue: string): DataSet; 113 | //begin 114 | // var LArr := TJSONMapper.Default.FromArray(AValue); 115 | // Result.Dataset := LArr; 116 | //end; 117 | // 118 | //function DataSet.ToJSONArray: TJSONArray; 119 | //begin 120 | // Result := TJSONMapper.Default.ToArray(Dataset); 121 | //end; 122 | // 123 | //function DataSet.ToJSONString: string; 124 | //begin 125 | // Result := TJSONMapper.Default.ToString(Dataset); 126 | //end; 127 | 128 | end. 129 | -------------------------------------------------------------------------------- /Web3/Ethereum/JSONRPC.EthereumClient.dpr: -------------------------------------------------------------------------------- 1 | program JSONRPC.EthereumClient; 2 | 3 | {$APPTYPE CONSOLE} 4 | {$WARN DUPLICATE_CTOR_DTOR OFF} 5 | {$R *.res} 6 | 7 | uses 8 | System.Variants, 9 | JSONRPC.RIO in '..\..\Common\JSONRPC.RIO.pas', 10 | System.Classes, 11 | System.Rtti, 12 | System.JSON, 13 | System.SysUtils, 14 | System.TypInfo, 15 | Winapi.Windows, 16 | System.DateUtils, 17 | System.JSON.Writers, 18 | JSONRPC.Common.Consts in '..\..\Common\JSONRPC.Common.Consts.pas', 19 | JSONRPC.InvokeRegistry in '..\..\Common\JSONRPC.InvokeRegistry.pas', 20 | JSONRPC.User.SomeTypes in '..\..\Common\JSONRPC.User.SomeTypes.pas', 21 | JSONRPC.Common.Types in '..\..\Common\JSONRPC.Common.Types.pas', 22 | JSONRPC.JsonUtils in '..\..\Common\JSONRPC.JsonUtils.pas', 23 | JSONRPC.TransportWrapper.HTTP in '..\..\Common\JSONRPC.TransportWrapper.HTTP.pas', 24 | System.Net.ClientSocket in '..\..\..\NetSocket\Client\System.Net.ClientSocket.pas', 25 | System.Net.Socket.Common in '..\..\..\NetSocket\Common\System.Net.Socket.Common.pas', 26 | JSONRPC.Web3.Common.Types in '..\JSONRPC.Web3.Common.Types.pas', 27 | JSONRPC.Web3.Serializers in '..\JSONRPC.Web3.Serializers.pas', 28 | JSONRPC.Common.RecordHandlers in '..\..\Common\JSONRPC.Common.RecordHandlers.pas', 29 | JSONRPC.Web3.Ethereum.Types in 'JSONRPC.Web3.Ethereum.Types.pas', 30 | JSONRPC.Web3.EthereumAPI in 'JSONRPC.Web3.EthereumAPI.pas', 31 | JSONRPC.Web3.Ethereum.RIO in 'JSONRPC.Web3.Ethereum.RIO.pas', 32 | JSONRPC.Web3.Ethereum.Serializers in 'JSONRPC.Web3.Ethereum.Serializers.pas'; 33 | 34 | procedure AssignSafeCallException(const AJSONRPC: IEthereumJSONRPC); 35 | begin 36 | AssignJSONRPCSafeCallExceptionHandler(AJSONRPC, 37 | function (ExceptObject: TObject; ExceptAddr: Pointer): HResult 38 | var 39 | LExc: EJSONRPCException; 40 | LExcMethod: EJSONRPCMethodException absolute LExc; 41 | begin 42 | if ExceptObject is EJSONRPCException then 43 | begin 44 | LExc := ExceptObject as EJSONRPCException; 45 | WriteLn('Intercepted safecall exception...'); 46 | Write(Format('message: "%s", code: %d', [LExc.Message, LExc.Code])); 47 | if LExc is EJSONRPCMethodException then 48 | begin 49 | Write(Format(', method: "%s"', [LExcMethod.MethodName])); 50 | end; 51 | WriteLn; 52 | WriteLn(StringOfChar('-', 90)); 53 | end else 54 | if ExceptObject is Exception then 55 | begin 56 | var LExcObj := ExceptObject as Exception; 57 | WriteLn('Intercepted safecall exception...'); 58 | WriteLn(Format('message: "%s"', [LExcObj.Message])); 59 | end; 60 | Result := S_OK; // Clear the error otherwise, CheckAutoResult will raise error 61 | end 62 | ); 63 | end; 64 | 65 | procedure Main; 66 | begin 67 | 68 | var EthereumJSONRPC := GetEthereumJSONRPC('https://rpc.ankr.com/eth_goerli'); 69 | AssignSafeCallException(EthereumJSONRPC); 70 | var LEthSyncing := EthereumJSONRPC.eth_syncing; 71 | var LgetBlockByHashResult := EthereumJSONRPC.eth_getBlockByHash('0x7c081ccbb9fa8db1fd68d093389391c72c649e26a77ae7a2c5b92546c8782ad3', false); 72 | 73 | // var Signature := EthereumJSONRPC.eth_sign( 74 | // '0x9b2055d370f73ec7d8a03e965129118dc8f5bf83', 75 | // '0xdeadbeaf' 76 | // ); 77 | // var blockNumber := EthereumJSONRPC.eth_blockNumber; 78 | // var LBytes: TBytes := [$68, $65, $6c, $6c, $6f, $20, $77, $6f, $72, $6c, $64]; 79 | var Lweb3_sha3Hash := EthereumJSONRPC.web3_sha3('0x68656c6c6f20776f726c64'); 80 | var Lweb3_clientVersion := EthereumJSONRPC.web3_clientVersion; 81 | var Lnetversion := EthereumJSONRPC.net_version; 82 | var Lnetlistening := EthereumJSONRPC.net_listening; 83 | // var LnetPeerCount := EthereumJSONRPC.net_peerCount; // doesn't exist 84 | var LProtocolVersion := EthereumJSONRPC.eth_protocolVersion; 85 | var transactionReceipt := EthereumJSONRPC.eth_getTransactionReceipt('0x85d995eba9763907fdf35cd2034144dd9d53ce32cbec21349d4b12823c6860c5'); 86 | 87 | var balance := EthereumJSONRPC.eth_getBalance('0x407d73d8a49eeb85d32cf465507dd71d507100c1', 88 | TBlockNumber.latest); 89 | var tranObj: TransactionObject; 90 | tranObj.from := '0xb60e8dd61c5d32be8058bb8eb970870f07233155'; 91 | tranObj.&to := '0xd46e8dd67c5d32be8058bb8eb970870f07244567'; 92 | tranObj.gas := '0x76c0'; 93 | tranObj.gasPrice := '0x9184e72a000'; 94 | tranObj.value := '0x9184e72a'; 95 | tranObj.data := '0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675'; 96 | var tranObjHash := EthereumJSONRPC.eth_sendTransaction(tranObj); 97 | EthereumJSONRPC := nil; 98 | end; 99 | 100 | begin 101 | ReportMemoryLeaksOnShutdown := True; 102 | try 103 | Main; 104 | finally 105 | Write('Press enter to terminate...'); 106 | ReadLn; 107 | end; 108 | end. 109 | -------------------------------------------------------------------------------- /Web3/Ethereum/JSONRPC.EthereumClient.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuacw/JSONRPC_Framework/9463b711d858b7fb91051146b757951923aa1441/Web3/Ethereum/JSONRPC.EthereumClient.res -------------------------------------------------------------------------------- /Web3/Ethereum/JSONRPC.Web3.Ethereum.Converters.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.Web3.Ethereum.Converters; 2 | 3 | interface 4 | 5 | uses 6 | JSONRPC.Common.Converters, System.TypInfo, System.JSON.Readers, 7 | System.Rtti, System.JSON.Writers, System.JSON.Serializers; 8 | 9 | type 10 | (* 11 | 12 | Response when not syncing (fully synced): 13 | false 14 | 15 | Response when syncing: 16 | { 17 | "startingBlock": "0x1234", // Starting block of the sync 18 | "currentBlock": "0x5678", // Current block processed by the node 19 | "highestBlock": "0x9abc" // Latest block in the blockchain 20 | } 21 | 22 | *) 23 | TJSONFalseBlockInfoConverter = class(TBaseJsonConverter) 24 | public 25 | function CanConvert(ATypeInfo: PTypeInfo): Boolean; override; 26 | 27 | function ReadJson(const AReader: TJsonReader; ATypeInf: PTypeInfo; 28 | const AExistingValue: TValue; const ASerializer: TJsonSerializer): TValue; override; 29 | 30 | procedure WriteJson(const AWriter: TJsonWriter; const AValue: TValue; 31 | const ASerializer: TJsonSerializer); override; 32 | end; 33 | 34 | implementation 35 | 36 | uses 37 | JSONRPC.Web3.EthereumAPI, System.JSON.Types, System.SysUtils; 38 | 39 | { TJSONFalseBlockInfoConverter } 40 | 41 | function TJSONFalseBlockInfoConverter.CanConvert(ATypeInfo: PTypeInfo): Boolean; 42 | begin 43 | Result := ATypeInfo = TypeInfo(TJSONFalseBlockInfo); 44 | end; 45 | 46 | function TJSONFalseBlockInfoConverter.ReadJson(const AReader: TJsonReader; 47 | ATypeInf: PTypeInfo; const AExistingValue: TValue; 48 | const ASerializer: TJsonSerializer): TValue; 49 | var 50 | LEmpty: TJSONFalseBlockInfo; 51 | LTokenType: TJsonToken; 52 | begin 53 | LTokenType := AReader.TokenType; 54 | case LTokenType of 55 | TJsonToken.Boolean: begin 56 | // Result := TValue.From(LEmpty); 57 | end; 58 | TJsonToken.StartObject: begin 59 | var LObjTokenType: Boolean; 60 | repeat 61 | LObjTokenType := AReader.Read; 62 | LTokenType := AReader.TokenType; 63 | if (LTokenType = TJsonToken.EndObject) or (not LObjTokenType) then 64 | Break; 65 | var LPropertyName: string := AReader.Value.AsString; 66 | AReader.Read; 67 | var LValue: string := AReader.Value.AsString; 68 | var LTempValue: UInt64 := 0; TryStrToUInt64(LValue, LTempValue); 69 | if SameText(LPropertyName, 'startingBlock') then 70 | LEmpty.startingBlock := LTempValue else 71 | if SameText(LPropertyName, 'currentBlock') then 72 | LEmpty.currentBlock := LTempValue else 73 | if SameText(LPropertyName, 'highestBlock') then 74 | LEmpty.highestBlock := LTempValue; 75 | until False; 76 | end; 77 | end; 78 | Result := TValue.From(LEmpty); 79 | end; 80 | 81 | procedure TJSONFalseBlockInfoConverter.WriteJson(const AWriter: TJsonWriter; 82 | const AValue: TValue; const ASerializer: TJsonSerializer); 83 | begin 84 | 85 | end; 86 | 87 | end. 88 | -------------------------------------------------------------------------------- /Web3/Ethereum/JSONRPC.Web3.Ethereum.RIO.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.Web3.Ethereum.RIO; 2 | 3 | interface 4 | 5 | uses 6 | JSONRPC.RIO, System.TypInfo, System.Classes, System.JSON, System.Rtti, 7 | JSONRPC.Client.JSONRPCHTTPWrapper, System.SysUtils; 8 | 9 | type 10 | TWeb3EthereumJSONRPCClient = class(TJSONRPCHTTPWrapper) 11 | protected 12 | FOnAfterDispatch: TProc; 13 | procedure DoAfterDispatch; override; 14 | function SerializeRecord(const [Ref] VRecord; ATypeInfo: PTypeInfo): string; override; 15 | procedure DeserializeJSON(const AJsonValue: TJSONValue; ATypeInfo: PTypeInfo; 16 | var VRestoredRecord); overload; override; 17 | procedure DeserializeJSON(const AJsonValue: TJSONValue; ATypeInfo: PTypeInfo; 18 | var VValue: TValue); overload; override; 19 | public 20 | constructor Create(AOwner: TComponent); override; 21 | property OnAfterDispatch: TProc read FOnAfterDispatch write FOnAfterDispatch; 22 | end; 23 | 24 | implementation 25 | 26 | uses 27 | JSONRPC.JsonUtils, JSONRPC.Common.Types, 28 | JSONRPC.Web3.Common.Types, System.JSON.Readers, System.JSON.Serializers, 29 | JSONRPC.Web3.Ethereum.Serializers; 30 | 31 | { TWeb3EthereumJSONRPCClient } 32 | 33 | constructor TWeb3EthereumJSONRPCClient.Create(AOwner: TComponent); 34 | begin 35 | inherited; 36 | FPassByPosOrName := tppByPos; 37 | end; 38 | 39 | procedure TWeb3EthereumJSONRPCClient.DeserializeJSON(const AJsonValue: TJSONValue; 40 | ATypeInfo: PTypeInfo; var VRestoredRecord); 41 | var 42 | LValue: TValue; 43 | {$IF DEFINED(DEBUG)} 44 | LClassName: string; 45 | {$ENDIF} 46 | begin 47 | {$IF DEFINED(DEBUG)} 48 | LClassName := AJsonValue.ClassName; 49 | {$ENDIF} 50 | if AJsonValue is TJSONNull then 51 | begin 52 | // How to initialize a null record? 53 | InvokeRecordInitializer(@VRestoredRecord, ATypeInfo); 54 | end else 55 | begin 56 | DeserializeJSON(AJsonValue, ATypeInfo, LValue); 57 | ValueToObj(LValue, ATypeInfo, VRestoredRecord); 58 | end; 59 | end; 60 | 61 | procedure TWeb3EthereumJSONRPCClient.DeserializeJSON(const AJsonValue: TJSONValue; 62 | ATypeInfo: PTypeInfo; var VValue: TValue); 63 | var 64 | LObjReader: TJsonReader; 65 | {$IF DEFINED(UseRTL35) OR (RTLVersion < 36.0)} 66 | LSerializer: TJsonSerializerHelper; 67 | {$ELSE } 68 | LSerializer: TJsonSerializer; 69 | {$ENDIF} 70 | begin 71 | if not Assigned(AJsonValue) then 72 | begin 73 | Exit; 74 | end; 75 | LObjReader := TJsonObjectReader.Create(AJsonValue); 76 | {$IF DEFINED(UseRTL35) OR (RTLVersion < 36.0)} 77 | LSerializer := TJsonSerializerHelper.Create; 78 | {$ELSEIF RTLVersion >= 36.0 } 79 | LSerializer := TWeb3EthereumJsonSerializer.Create; 80 | {$ENDIF} 81 | try 82 | {$IF DEFINED(UseRTL35) OR (RTLVersion < 36.0)} 83 | VValue := LSerializer.InternalDeserialize(LObjReader, ATypeInfo); 84 | {$ELSEIF RTLVersion >= 36.0 } 85 | VValue := LSerializer.Deserialize(LObjReader, ATypeInfo); 86 | {$ENDIF} 87 | finally 88 | LSerializer.Free; 89 | LObjReader.Free; 90 | end; 91 | end; 92 | 93 | procedure TWeb3EthereumJSONRPCClient.DoAfterDispatch; 94 | begin 95 | if Assigned(FOnAfterDispatch) then 96 | FOnAfterDispatch; 97 | end; 98 | 99 | function TWeb3EthereumJSONRPCClient.SerializeRecord(const [ref] VRecord; 100 | ATypeInfo: PTypeInfo): string; 101 | var 102 | LCopy: string; 103 | begin 104 | if ATypeInfo = TypeInfo(Web3Address) then 105 | begin 106 | LCopy := PString(VRecord)^; 107 | UniqueString(LCopy); 108 | Result := LCopy; 109 | end else 110 | begin 111 | Result := inherited; 112 | end; 113 | end; 114 | 115 | end. 116 | -------------------------------------------------------------------------------- /Web3/Ethereum/JSONRPC.Web3.Ethereum.Serializers.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.Web3.Ethereum.Serializers; 2 | 3 | interface 4 | 5 | uses 6 | System.JSON.Serializers; 7 | 8 | type 9 | 10 | TWeb3EthereumJsonSerializer = class(TJsonSerializer) 11 | end; 12 | 13 | implementation 14 | 15 | end. 16 | -------------------------------------------------------------------------------- /Web3/Ethereum/JSONRPC.Web3.Ethereum.Types.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.Web3.Ethereum.Types; 2 | 3 | interface 4 | 5 | uses 6 | System.SysUtils, System.JSON.Serializers, System.TypInfo, System.JSON.Readers, 7 | System.JSON.Writers, System.Rtti, Velthuis.BigIntegers; 8 | 9 | type 10 | 11 | {$SCOPEDENUMS ON} 12 | TBlockNumber = (earliest, latest, safe, finalized, pending); 13 | 14 | Web3Address = BigInteger; 15 | Hash = string; 16 | NonceType = string; 17 | HexNumber = string; 18 | StrHexNumber = record 19 | private 20 | FValue: Integer; 21 | public 22 | class operator Implicit(const Src: StrHexNumber): Integer; 23 | end; 24 | BloomFilter = string; 25 | log = string; 26 | 27 | TEthSyncingConverter = class(TJsonConverter) 28 | public 29 | function CanConvert(ATypeInf: PTypeInfo): Boolean; override; 30 | function ReadJson(const AReader: TJsonReader; ATypeInf: PTypeInfo; 31 | const AExistingValue: TValue; const ASerializer: TJsonSerializer): TValue; override; 32 | procedure WriteJson(const AWriter: TJsonWriter; const AValue: TValue; 33 | const ASerializer: TJsonSerializer); override; 34 | end; 35 | 36 | TransactionReceiptObjectConverter = class(TJsonConverter) 37 | end; 38 | 39 | [JsonConverter(TEthSyncingConverter)] 40 | TEthSyncing = record 41 | Syncing: Boolean; 42 | startingBlock: HexNumber; currentBlock: HexNumber; highestBlock: HexNumber; 43 | end align 16; 44 | 45 | TransactionObject = record 46 | from: Web3Address; 47 | &to: Web3Address; 48 | gas: HexNumber; 49 | gasPrice: HexNumber; 50 | value: HexNumber; 51 | data: Hash; 52 | nonce: HexNumber; 53 | &type: HexNumber; 54 | end; 55 | PTransactionObject = ^TransactionObject; 56 | 57 | [JsonConverter(TransactionReceiptObjectConverter)] 58 | TransactionReceiptObject = record 59 | transactionHash: Hash; 60 | transactionIndex: HexNumber; 61 | blockHash: Hash; 62 | blockNumber: HexNumber; 63 | from: Web3Address; 64 | &to: Web3Address; 65 | cumulativeGasUsed: HexNumber; 66 | effectiveGasPrice: HexNumber; 67 | gasUsed: HexNumber; 68 | contractAddress: Web3Address; 69 | logs: TArray; 70 | logsBloom: BloomFilter; 71 | end align 16; 72 | 73 | Withdrawal = record 74 | index: HexNumber; 75 | validatorIndex: HexNumber; 76 | address: Web3Address; 77 | amount: HexNumber; 78 | end align 16; 79 | 80 | getBlockByHashReturn = record 81 | baseFeePerGas: HexNumber; 82 | mixHash: HexNumber; 83 | number: HexNumber; 84 | hash: Hash; 85 | parentHash: Hash; 86 | nonce: NonceType; 87 | sha3Uncles: Hash; 88 | logsBloom: BloomFilter; 89 | transactionsRoot: HexNumber; 90 | stateRoot: HexNumber; 91 | receiptsRoot: HexNumber; 92 | miner: Web3Address; 93 | difficulty: HexNumber; 94 | totalDifficulty: HexNumber; 95 | extraData: HexNumber; 96 | size: HexNumber; 97 | gasLimit: HexNumber; 98 | gasUsed: HexNumber; 99 | timestamp: HexNumber; 100 | transactions: TArray; 101 | uncles: TArray; 102 | withdrawals: TArray; 103 | withdrawalsRoot: HexNumber; 104 | end align 16; 105 | 106 | implementation 107 | 108 | uses 109 | System.JSON, JSONRPC.Common.Types, JSONRPC.Common.RecordHandlers, 110 | System.JSON.Types, JSONRPC.JsonUtils, JSONRPC.Common.Consts; 111 | 112 | { TEthSyncingConverter } 113 | 114 | function TEthSyncingConverter.CanConvert(ATypeInf: PTypeInfo): Boolean; 115 | begin 116 | Result := True; 117 | end; 118 | 119 | function TEthSyncingConverter.ReadJson(const AReader: TJsonReader; 120 | ATypeInf: PTypeInfo; const AExistingValue: TValue; 121 | const ASerializer: TJsonSerializer): TValue; 122 | var 123 | // LJSONText: string; 124 | LEthSyncing: TEthSyncing; 125 | begin 126 | LEthSyncing := Default(TEthSyncing); 127 | var LTokenType := AReader.TokenType; 128 | repeat 129 | AReader.Read; 130 | var LValue := AReader.Value; 131 | case LTokenType of 132 | TJsonToken.Boolean: LEthSyncing.Syncing := LValue.AsBoolean; 133 | end; 134 | until AReader.CurrentState = TJsonReader.TState.Finished; 135 | Result := TValue.From(LEthSyncing); 136 | end; 137 | 138 | procedure TEthSyncingConverter.WriteJson(const AWriter: TJsonWriter; 139 | const AValue: TValue; const ASerializer: TJsonSerializer); 140 | begin 141 | end; 142 | 143 | { StrHexNumber } 144 | 145 | class operator StrHexNumber.Implicit(const Src: StrHexNumber): Integer; 146 | begin 147 | Result := Src.FValue; 148 | end; 149 | 150 | initialization 151 | RegisterRecordHandler(TypeInfo(BigInteger), 152 | procedure( 153 | const APassParamByPosOrName: TPassParamByPosOrName; 154 | ATypeInfo: PTypeInfo; 155 | const AParamName: string; 156 | const AParamValuePtr: Pointer; 157 | const AParamsObj: TJSONObject; 158 | const AParamsArray: TJSONArray 159 | ) 160 | // NativeToJSON 161 | var 162 | LJSON: TJSONString; 163 | begin 164 | BigInteger.Hex; 165 | LJSON := TJSONString.Create('0x'+BigInteger(AParamValuePtr^).ToString(16)); 166 | case APassParamByPosOrName of 167 | tppByName: AParamsObj.AddPair(AParamName, LJSON); 168 | tppByPos: AParamsArray.AddElement(LJSON); 169 | end; 170 | end, 171 | procedure(const AJSONResponseObj: TJSONValue; const APathName: string; AResultP: Pointer) 172 | // JSONToNative 173 | var 174 | LDecimalPlaces: Integer; 175 | begin 176 | var LResultValue: string; 177 | AJSONResponseObj.TryGetValue(APathName, LResultValue); 178 | if LResultValue.StartsWith('0x', True) then 179 | begin 180 | LResultValue := Copy(LResultValue, Low(LResultValue) + 2); 181 | LDecimalPlaces := 16; 182 | end else 183 | begin 184 | LDecimalPlaces := 10; 185 | end; 186 | BigInteger.TryParse(LResultValue, LDecimalPlaces, PBigInteger(AResultP)^); 187 | end, 188 | procedure(const AParamName: string; const AValue: TValue; 189 | ATypeInfo: PTypeInfo; const AJSONObject: TJSONObject) 190 | // TValueToJSON 191 | var 192 | LBigInteger: BigInteger; 193 | LJSON: string; 194 | begin 195 | // LResult is a TValue from BigDecimal 196 | ValueToObj(AValue, ATypeInfo, LBigInteger); 197 | LJSON := LBigInteger.ToString; 198 | AJSONObject.AddPair(SRESULT, LJSON); 199 | end, 200 | function(const AJSON: string): TValue 201 | // JSONToTValue 202 | var 203 | LParamValue: string; 204 | LBigInteger: BigInteger; 205 | begin 206 | LParamValue := AJSON; 207 | if LParamValue.StartsWith('0x', True) then 208 | LParamValue := Copy(LParamValue, Low(LParamValue) + 2); 209 | BigInteger.TryParse(LParamValue, 16, LBigInteger); 210 | Result := TValue.From(LBigInteger); 211 | end 212 | ); 213 | end. 214 | -------------------------------------------------------------------------------- /Web3/Ethereum/JSONRPC.Web3.EthereumAPI.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.Web3.EthereumAPI; 2 | 3 | interface 4 | 5 | uses 6 | JSONRPC.RIO, JSONRPC.Web3.Common.Types, JSONRPC.Common.Types, 7 | JSONRPC.Web3.Ethereum.Types, System.SysUtils, System.JSON, Velthuis.BigIntegers, 8 | JSONRPC.Web3.Ethereum.Converters, System.JSON.Serializers; 9 | 10 | type 11 | 12 | HexBytes = BigInteger; 13 | 14 | [JsonConverter(TJSONFalseBlockInfoConverter)] 15 | TJSONFalseBlockInfo = record 16 | public 17 | startingBlock, currentBlock, highestBlock: UInt64; // encoded as hex 18 | class operator Assign(var Dest: TJSONFalseBlockInfo; const [ref] Src: TJSONFalseBlockInfo); 19 | class operator Implicit(const Value: TJSONFalseBlockInfo): Boolean; 20 | class operator Initialize(out Dest: TJSONFalseBlockInfo); 21 | end; 22 | 23 | IEthereumJSONRPC = interface(IJSONRPCMethods) 24 | ['{BC41AE33-10B1-4969-BA60-D2581EA21613}'] 25 | function web3_clientVersion: string; 26 | function web3_sha3(const Data: HexBytes): Hash; overload; 27 | function net_version: HexNumber; 28 | function net_listening: Boolean; 29 | function net_peerCount: HexNumber; deprecated 'This might not exist!'; 30 | function eth_protocolVersion: HexNumber; 31 | function eth_syncing: TJSONFalseBlockInfo; 32 | function eth_coinbase: HexNumber; 33 | function eth_chainId: HexNumber; 34 | function eth_mining: Boolean; 35 | function eth_hashrate: HexNumber; 36 | function eth_gasPrice: HexNumber; 37 | function eth_accounts: TArray; 38 | function eth_blockNumber: HexNumber; 39 | 40 | function eth_getBalance(const AAddress: Web3Address; const ABlockNumber: HexNumber): HexNumber; overload; 41 | function eth_getBalance(const AAddress: Web3Address; const ABlockNumber: TBlockNumber): HexNumber; overload; 42 | function eth_getStorageAt(const AAddress: Web3Address; const Position: HexNumber; 43 | const AQuantity: HexNumber): HexNumber; overload; 44 | function eth_getStorageAt(const AAddress: Web3Address; const Position: HexNumber; 45 | const AQuantity: TBlockNumber): HexNumber; overload; 46 | function eth_getTransactionCount(const AAddress: Web3Address; 47 | const AQuantity: HexNumber): HexNumber; overload; 48 | function eth_getTransactionCount(const AAddress: Web3Address; 49 | const AQuantity: TBlockNumber): HexNumber; overload; 50 | function eth_getBlockTransactionCountByHash(const AHash: Hash): HexNumber; 51 | function eth_getBlockTransactionCountByNumber(const ABlockNumber: HexNumber): HexNumber; overload; 52 | function eth_getBlockTransactionCountByNumber(const ABlockNumber: TBlockNumber): HexNumber; overload; 53 | function eth_getUncleCountByBlockHash(const AHash: Hash): HexNumber; 54 | function eth_getUncleCountByBlockNumber(const ABlockNumber: HexNumber): HexNumber; overload; 55 | function eth_getUncleCountByBlockNumber(const ABlockNumber: TBlockNumber): HexNumber; overload; 56 | function eth_getCode(const AAddress: Web3Address; const ABlockNumber: HexNumber): HexNumber; overload; 57 | function eth_getCode(const AAddress: Web3Address; const ABlockNumber: TBlockNumber): HexNumber; overload; 58 | function eth_sign(const AAddress: Web3Address; const Data: string): HexNumber; 59 | // TODO : Complete eth_signTransaction 60 | // function eth_signTransaction( 61 | function eth_sendTransaction(const ATranObj: TransactionObject): Hash; safecall; 62 | function eth_sendRawTransaction(const ASignedTransactionData: HexNumber): Hash; 63 | function eth_call(const ATranObj: TransactionObject): HexNumber; 64 | function eth_estimateGas: HexNumber; 65 | function eth_getBlockByHash(const AHash: Hash; 66 | ReturnFullTransactions: Boolean): getBlockByHashReturn; 67 | function eth_getTransactionReceipt(const AAddress: Web3Address): TransactionReceiptObject; 68 | 69 | end; 70 | 71 | implementation 72 | 73 | uses 74 | JSONRPC.InvokeRegistry; 75 | 76 | { TJSONFalseBlockInfo } 77 | 78 | class operator TJSONFalseBlockInfo.Assign( 79 | var Dest: TJSONFalseBlockInfo; 80 | const [ref] Src: TJSONFalseBlockInfo); 81 | begin 82 | Dest.currentBlock := Src.currentBlock; 83 | Dest.highestBlock := Src.highestBlock; 84 | Dest.startingBlock := Src.highestBlock; 85 | end; 86 | 87 | class operator TJSONFalseBlockInfo.Implicit( 88 | const Value: TJSONFalseBlockInfo): Boolean; 89 | begin 90 | if (Value.currentBlock = 0) and (Value.highestBlock = 0) and 91 | (Value.startingBlock = 0) then 92 | Result := False else 93 | Result := True; 94 | end; 95 | 96 | class operator TJSONFalseBlockInfo.Initialize(out Dest: TJSONFalseBlockInfo); 97 | begin 98 | Dest.currentBlock := 0; 99 | Dest.highestBlock := 0; 100 | Dest.startingBlock := 0; 101 | end; 102 | 103 | initialization 104 | InvokableRegistry.RegisterInterface(TypeInfo(IEthereumJSONRPC)); 105 | end. 106 | -------------------------------------------------------------------------------- /Web3/JSONRPC.Web3.Clients.groupproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {837C2E73-12A8-4C50-BC10-552790AA3BE6} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | Default.Personality.12 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /Web3/JSONRPC.Web3.Common.Types.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.Web3.Common.Types; 2 | 3 | interface 4 | 5 | type 6 | 7 | // HexNumber = record 8 | // private 9 | // FValue: string; 10 | // public 11 | // class operator Implicit(const AHexNumber: HexNumber): string; 12 | // class operator Implicit(const ANumber: string): HexNumber; 13 | // 14 | // class operator Implicit(const AHexNumber: HexNumber): Integer; 15 | // class operator Implicit(const ANumber: Integer): HexNumber; 16 | // 17 | // class operator Implicit(const ANumber: Int64): HexNumber; 18 | // class operator Implicit(const AHexNumber: HexNumber): Int64; 19 | // 20 | // class operator Implicit(const ANumber: UInt64): HexNumber; 21 | // class operator Implicit(const AHexNumber: HexNumber): UInt64; 22 | // end; 23 | 24 | HexNumber = string; 25 | 26 | // Web3Address = record 27 | // private 28 | // FValue: string; 29 | // public 30 | // class operator Implicit(const AAddress: string): Web3Address; 31 | // class operator Implicit(const AWeb3Address: Web3Address): string; 32 | // end; 33 | 34 | Web3Address = string; 35 | Hash = string; 36 | NonceType = string; 37 | 38 | implementation 39 | 40 | uses 41 | System.SysUtils; 42 | 43 | { HexNumber } 44 | 45 | //class operator HexNumber.Implicit(const AHexNumber: HexNumber): string; 46 | //begin 47 | // Result := AHexNumber.FValue; 48 | //end; 49 | // 50 | //class operator HexNumber.Implicit(const ANumber: string): HexNumber; 51 | //begin 52 | // Result.FValue := ANumber; 53 | //end; 54 | // 55 | //class operator HexNumber.Implicit(const ANumber: UInt64): HexNumber; 56 | //begin 57 | // Result.FValue := Format('0x%x', [ANumber]); 58 | //end; 59 | // 60 | //class operator HexNumber.Implicit(const ANumber: Integer): HexNumber; 61 | //begin 62 | // Result.FValue := Format('0x%x', [ANumber]); 63 | //end; 64 | // 65 | //class operator HexNumber.Implicit(const ANumber: Int64): HexNumber; 66 | //begin 67 | // Result.FValue := Format('0x%x', [ANumber]); 68 | //end; 69 | // 70 | //class operator HexNumber.Implicit(const AHexNumber: HexNumber): Integer; 71 | //begin 72 | // Result := StrToInt(AHexNumber.FValue); 73 | //end; 74 | // 75 | //class operator HexNumber.Implicit(const AHexNumber: HexNumber): Int64; 76 | //begin 77 | // Result := StrToInt64(AHexNumber.FValue); 78 | //end; 79 | // 80 | //class operator HexNumber.Implicit(const AHexNumber: HexNumber): UInt64; 81 | //begin 82 | // Result := StrToUInt64(AHexNumber.FValue); 83 | //end; 84 | 85 | { Web3Address } 86 | 87 | //class operator Web3Address.Implicit(const AWeb3Address: Web3Address): string; 88 | //begin 89 | // Result := AWeb3Address.FValue; 90 | //end; 91 | // 92 | //class operator Web3Address.Implicit(const AAddress: string): Web3Address; 93 | //begin 94 | // Result.FValue := AAddress; 95 | //end; 96 | 97 | end. 98 | -------------------------------------------------------------------------------- /Web3/JSONRPC.Web3.Serializers.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.Web3.Serializers; 2 | 3 | interface 4 | 5 | uses 6 | System.JSON.Serializers, System.JSON.Readers, System.TypInfo, System.Rtti; 7 | 8 | type 9 | TWeb3JsonSerializer = class(TJsonSerializer) 10 | public 11 | constructor Create; reintroduce; 12 | function InternalDeserialize(const AReader: TJsonReader; ATypeInfo: PTypeInfo): TValue; override; 13 | end; 14 | 15 | TWeb3JsonSerializerHelper = class helper for TWeb3JsonSerializer 16 | end; 17 | 18 | implementation 19 | 20 | uses 21 | JSONRPC.Web3.Common.Types, JSONRPC.Web3.Ethereum.Types, System.JSON.Writers, 22 | System.JSON.Types; 23 | 24 | type 25 | 26 | TWeb3ContractResolver = class(TJsonDefaultContractResolver) 27 | protected 28 | procedure InitializeContract(const AJsonContract: TJsonContract; const ARttiType: TRttiType); override; 29 | function CreateContract(ATypeInfo: PTypeInfo): TJsonContract; override; 30 | end; 31 | 32 | TTransactionReceiptObjectConverter = class(TJsonConverter) 33 | public 34 | function CanConvert(ATypeInfo: PTypeInfo): Boolean; override; 35 | function ReadJson(const AReader: TJsonReader; ATypeInfo: PTypeInfo; 36 | const AExistingValue: TValue; const ASerializer: TJsonSerializer): TValue; override; 37 | procedure WriteJson(const AWriter: TJsonWriter; const AValue: TValue; 38 | const ASerializer: TJsonSerializer); override; 39 | end; 40 | 41 | THexNumberJsonContract = class(TJsonPrimitiveContract) 42 | public 43 | constructor Create(ATypeInfo: PTypeInfo); 44 | end; 45 | 46 | TWeb3AddressJsonContract = class(TJsonPrimitiveContract) 47 | public 48 | constructor Create(ATypeInfo: PTypeInfo); 49 | end; 50 | 51 | { TWeb3JsonSerializer } 52 | 53 | constructor TWeb3JsonSerializer.Create; 54 | begin 55 | inherited Create; 56 | ContractResolver := TWeb3ContractResolver.Create; 57 | end; 58 | 59 | function TWeb3JsonSerializer.InternalDeserialize(const AReader: TJsonReader; 60 | ATypeInfo: PTypeInfo): TValue; 61 | //var 62 | // LSerializerReader: TJsonSerializerReader; 63 | begin 64 | // LSerializerReader := TJsonSerializerReader.Create(Self); 65 | // try 66 | // Result := LSerializerReader.DeSerialize(AReader, ATypeInf); 67 | // finally 68 | // LSerializerReader.Free; 69 | // end; 70 | inherited; 71 | end; 72 | 73 | { TWeb3ContractResolver } 74 | 75 | function TWeb3ContractResolver.CreateContract( 76 | ATypeInfo: PTypeInfo): TJsonContract; 77 | begin 78 | if ATypeInfo = TypeInfo(HexNumber) then 79 | Result := THexNumberJsonContract.Create(ATypeInfo) else 80 | if ATypeInfo = TypeInfo(Web3Address) then 81 | Result := TWeb3AddressJsonContract.Create(ATypeInfo) else 82 | Result := inherited; 83 | end; 84 | 85 | procedure TWeb3ContractResolver.InitializeContract( 86 | const AJsonContract: TJsonContract; const ARttiType: TRttiType); 87 | begin 88 | inherited; 89 | end; 90 | 91 | { THexNumberJsonContract } 92 | 93 | constructor THexNumberJsonContract.Create(ATypeInfo: PTypeInfo); 94 | begin 95 | inherited Create(ATypeInfo, TJsonPrimitiveKind.String); 96 | end; 97 | 98 | { TWeb3AddressJsonContract } 99 | 100 | constructor TWeb3AddressJsonContract.Create(ATypeInfo: PTypeInfo); 101 | begin 102 | inherited Create(ATypeInfo, TJsonPrimitiveKind.String); 103 | end; 104 | 105 | { TTransactionReceiptObjectConverter } 106 | 107 | function TTransactionReceiptObjectConverter.CanConvert( 108 | ATypeInfo: PTypeInfo): Boolean; 109 | begin 110 | Result := ATypeInfo = TypeInfo(TransactionReceiptObject); 111 | end; 112 | 113 | function TTransactionReceiptObjectConverter.ReadJson(const AReader: TJsonReader; 114 | ATypeInfo: PTypeInfo; const AExistingValue: TValue; 115 | const ASerializer: TJsonSerializer): TValue; 116 | begin 117 | if AReader.TokenType = TJsonToken.Null then 118 | ; 119 | end; 120 | 121 | procedure TTransactionReceiptObjectConverter.WriteJson( 122 | const AWriter: TJsonWriter; const AValue: TValue; 123 | const ASerializer: TJsonSerializer); 124 | begin 125 | inherited; 126 | end; 127 | 128 | end. -------------------------------------------------------------------------------- /Web3/Polkadot/JSONRPC.PolkadotClient.dpr: -------------------------------------------------------------------------------- 1 | program JSONRPC.PolkadotClient; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | {$R *.res} 6 | 7 | uses 8 | System.SysUtils, System.Math, 9 | Vcl.Clipbrd, Velthuis.BigIntegers, 10 | JSONRPC.RIO in '..\..\Common\JSONRPC.RIO.pas', 11 | JSONRPC.Common.Types in '..\..\Common\JSONRPC.Common.Types.pas', 12 | JSONRPC.InvokeRegistry in '..\..\Common\JSONRPC.InvokeRegistry.pas', 13 | JSONRPC.Common.Consts in '..\..\Common\JSONRPC.Common.Consts.pas', 14 | JSONRPC.JsonUtils in '..\..\Common\JSONRPC.JsonUtils.pas', 15 | JSONRPC.Common.RecordHandlers in '..\..\Common\JSONRPC.Common.RecordHandlers.pas', 16 | JSONRPC.Web3.Common.Types in '..\JSONRPC.Web3.Common.Types.pas', 17 | JSONRPC.TransportWrapper.HTTP in '..\..\Common\JSONRPC.TransportWrapper.HTTP.pas', 18 | JSONRPC.Web3.Polkadot.Types in 'JSONRPC.Web3.Polkadot.Types.pas', 19 | JSONRPC.Web3.PolkadotAPI in 'JSONRPC.Web3.PolkadotAPI.pas'; 20 | 21 | const 22 | Base58Alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; 23 | 24 | function Base58Encode(const input: string): string; experimental 25 | var 26 | dividend, remainder: UInt64; 27 | quotient: Integer; 28 | i: Integer; 29 | res: string; 30 | begin 31 | dividend := StrToInt64Def(input, 0); 32 | res := ''; 33 | while dividend > 0 do 34 | begin 35 | 36 | quotient := dividend div 58; 37 | remainder := dividend mod 58; 38 | res := Base58Alphabet[remainder + 1] + res; 39 | dividend := quotient; 40 | end; 41 | Result := res; 42 | end; 43 | 44 | function Base58Decode(const input: string): string; experimental 45 | var 46 | i, j: Integer; 47 | c: Char; 48 | res: BigInteger; 49 | begin 50 | res := 0; 51 | for i := 1 to Length(input) do 52 | begin 53 | c := input[i]; 54 | j := Pos(c, Base58Alphabet) - 1; 55 | if j = -1 then 56 | Exit(''); 57 | res := res * 58 + UInt64(j); 58 | end; 59 | Result := res.ToString; 60 | end; 61 | 62 | function GetPolkadotClient: IPolkadotJSONRPC; 63 | begin 64 | Result := GetPolkadotJSONRPC('https://apps-rpc.polkadot.io/', 65 | procedure(const AJSONRPCRequest: string) 66 | begin 67 | WriteLn('--- Outgoing JSON request ---'); 68 | WriteLn(AJSONRPCRequest); 69 | end, 70 | procedure(const AJSONRPCResponse: string) 71 | begin 72 | WriteLn('--- Incoming JSON response ---'); 73 | Clipboard.AsText := AJSONRPCResponse; 74 | WriteLn(AJSONRPCResponse); 75 | WriteLn; 76 | end 77 | ); 78 | AssignJSONRPCSafeCallExceptionHandler(Result, 79 | function (ExceptObject: TObject; ExceptAddr: Pointer): HResult 80 | var 81 | LExc: EJSONRPCException; 82 | LExcMethod: EJSONRPCMethodException absolute LExc; 83 | begin 84 | if ExceptObject is EJSONRPCException then 85 | begin 86 | LExc := ExceptObject as EJSONRPCException; 87 | WriteLn('Intercepted safecall exception...'); 88 | Write(Format('message: "%s", code: %d', [LExc.Message, LExc.Code])); 89 | if LExc is EJSONRPCMethodException then 90 | begin 91 | Write(Format(', method: "%s"', [LExcMethod.MethodName])); 92 | end; 93 | WriteLn; 94 | WriteLn(StringOfChar('-', 90)); 95 | end else 96 | if ExceptObject is Exception then 97 | begin 98 | var LExcObj := ExceptObject as Exception; 99 | WriteLn('Intercepted safecall exception...'); 100 | WriteLn(Format('message: "%s"', [LExcObj.Message])); 101 | end; 102 | Result := S_OK; // Clear the error otherwise, CheckAutoResult will raise error 103 | end 104 | ); 105 | end; 106 | 107 | procedure TestPolkadotClient; 108 | begin 109 | try 110 | var LPolkadotClient := GetPolkadotClient; 111 | 112 | // https://t.me/substratedevs/10356 113 | var lBlockHash := LPolkadotClient.chain_getBlockHash(0); 114 | var lGetBlockHash := LPolkadotClient.chain_getBlock(lBlockHash); 115 | 116 | var lLocalPeerId := LPolkadotClient.system_localPeerId; 117 | var base58Decoded := Base58Decode(lLocalPeerId); 118 | var LSyncStateGenSpec := LPolkadotClient.sync_state_genSyncSpec; 119 | 120 | var lPendingExtrinsics := LPolkadotClient.author_pendingExtrinsics; 121 | // // var LRemoveExtrinsicResult := LPolkadotClient.author_removeExtrinsic([]); 122 | // 123 | // var LGrandpaRoundState := LPolkadotClient.grandpa_roundState; 124 | var LBlockNumber := LPolkadotClient.chain_getBlock; 125 | var LHeader := LPolkadotClient.chain_getHeader; 126 | LBlockHash := LPolkadotClient.chain_getBlockHash(50, $64, 200); 127 | LBlockHash := LPolkadotClient.chain_getBlockHash(19518865); 128 | var LGrandpaProveFinality := LPolkadotClient.grandpa_proveFinality( 129 | (LBlockNumber.block.header.number-10).AsInteger 130 | ); 131 | 132 | var LMetadata := LPolkadotClient.state_getMetadata; 133 | // var lFinalizedHead := LPolkadotClient.getFinalizedHead; // not available? 134 | 135 | var LAccountNonce := LPolkadotClient.system_accountNextIndex('FJaSzBUAJ1Nwa1u5TbKAFZG5MBtcUouTixdP7hAkmce2SDS'); 136 | var LSystemChain := LPolkadotClient.system_chain; 137 | var LSystemChainType := LPolkadotClient.system_chainType; 138 | var LAddresses := LPolkadotClient.system_localListenAddresses; 139 | var LNodeRoles := LPolkadotClient.system_nodeRoles; 140 | var LSystemProperties := LPolkadotClient.system_properties; 141 | var LSystemHealth := LPolkadotClient.system_health; 142 | Assert(LBlockHash = '0x66722d90a8fec09cb410fed0292b397d5d3cbd1bca376b1fd0c1bb8caee3e6d4'); 143 | WriteLn(LBlockHash.ToString); 144 | 145 | var LMethods := LPolkadotClient.rpc_methods; 146 | var LKey: StorageKey := '0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8'; 147 | var LAt: TBlockHash := '0x841a21ab1aa402aca5185e1b9d72f85e181de28e8f68e279c4f7a25f06e63d23'; 148 | 149 | LBlockHash := LPolkadotClient.state_getStorage(LKey, LAt); 150 | 151 | var LVersion := LPolkadotClient.system_version; 152 | WriteLn(LVersion); 153 | 154 | var lSyncState := LPolkadotClient.system_syncState; 155 | var lReservedPeers := LPolkadotClient.system_reservedPeers; 156 | lLocalPeerId := LPolkadotClient.system_localPeerId; 157 | var lNodeName := LPolkadotClient.system_name; 158 | 159 | var lStateRuntimeVersion := LPolkadotClient.state_getRuntimeVersion; 160 | var LPendingRewards := LPolkadotClient.state_call(NominationPoolsApi_pending_rewards, '0x5626fb92ce5aacc7ac4dd042dd55308832ba8dde38c557b140ae8740948fe76c'); 161 | var LBalance := LPolkadotClient.state_call(NominationPoolsApi_points_to_balance, '0xdc000000b9b48ac2020000000000000000000000'); 162 | var LPoints := LPolkadotClient.state_call(NominationPoolsApi_balance_to_points, '0xdc000000b9b48ac2020000000000000000000000'); 163 | WriteLn; 164 | WriteLn('SUCCESS! There''s no implementation error!'); 165 | except 166 | WriteLn; 167 | WriteLn('Investigate the implementation error!'); 168 | end; 169 | end; 170 | 171 | begin 172 | TestPolkadotClient; 173 | WriteLn; 174 | Write('Press enter to quit.'); 175 | ReadLn; 176 | end. 177 | -------------------------------------------------------------------------------- /Web3/Polkadot/JSONRPC.PolkadotClient.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuacw/JSONRPC_Framework/9463b711d858b7fb91051146b757951923aa1441/Web3/Polkadot/JSONRPC.PolkadotClient.res -------------------------------------------------------------------------------- /Web3/Polkadot/JSONRPC.Web3.Polkadot.Types.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.Web3.Polkadot.Types; 2 | 3 | interface 4 | 5 | uses 6 | Velthuis.BigIntegers, System.Generics.Collections; 7 | 8 | type 9 | TSystemHealth = record 10 | peers: Integer; 11 | isSyncing: Boolean; 12 | shouldHavePeers: Boolean; 13 | end; 14 | 15 | HexBytes = BigInteger; 16 | TBlockHash = BigInteger; 17 | TGetBlockHash = BigInteger; 18 | THash = string; 19 | THex = string; 20 | StorageKey = string; 21 | TAccountNonce = UInt64; 22 | 23 | TMethods = record 24 | methods: TArray; 25 | end; 26 | 27 | // {"startingBlock":19480132,"currentBlock":19523851,"highestBlock":19523851},"id":6} 28 | TSyncState = record 29 | startingBlock: UInt32; 30 | currentBlock: UInt32; 31 | highestBlock: UInt32; 32 | end; 33 | 34 | TSyncStateGenSyncSpecProperties = record 35 | ss58Format: UInt32; 36 | tokenDecimals: UInt32; 37 | tokenSymbol: string; 38 | end; 39 | TSyncStateGenSyncSpecCodeSubstitutes = TDictionary; 40 | TSyncStateGenSyncSpecGenesisRawTop = TDictionary; 41 | TSyncStateGenSyncSpecGenesisRawChildrenDefault = TDictionary; 42 | TSyncStateGenSyncSpecGenesisRaw = record 43 | childrenDefault: TSyncStateGenSyncSpecGenesisRawChildrenDefault; 44 | top: TSyncStateGenSyncSpecGenesisRawTop; 45 | end; 46 | TSyncStateGenSyncSpecGenesis = record 47 | raw: TSyncStateGenSyncSpecGenesisRaw; 48 | end; 49 | TSyncStateGenSyncSpecLightSyncState = record 50 | babeEpochChanges: BigInteger; 51 | babeFinalizedBlockWeight: BigInteger; 52 | finalizedBlockHeader: BigInteger; 53 | grandpaAuthoritySet: BigInteger; 54 | end; 55 | 56 | // [ 57 | // string, // URL to telemetry 58 | // UInt32 // max verbosity level 59 | // ] 60 | telemetryEndpointsElement = TArray; 61 | 62 | // [ 63 | // UInt32, // block number 64 | // Hash // hash 65 | // ] 66 | TForkBlocksElement = TArray; 67 | 68 | TSyncStateGenSyncSpec = record 69 | badBlocks: TArray; 70 | bootNodes: TArray; 71 | chainType: string; 72 | codeSubstitutes: TSyncStateGenSyncSpecCodeSubstitutes; 73 | forkBlocks: TArray< 74 | TForkBlocksElement 75 | >; 76 | genesis: TSyncStateGenSyncSpecGenesis; 77 | id: string; 78 | lightSyncState: TSyncStateGenSyncSpecLightSyncState; 79 | name: string; 80 | properties: TSyncStateGenSyncSpecProperties; 81 | protocolId: string; 82 | telemetryEndpoints: TArray; 83 | end; 84 | 85 | // https://spec.polkadot.network/chap-runtime-api 86 | TStateCallType = ( 87 | NominationPoolsApi_pending_rewards, // args = account id 88 | NominationPoolsApi_points_to_balance, 89 | NominationPoolsApi_balance_to_points 90 | ); 91 | 92 | TSystemProperties = record 93 | ss58Format: Integer; 94 | tokenDecimals: Integer; 95 | tokenSymbol: string; 96 | end; 97 | 98 | // base58 encoded PeerId 99 | TPeerId = string; 100 | 101 | TAPIs = TArray>; 102 | 103 | TRuntimeVersion = record 104 | specName: string; 105 | implName: string; 106 | authoringVersion: Integer; 107 | specVersion: Integer; 108 | implVersion: Integer; 109 | apis: TAPIs; 110 | transactionVersion: Integer; 111 | stateVersion: Integer; 112 | end; 113 | 114 | TAccountId = string; 115 | 116 | TSystemPeerRoles = (NONE, FULL, LIGHT, AUTHORITY); 117 | TSystemPeers = record 118 | PeerId: string; 119 | roles: TSystemPeerRoles; 120 | protocolVersion: UInt32; 121 | bestHash: THex; 122 | bestNumber: UInt64; 123 | end; 124 | 125 | // Not completely defined 126 | TBabeEpochAuthorship = record // unsafe 127 | end; 128 | 129 | TVotes = record 130 | currentWeight: UInt32; 131 | missing: TArray; // address of authority 132 | end; 133 | 134 | TRoundState = record 135 | round: UInt32; 136 | totalWeight: UInt32; 137 | thresholdWeight: UInt32; 138 | prevotes: TVotes; 139 | precommits: TVotes; 140 | end; 141 | 142 | TGrandpaRoundState = record 143 | setId: UInt32; 144 | best: TRoundState; 145 | background: TArray; 146 | end; 147 | 148 | TDigest = record 149 | logs: TArray; 150 | end; 151 | 152 | TGetBlockHeader = record 153 | number: BigInteger; 154 | parentHash: BigInteger; 155 | stateRoot: BigInteger; 156 | extrinsicsRoot: BigInteger; 157 | digest: TDigest; 158 | end; 159 | 160 | TGetHeader = record 161 | number: BigInteger; 162 | parentHash: BigInteger; 163 | stateRoot: BigInteger; 164 | extrinsicsRoot: BigInteger; 165 | digest: TDigest; 166 | end; 167 | 168 | TBlock = record 169 | header: TGetBlockHeader; 170 | extrinsics: TArray; 171 | end; 172 | 173 | TGetBlock = record 174 | block: TBlock; 175 | justifications: string; 176 | end; 177 | 178 | implementation 179 | 180 | end. 181 | 182 | -------------------------------------------------------------------------------- /Web3/Solana/JSONRPC.SolanaClient.dpr: -------------------------------------------------------------------------------- 1 | program JSONRPC.SolanaClient; 2 | 3 | {$APPTYPE CONSOLE} 4 | {$WARN DUPLICATE_CTOR_DTOR OFF} 5 | {$R *.res} 6 | 7 | uses 8 | System.SysUtils, 9 | System.Rtti, 10 | System.TypInfo, 11 | System.JSON.Serializers, 12 | JSONRPC.Web3.SolanaClient in 'JSONRPC.Web3.SolanaClient.pas', 13 | JSONRPC.Web3.SolanaAPI in 'JSONRPC.Web3.SolanaAPI.pas', 14 | JSONRPC.TransportWrapper.HTTP in '..\..\Common\JSONRPC.TransportWrapper.HTTP.pas', 15 | JSONRPC.RIO in '..\..\Common\JSONRPC.RIO.pas', 16 | JSONRPC.JsonUtils in '..\..\Common\JSONRPC.JsonUtils.pas', 17 | JSONRPC.InvokeRegistry in '..\..\Common\JSONRPC.InvokeRegistry.pas', 18 | JSONRPC.Common.Types in '..\..\Common\JSONRPC.Common.Types.pas', 19 | JSONRPC.Common.RecordHandlers in '..\..\Common\JSONRPC.Common.RecordHandlers.pas', 20 | JSONRPC.Common.Consts in '..\..\Common\JSONRPC.Common.Consts.pas', 21 | JSONRPC.Web3.SolanaTypes in 'JSONRPC.Web3.SolanaTypes.pas', 22 | JSONRPC.Web3.Solana.CustomConverters in 'JSONRPC.Web3.Solana.CustomConverters.pas', 23 | JSONRPC.Web3.Solana.RIO in 'JSONRPC.Web3.Solana.RIO.pas', 24 | JSONRPC.Web3.Solana.Attributes in 'JSONRPC.Web3.Solana.Attributes.pas', 25 | JSONRPC.Web3.SolanaTypes.getAccountInfoResultsType in 'JSONRPC.Web3.SolanaTypes.getAccountInfoResultsType.pas', 26 | JSONRPC.Web3.SolanaTypes.getVoteAccountResultsType in 'JSONRPC.Web3.SolanaTypes.getVoteAccountResultsType.pas'; 27 | 28 | procedure Main; 29 | //var 30 | // LCtx: TRttiContext; 31 | // LTypeInfo: PTypeInfo; 32 | // LType: TRttiType; 33 | // LAttribute: EnumAsAttribute; 34 | begin 35 | // LTypeInfo := TypeInfo(TEncoding); 36 | // LType := LCtx.GetType(LTypeInfo); 37 | // LAttribute := LType.GetAttribute; 38 | // // LAttribute.Index = 39 | end; 40 | 41 | begin 42 | ReportMemoryLeaksOnShutdown := True; 43 | Main; 44 | end. 45 | -------------------------------------------------------------------------------- /Web3/Solana/JSONRPC.SolanaClient.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuacw/JSONRPC_Framework/9463b711d858b7fb91051146b757951923aa1441/Web3/Solana/JSONRPC.SolanaClient.res -------------------------------------------------------------------------------- /Web3/Solana/JSONRPC.Web3.Solana.Attributes.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.Web3.Solana.Attributes; 2 | 3 | interface 4 | 5 | type 6 | 7 | EnumAsAttribute = class(TCustomAttribute) 8 | protected 9 | FIndex: Integer; 10 | FName: string; 11 | public 12 | constructor Create(AIndex: Integer; const AName: string); 13 | property Index: Integer read FIndex; 14 | property EnumName: string read FName; 15 | end; 16 | 17 | implementation 18 | 19 | { EnumAsAttribute } 20 | 21 | constructor EnumAsAttribute.Create(AIndex: Integer; const AName: string); 22 | begin 23 | FIndex := AIndex; 24 | FName := AName; 25 | end; 26 | 27 | end. 28 | -------------------------------------------------------------------------------- /Web3/Solana/JSONRPC.Web3.Solana.Consts.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.Web3.Solana.Consts; 2 | 3 | interface 4 | 5 | const 6 | URL_SolanaTestNet: string = 'https://api.testnet.solana.com'; 7 | URL_SolanaDevNet: string = 'https://api.devnet.solana.com'; 8 | URL_SolanaMainNet: string = 'https://api.mainnet-beta.solana.com'; 9 | 10 | implementation 11 | 12 | end. 13 | -------------------------------------------------------------------------------- /Web3/Solana/JSONRPC.Web3.Solana.Converters.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.Web3.Solana.Converters; 2 | 3 | interface 4 | 5 | uses 6 | System.JSON.Converters, System.TypInfo, System.JSON.Readers, 7 | System.JSON.Serializers, System.Rtti, System.JSON.Writers, 8 | System.Messaging, JSONRPC.Web3.Solana.Encoding; 9 | 10 | type 11 | 12 | TEncodingEnumConverter = class(TJsonEnumNameConverter) 13 | protected 14 | class var FMsgId: TMessageSubscriptionId; 15 | class var FEnumNames: array[JSONRPC.Web3.Solana.Encoding.TEncoding] of string; 16 | class constructor Create; 17 | class destructor Destroy; 18 | public 19 | function CanConvert(ATypeInfo: PTypeInfo): Boolean; override; 20 | function ReadJson(const AReader: TJsonReader; ATypeInf: PTypeInfo; 21 | const AExistingValue: TValue; 22 | const ASerializer: TJsonSerializer): TValue; override; 23 | procedure WriteJson(const AWriter: TJsonWriter; const AValue: TValue; 24 | const ASerializer: TJsonSerializer); override; 25 | end; 26 | 27 | implementation 28 | 29 | { TEncodingEnumConverter } 30 | 31 | uses 32 | System.SysUtils, JSONRPC.Web3.Solana.Attributes, 33 | JSONRPC.Common.Types; 34 | 35 | function TEncodingEnumConverter.CanConvert(ATypeInfo: PTypeInfo): Boolean; 36 | begin 37 | Result := (ATypeInfo^.Kind = tkEnumeration); 38 | end; 39 | 40 | class constructor TEncodingEnumConverter.Create; 41 | var 42 | I: JSONRPC.Web3.Solana.Encoding.TEncoding; 43 | // LNames: array[JSONRPC.Web3.Solana.Attributes.TEncoding] of string; 44 | LTypeInfo: PTypeInfo; 45 | LType: TRttiType; 46 | // LOrdValue: Integer; 47 | LCtx: TRttiContext; 48 | LAttributes: TArray; 49 | LCustomAttr: TCustomAttribute; 50 | LEnumAsAttr: EnumAsAttribute; 51 | // LReadName: string; 52 | begin 53 | // FMsgId := TMessageManager.DefaultManager.SubscribeToMessage( 54 | // TJsonConverterRegisterMessage, 55 | // procedure(const Sender: TObject; const AMsg: TMessage) 56 | // var 57 | // LMsg: TJsonConverterRegisterMessage absolute AMsg; 58 | // begin 59 | // LMsg.Converters.Add(TEncodingEnumConverter.Create); 60 | // end 61 | // ); 62 | for I := Low(JSONRPC.Web3.Solana.Encoding.TEncoding) to 63 | High(JSONRPC.Web3.Solana.Encoding.TEncoding) do 64 | begin 65 | FEnumNames[I] := GetEnumName(TypeInfo(JSONRPC.Web3.Solana.Encoding.TEncoding), Ord(I)); 66 | end; 67 | 68 | LTypeInfo := TypeInfo(JSONRPC.Web3.Solana.Encoding.TEncoding); 69 | LType := LCtx.GetType(LTypeInfo); 70 | LAttributes := LType.GetAttributes; 71 | 72 | // LOrdValue := -1; 73 | for LCustomAttr in LAttributes do 74 | begin 75 | if LCustomAttr is EnumAsAttribute then 76 | LEnumAsAttr := EnumAsAttribute(LCustomAttr) else 77 | LEnumAsAttr := nil; 78 | if Assigned(LEnumAsAttr) then 79 | begin 80 | FEnumNames[JSONRPC.Web3.Solana.Encoding.TEncoding(LEnumAsAttr.Index)] := LEnumAsAttr.EnumName; 81 | end; 82 | end; 83 | end; 84 | 85 | class destructor TEncodingEnumConverter.Destroy; 86 | begin 87 | // TMessageManager.DefaultManager.Unsubscribe(TJsonConverterRegisterMessage, FMsgId); 88 | end; 89 | 90 | function TEncodingEnumConverter.ReadJson(const AReader: TJsonReader; 91 | ATypeInf: PTypeInfo; const AExistingValue: TValue; 92 | const ASerializer: TJsonSerializer): TValue; 93 | var 94 | LReadName: string; 95 | LOrdValue: JSONRPC.Web3.Solana.Encoding.TEncoding; 96 | // LCtx: TRttiContext; 97 | // LEnumName: string; 98 | // LTypeInfo: PTypeInfo; 99 | // LType: TRttiType; 100 | // LAttributes: TArray; 101 | // LCustomAttr: TCustomAttribute; 102 | // LEnumAsAttr: EnumAsAttribute; 103 | begin 104 | AReader.Read; // PropertyName = 'encoding' 105 | AReader.Read; // PropertyName = 'encoding' 106 | LReadName := AReader.Value.AsString; 107 | 108 | for LOrdValue := Low(JSONRPC.Web3.Solana.Encoding.TEncoding) to High(JSONRPC.Web3.Solana.Encoding.TEncoding) do 109 | begin 110 | if SameText(FEnumNames[JSONRPC.Web3.Solana.Encoding.TEncoding(LOrdValue)], LReadName) then 111 | Break; 112 | end; 113 | Result := TValue.From(LOrdValue); 114 | 115 | AReader.Read; // EndObject 116 | end; 117 | 118 | procedure TEncodingEnumConverter.WriteJson(const AWriter: TJsonWriter; 119 | const AValue: TValue; const ASerializer: TJsonSerializer); 120 | var 121 | // LCtx: TRttiContext; 122 | // LTypeInfo: PTypeInfo; 123 | // LType: TRttiType; 124 | // LCustomAttr: TCustomAttribute; 125 | // LEnumAsAttr: EnumAsAttribute; 126 | // LAttributes: TArray; 127 | LOrdValue: JSONRPC.Web3.Solana.Encoding.TEncoding; 128 | LEnumName: string; 129 | begin 130 | AWriter.WriteStartObject; 131 | AWriter.WritePropertyName('encoding'); 132 | 133 | LOrdValue := JSONRPC.Web3.Solana.Encoding.TEncoding(AValue.AsOrdinal); 134 | LEnumName := FEnumNames[LOrdValue]; 135 | 136 | AWriter.WriteValue(LEnumName); 137 | AWriter.WriteEndObject; 138 | end; 139 | 140 | end. 141 | -------------------------------------------------------------------------------- /Web3/Solana/JSONRPC.Web3.Solana.CustomConverters.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.Web3.Solana.CustomConverters; 2 | 3 | interface 4 | 5 | uses 6 | System.JSON.Converters, System.TypInfo, System.JSON.Readers, 7 | System.JSON.Serializers, System.Rtti, System.JSON.Writers, 8 | JSONRPC.Web3.Solana.Attributes; 9 | 10 | type 11 | 12 | TEncodingEnumConverter = class(TJsonEnumNameConverter) 13 | protected 14 | class var FEnumNames: array[JSONRPC.Web3.Solana.Attributes.TEncoding] of string; 15 | class constructor Create; 16 | public 17 | function CanConvert(ATypeInfo: PTypeInfo): Boolean; override; 18 | function ReadJson(const AReader: TJsonReader; ATypeInf: PTypeInfo; 19 | const AExistingValue: TValue; 20 | const ASerializer: TJsonSerializer): TValue; override; 21 | procedure WriteJson(const AWriter: TJsonWriter; const AValue: TValue; 22 | const ASerializer: TJsonSerializer); override; 23 | end; 24 | 25 | implementation 26 | 27 | { TEncodingEnumConverter } 28 | 29 | uses 30 | System.SysUtils; 31 | 32 | function TEncodingEnumConverter.CanConvert(ATypeInfo: PTypeInfo): Boolean; 33 | begin 34 | Result := (ATypeInfo^.Kind = tkEnumeration); 35 | end; 36 | 37 | class constructor TEncodingEnumConverter.Create; 38 | var 39 | I: JSONRPC.Web3.Solana.Attributes.TEncoding; 40 | // LNames: array[JSONRPC.Web3.Solana.Attributes.TEncoding] of string; 41 | LTypeInfo: PTypeInfo; 42 | LType: TRttiType; 43 | // LOrdValue: Integer; 44 | LCtx: TRttiContext; 45 | LAttributes: TArray; 46 | LCustomAttr: TCustomAttribute; 47 | LEnumAsAttr: EnumAsAttribute; 48 | // LReadName: string; 49 | begin 50 | for I := Low(JSONRPC.Web3.Solana.Attributes.TEncoding) to 51 | High(JSONRPC.Web3.Solana.Attributes.TEncoding) do 52 | begin 53 | FEnumNames[I] := GetEnumName(TypeInfo(JSONRPC.Web3.Solana.Attributes.TEncoding), Ord(I)); 54 | end; 55 | 56 | LTypeInfo := TypeInfo(JSONRPC.Web3.Solana.Attributes.TEncoding); 57 | LType := LCtx.GetType(LTypeInfo); 58 | LAttributes := LType.GetAttributes; 59 | 60 | // LOrdValue := -1; 61 | for LCustomAttr in LAttributes do 62 | begin 63 | if LCustomAttr is EnumAsAttribute then 64 | LEnumAsAttr := EnumAsAttribute(LCustomAttr) else 65 | LEnumAsAttr := nil; 66 | if Assigned(LEnumAsAttr) then 67 | begin 68 | FEnumNames[JSONRPC.Web3.Solana.Attributes.TEncoding(LEnumAsAttr.Index)] := LEnumAsAttr.EnumName; 69 | end; 70 | end; 71 | end; 72 | 73 | function TEncodingEnumConverter.ReadJson(const AReader: TJsonReader; 74 | ATypeInf: PTypeInfo; const AExistingValue: TValue; 75 | const ASerializer: TJsonSerializer): TValue; 76 | var 77 | LReadName: string; 78 | LOrdValue: JSONRPC.Web3.Solana.Attributes.TEncoding; 79 | // LCtx: TRttiContext; 80 | // LEnumName: string; 81 | // LTypeInfo: PTypeInfo; 82 | // LType: TRttiType; 83 | // LAttributes: TArray; 84 | // LCustomAttr: TCustomAttribute; 85 | // LEnumAsAttr: EnumAsAttribute; 86 | begin 87 | AReader.Read; // PropertyName = 'encoding' 88 | AReader.Read; // PropertyName = 'encoding' 89 | LReadName := AReader.Value.AsString; 90 | 91 | for LOrdValue := Low(JSONRPC.Web3.Solana.Attributes.TEncoding) to High(JSONRPC.Web3.Solana.Attributes.TEncoding) do 92 | begin 93 | if SameText(FEnumNames[JSONRPC.Web3.Solana.Attributes.TEncoding(LOrdValue)], LReadName) then 94 | Break; 95 | end; 96 | Result := TValue.From(LOrdValue); 97 | 98 | AReader.Read; // EndObject 99 | end; 100 | 101 | procedure TEncodingEnumConverter.WriteJson(const AWriter: TJsonWriter; 102 | const AValue: TValue; const ASerializer: TJsonSerializer); 103 | var 104 | // LCtx: TRttiContext; 105 | // LTypeInfo: PTypeInfo; 106 | // LType: TRttiType; 107 | // LCustomAttr: TCustomAttribute; 108 | // LEnumAsAttr: EnumAsAttribute; 109 | // LAttributes: TArray; 110 | LOrdValue: JSONRPC.Web3.Solana.Attributes.TEncoding; 111 | LEnumName: string; 112 | begin 113 | AWriter.WriteStartObject; 114 | AWriter.WritePropertyName('encoding'); 115 | 116 | LOrdValue := JSONRPC.Web3.Solana.Attributes.TEncoding(AValue.AsOrdinal); 117 | LEnumName := FEnumNames[LOrdValue]; 118 | 119 | AWriter.WriteValue(LEnumName); 120 | AWriter.WriteEndObject; 121 | end; 122 | 123 | end. 124 | -------------------------------------------------------------------------------- /Web3/Solana/JSONRPC.Web3.Solana.Encoding.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.Web3.Solana.Encoding; 2 | 3 | interface 4 | 5 | uses 6 | JSONRPC.Web3.Solana.Attributes; 7 | 8 | type 9 | 10 | [EnumAs(2, 'base64+zstd')] 11 | TEncoding = ( 12 | base58, 13 | base64, 14 | base64_zstd, // 2, base64+zstd 15 | jsonParsed, 16 | json 17 | ); 18 | 19 | implementation 20 | 21 | end. -------------------------------------------------------------------------------- /Web3/Solana/JSONRPC.Web3.Solana.RIO.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.Web3.Solana.RIO; 2 | 3 | interface 4 | 5 | uses 6 | JSONRPC.Client.JSONRPCHTTPWrapper, System.Classes, System.SysUtils; 7 | 8 | type 9 | TWeb3SolanaJSONRPCClient = class(TJSONRPCHTTPWrapper) 10 | protected 11 | FOnAfterDispatch: TProc; 12 | procedure DoAfterDispatch; override; 13 | function InitializeHeaders(const ARequestStream: TStream): TNetHeaders; override; 14 | public 15 | property OnAfterDispatch: TProc read FOnAfterDispatch write FOnAfterDispatch; 16 | end; 17 | 18 | implementation 19 | 20 | uses 21 | JSONRPC.Common.Types, JSONRPC.Common.Consts; 22 | 23 | { TWeb3SolanaJSONRPCClient } 24 | 25 | procedure TWeb3SolanaJSONRPCClient.DoAfterDispatch; 26 | begin 27 | inherited; 28 | if Assigned(FOnAfterDispatch) then 29 | FOnAfterDispatch; 30 | end; 31 | 32 | function TWeb3SolanaJSONRPCClient.InitializeHeaders( 33 | const ARequestStream: TStream): TNetHeaders; 34 | begin 35 | inherited; 36 | if Result.ContainsName(SHeadersContentType) then 37 | Result.DeleteName(SHeadersContentType); 38 | Result := Result + [TNameValuePair.Create(SHeadersContentType, SApplicationJson)]; 39 | end; 40 | 41 | end. 42 | -------------------------------------------------------------------------------- /Web3/Solana/JSONRPC.Web3.SolanaClient.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.Web3.SolanaClient; 2 | 3 | {$ALIGN 16} 4 | {$CODEALIGN 16} 5 | 6 | interface 7 | 8 | uses 9 | JSONRPC.Common.Types, System.Classes, System.JSON.Serializers, 10 | JSONRPC.RIO, JSONRPC.Web3.SolanaAPI; 11 | 12 | function GetSolanaJSONRPC(const ServerURL: string = ''; 13 | const AOnLoggingOutgoingJSONRequest: TOnLogOutgoingJSONRequest = nil; 14 | const AOnLoggingIncomingJSONResponse: TOnLogIncomingJSONResponse = nil; 15 | const AOnLogServerURL: TOnLogServerURL = nil 16 | ): ISolanaJSONRPC; 17 | 18 | implementation 19 | 20 | uses 21 | {$IF DEFINED(TEST) OR DEFINED(DEBUG)} 22 | Winapi.Windows, 23 | {$ENDIF} 24 | JSONRPC.Common.Consts, 25 | System.JSON, System.Rtti, JSONRPC.InvokeRegistry, 26 | JSONRPC.JsonUtils; 27 | 28 | function GetSolanaJSONRPC(const ServerURL: string = ''; 29 | const AOnLoggingOutgoingJSONRequest: TOnLogOutgoingJSONRequest = nil; 30 | const AOnLoggingIncomingJSONResponse: TOnLogIncomingJSONResponse = nil; 31 | const AOnLogServerURL: TOnLogServerURL = nil 32 | ): ISolanaJSONRPC; 33 | begin 34 | var LJSONRPCWrapper := TJSONRPCWrapper.Create(nil); 35 | LJSONRPCWrapper.ServerURL := ServerURL; 36 | LJSONRPCWrapper.PassParamsByPos := True; // !! IMPT !! 37 | 38 | LJSONRPCWrapper.OnLogOutgoingJSONRequest := AOnLoggingOutgoingJSONRequest; 39 | LJSONRPCWrapper.OnLogIncomingJSONResponse := AOnLoggingIncomingJSONResponse; 40 | LJSONRPCWrapper.OnLogServerURL := AOnLogServerURL; 41 | 42 | Result := LJSONRPCWrapper as ISolanaJSONRPC; 43 | 44 | {$IF DECLARED(IsDebuggerPresent)} 45 | if IsDebuggerPresent then 46 | begin 47 | LJSONRPCWrapper.SendTimeout := 10*60*1000; 48 | LJSONRPCWrapper.ResponseTimeout := LJSONRPCWrapper.SendTimeout; 49 | {$IF RTLVersion >= TRTLVersion.Delphi120 } 50 | LJSONRPCWrapper.ConnectionTimeout := LJSONRPCWrapper.SendTimeout; 51 | {$ENDIF} 52 | end; 53 | {$ENDIF} 54 | 55 | end; 56 | 57 | 58 | end. 59 | -------------------------------------------------------------------------------- /Web3/Solana/JSONRPC.Web3.SolanaTypes.getAccountInfoResultsType.pas: -------------------------------------------------------------------------------- 1 | // This unit is autogenerated. Do not edit it manually. 2 | // Source: JSON entered in editor 3 | // Date: 30/9/2023 8:47:57 PM 4 | 5 | unit JSONRPC.Web3.SolanaTypes.getAccountInfoResultsType; 6 | 7 | interface 8 | 9 | uses 10 | System.JSON.Serializers; 11 | 12 | type 13 | [JsonSerialize(TJsonMemberSerialization.Fields)] 14 | getAccountInfoHeader = record 15 | private 16 | FnumReadonlySignedAccounts: Integer; 17 | FnumReadonlyUnsignedAccounts: Integer; 18 | FnumRequiredSignatures: Integer; 19 | public 20 | property numReadonlySignedAccounts: Integer read FnumReadonlySignedAccounts write FnumReadonlySignedAccounts; 21 | property numReadonlyUnsignedAccounts: Integer read FnumReadonlyUnsignedAccounts write FnumReadonlyUnsignedAccounts; 22 | property numRequiredSignatures: Integer read FnumRequiredSignatures write FnumRequiredSignatures; 23 | end; 24 | 25 | [JsonSerialize(TJsonMemberSerialization.Fields)] 26 | TInstruction = record 27 | private 28 | Faccounts: TArray; 29 | Fdata: string; 30 | FprogramIdIndex: Integer; 31 | public 32 | property accounts: TArray read Faccounts write Faccounts; 33 | property data: string read Fdata write Fdata; 34 | property programIdIndex: Integer read FprogramIdIndex write FprogramIdIndex; 35 | end; 36 | 37 | [JsonSerialize(TJsonMemberSerialization.Fields)] 38 | TStatus = record 39 | private 40 | FOk: string; 41 | public 42 | property Ok: string read FOk write FOk; 43 | end; 44 | 45 | [JsonSerialize(TJsonMemberSerialization.Fields)] 46 | TMessage = record 47 | private 48 | FaccountKeys: TArray; 49 | Fheader: getAccountInfoHeader; 50 | Finstructions: TArray; 51 | FrecentBlockhash: string; 52 | public 53 | property accountKeys: TArray read FaccountKeys write FaccountKeys; 54 | property header: getAccountInfoHeader read Fheader write Fheader; 55 | property instructions: TArray read Finstructions write Finstructions; 56 | property recentBlockhash: string read FrecentBlockhash write FrecentBlockhash; 57 | end; 58 | 59 | [JsonSerialize(TJsonMemberSerialization.Fields)] 60 | TMeta = record 61 | private 62 | Ferr: string; 63 | Ffee: Integer; 64 | FinnerInstructions: TArray; 65 | FlogMessages: TArray; 66 | FpostBalances: TArray; 67 | FpostTokenBalances: TArray; 68 | FpreBalances: TArray; 69 | FpreTokenBalances: TArray; 70 | Frewards: string; 71 | Fstatus: TStatus; 72 | public 73 | property err: string read Ferr write Ferr; 74 | property fee: Integer read Ffee write Ffee; 75 | property innerInstructions: TArray read FinnerInstructions write FinnerInstructions; 76 | property logMessages: TArray read FlogMessages write FlogMessages; 77 | property postBalances: TArray read FpostBalances write FpostBalances; 78 | property postTokenBalances: TArray read FpostTokenBalances write FpostTokenBalances; 79 | property preBalances: TArray read FpreBalances write FpreBalances; 80 | property preTokenBalances: TArray read FpreTokenBalances write FpreTokenBalances; 81 | property rewards: string read Frewards write Frewards; 82 | property status: TStatus read Fstatus write Fstatus; 83 | end; 84 | 85 | [JsonSerialize(TJsonMemberSerialization.Fields)] 86 | TTransaction_1 = record 87 | private 88 | Fmessage: TMessage; 89 | Fsignatures: TArray; 90 | public 91 | property message: TMessage read Fmessage write Fmessage; 92 | property signatures: TArray read Fsignatures write Fsignatures; 93 | end; 94 | 95 | [JsonSerialize(TJsonMemberSerialization.Fields)] 96 | getAccountInfoResultTransaction = record 97 | private 98 | Fmeta: TMeta; 99 | Ftransaction: TTransaction_1; 100 | public 101 | property meta: TMeta read Fmeta write Fmeta; 102 | property transaction: TTransaction_1 read Ftransaction write Ftransaction; 103 | end; 104 | 105 | [JsonSerialize(TJsonMemberSerialization.Fields)] 106 | getAccountInfoResult = record 107 | private 108 | FblockHeight: Integer; 109 | FblockTime: string; 110 | Fblockhash: string; 111 | FparentSlot: Integer; 112 | FpreviousBlockhash: string; 113 | Ftransactions: TArray; 114 | public 115 | property blockHeight: Integer read FblockHeight write FblockHeight; 116 | property blockTime: string read FblockTime write FblockTime; 117 | property blockhash: string read Fblockhash write Fblockhash; 118 | property parentSlot: Integer read FparentSlot write FparentSlot; 119 | property previousBlockhash: string read FpreviousBlockhash write FpreviousBlockhash; 120 | property transactions: TArray read Ftransactions write Ftransactions; 121 | end; 122 | 123 | implementation 124 | 125 | end. 126 | -------------------------------------------------------------------------------- /Web3/Solana/JSONRPC.Web3.SolanaTypes.getVoteAccountResultsType.pas: -------------------------------------------------------------------------------- 1 | // This unit is autogenerated. Do not edit it manually. 2 | // Source: JSON entered in editor 3 | // Date: 29/9/2023 7:37:41 PM 4 | 5 | unit JSONRPC.Web3.SolanaTypes.getVoteAccountResultsType; 6 | 7 | interface 8 | 9 | uses 10 | System.JSON.Serializers; 11 | 12 | type 13 | [JsonSerialize(TJsonMemberSerialization.Fields)] 14 | TEpochCredit = record 15 | private 16 | [JsonName('Array')] 17 | FArray_: TArray; 18 | public 19 | property Array_: TArray read FArray_ write FArray_; 20 | end; 21 | 22 | [JsonSerialize(TJsonMemberSerialization.Fields)] 23 | TEpochCredit_1 = record 24 | private 25 | [JsonName('Array')] 26 | FArray_: TArray; 27 | public 28 | property Array_: TArray read FArray_ write FArray_; 29 | end; 30 | 31 | [JsonSerialize(TJsonMemberSerialization.Fields)] 32 | TCurrent = record 33 | private 34 | FactivatedStake: Integer; 35 | Fcommission: Integer; 36 | FepochCredits: TArray; 37 | FepochVoteAccount: Boolean; 38 | FlastVote: Integer; 39 | FnodePubkey: string; 40 | FrootSlot: Integer; 41 | FvotePubkey: string; 42 | public 43 | property activatedStake: Integer read FactivatedStake write FactivatedStake; 44 | property commission: Integer read Fcommission write Fcommission; 45 | property epochCredits: TArray read FepochCredits write FepochCredits; 46 | property epochVoteAccount: Boolean read FepochVoteAccount write FepochVoteAccount; 47 | property lastVote: Integer read FlastVote write FlastVote; 48 | property nodePubkey: string read FnodePubkey write FnodePubkey; 49 | property rootSlot: Integer read FrootSlot write FrootSlot; 50 | property votePubkey: string read FvotePubkey write FvotePubkey; 51 | end; 52 | 53 | [JsonSerialize(TJsonMemberSerialization.Fields)] 54 | TDelinquent = record 55 | private 56 | FactivatedStake: Integer; 57 | Fcommission: Integer; 58 | FepochCredits: TArray; 59 | FepochVoteAccount: Boolean; 60 | FlastVote: Integer; 61 | FnodePubkey: string; 62 | FrootSlot: Integer; 63 | FvotePubkey: string; 64 | public 65 | property activatedStake: Integer read FactivatedStake write FactivatedStake; 66 | property commission: Integer read Fcommission write Fcommission; 67 | property epochCredits: TArray read FepochCredits write FepochCredits; 68 | property epochVoteAccount: Boolean read FepochVoteAccount write FepochVoteAccount; 69 | property lastVote: Integer read FlastVote write FlastVote; 70 | property nodePubkey: string read FnodePubkey write FnodePubkey; 71 | property rootSlot: Integer read FrootSlot write FrootSlot; 72 | property votePubkey: string read FvotePubkey write FvotePubkey; 73 | end; 74 | 75 | [JsonSerialize(TJsonMemberSerialization.Fields)] 76 | TgetVoteAccountsResult = record 77 | private 78 | Fcurrent: TArray; 79 | Fdelinquent: TArray; 80 | public 81 | property current: TArray read Fcurrent write Fcurrent; 82 | property delinquent: TArray read Fdelinquent write Fdelinquent; 83 | end; 84 | 85 | implementation 86 | 87 | end. 88 | -------------------------------------------------------------------------------- /Web3/Solana/Solana-README.md: -------------------------------------------------------------------------------- 1 | ### Solana README 2 | 3 | Implements the Solana JSON RPC API as documented at [Solana API](https://docs.solana.com/api/http). 4 | 5 | -------------------------------------------------------------------------------- /Wizard/JSONRPC.App.Form.dfm: -------------------------------------------------------------------------------- 1 | object FormInterfaceGeneration: TFormInterfaceGeneration 2 | Left = 71 3 | Top = 18 4 | Margins.Left = 7 5 | Margins.Top = 7 6 | Margins.Right = 7 7 | Margins.Bottom = 7 8 | Caption = 'Interface generation' 9 | ClientHeight = 1298 10 | ClientWidth = 1419 11 | Color = clBtnFace 12 | Font.Charset = DEFAULT_CHARSET 13 | Font.Color = clWindowText 14 | Font.Height = -27 15 | Font.Name = 'Segoe UI' 16 | Font.Style = [] 17 | Position = poDesktopCenter 18 | OnCreate = FormCreate 19 | PixelsPerInch = 216 20 | TextHeight = 37 21 | inline frmWizard: TfrmWizard 22 | Left = 0 23 | Top = 0 24 | Width = 1419 25 | Height = 1298 26 | Margins.Left = 7 27 | Margins.Top = 7 28 | Margins.Right = 7 29 | Margins.Bottom = 7 30 | Align = alClient 31 | Constraints.MinHeight = 990 32 | Constraints.MinWidth = 1419 33 | TabOrder = 0 34 | ExplicitHeight = 1298 35 | inherited pnlOptions: TPanel 36 | ExplicitWidth = 1419 37 | end 38 | inherited GroupBox1: TGroupBox 39 | Top = 927 40 | ExplicitTop = 927 41 | ExplicitWidth = 1419 42 | inherited PageControl1: TPageControl 43 | inherited TabSheet1: TTabSheet 44 | inherited memSource: TMemo 45 | Width = 1416 46 | Height = 571 47 | ExplicitWidth = 1416 48 | ExplicitHeight = 571 49 | end 50 | end 51 | inherited TabSheet2: TTabSheet 52 | inherited memGetMethodUnit: TMemo 53 | ExplicitWidth = 1395 54 | end 55 | end 56 | end 57 | end 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /Wizard/JSONRPC.App.Form.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.App.Form; 2 | 3 | interface 4 | 5 | uses 6 | Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, 7 | System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, 8 | JSONRPC.App.Wizard; 9 | 10 | type 11 | TFormInterfaceGeneration = class(TForm) 12 | frmWizard: TfrmWizard; 13 | procedure FormCreate(Sender: TObject); 14 | private 15 | { Private declarations } 16 | public 17 | { Public declarations } 18 | end; 19 | 20 | var 21 | FormInterfaceGeneration: TFormInterfaceGeneration; 22 | 23 | implementation 24 | 25 | {$R *.dfm} 26 | 27 | procedure TFormInterfaceGeneration.FormCreate(Sender: TObject); 28 | begin 29 | frmWizard.frameCreate; 30 | end; 31 | 32 | end. 33 | -------------------------------------------------------------------------------- /Wizard/JSONRPC.AppWizard.dpr: -------------------------------------------------------------------------------- 1 | {---------------------------------------------------------------------------} 2 | { } 3 | { File: JSONRPC.AppWizard.dpr } 4 | { Function: JSON RPC wizard } 5 | { } 6 | { Language: Delphi version XE11 or later } 7 | { Author: Chee-Wee Chua } 8 | { Copyright: (c) 2023,2024 Chee-Wee Chua } 9 | {---------------------------------------------------------------------------} 10 | program JSONRPC.AppWizard; 11 | 12 | uses 13 | Vcl.Forms, 14 | System.Net.URLClient, 15 | JSONRPC.App.Form in 'JSONRPC.App.Form.pas' {FormInterfaceGeneration}, 16 | JSONRPC.App.Wizard in 'JSONRPC.App.Wizard.pas' {frmWizard: TFrame}, 17 | JSONRPC.Wizard.Consts in 'JSONRPC.Wizard.Consts.pas'; 18 | 19 | {$R *.res} 20 | 21 | begin 22 | Application.Initialize; 23 | Application.MainFormOnTaskbar := True; 24 | Application.CreateForm(TFormInterfaceGeneration, FormInterfaceGeneration); 25 | Application.Run; 26 | end. 27 | -------------------------------------------------------------------------------- /Wizard/JSONRPC.AppWizard.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chuacw/JSONRPC_Framework/9463b711d858b7fb91051146b757951923aa1441/Wizard/JSONRPC.AppWizard.res -------------------------------------------------------------------------------- /Wizard/JSONRPC.DelphiUnitCreator.pas: -------------------------------------------------------------------------------- 1 | unit JSONRPC.DelphiUnitCreator; 2 | 3 | interface 4 | 5 | uses 6 | ToolsAPI, System.Classes; 7 | 8 | type 9 | 10 | TDelphiUnitCreator = class(TInterfacedObject, IOTAModuleCreator, IOTACreator) 11 | protected 12 | FPersonality: string; 13 | FImplementationSource: string; 14 | FInterfaceSource: string; 15 | FImplementationStream, 16 | FInterfaceStream: TStream; 17 | function GetImplementationStream: TStream; 18 | function GetInterfaceStream: TStream; 19 | public 20 | constructor Create(const APersonality: string); 21 | destructor Destroy; override; 22 | 23 | { IOTACreator } 24 | /// 25 | /// Return a string representing the default creator type in which to augment. 26 | /// See the definitions of sApplication, sConsole, sLibrary and 27 | /// sPackage, etc.. above. Return an empty string indicating that this 28 | /// creator will provide *all* information 29 | /// 30 | function GetCreatorType: string; 31 | /// 32 | /// Return False if this is a new module 33 | /// 34 | function GetExisting: Boolean; 35 | /// 36 | /// Return the File system IDString that this module uses for reading/writing 37 | /// 38 | function GetFileSystem: string; 39 | /// 40 | /// Return the Owning module, if one exists (for a project module, this would 41 | /// be a project; for a project this is a project group) 42 | /// 43 | function GetOwner: IOTAModule; 44 | /// 45 | /// Return true, if this item is to be marked as un-named. This will force the 46 | /// save as dialog to appear the first time the user saves. 47 | /// 48 | function GetUnnamed: Boolean; 49 | 50 | { IOTAModuleCreator } 51 | /// 52 | /// Return the Ancestor form name 53 | /// 54 | function GetAncestorName: string; 55 | /// 56 | /// Return the implementation filename, or blank to have the IDE create a new 57 | /// unique one. (C++ .cpp file or Delphi unit) NOTE: If a value is returned then it *must* be a 58 | /// fully qualified filename. This also applies to GetIntfFileName and 59 | /// GetAdditionalFileName on the IOTAAdditionalFilesModuleCreator interface. 60 | /// 61 | function GetImplFileName: string; 62 | /// 63 | /// Return the interface filename, or blank to have the IDE create a new 64 | /// unique one. (C++ header) 65 | /// 66 | function GetIntfFileName: string; 67 | /// 68 | /// Return the form name 69 | /// 70 | function GetFormName: string; 71 | /// 72 | /// Return True to Make this module the main form of the given Owner/Project 73 | /// 74 | function GetMainForm: Boolean; 75 | /// 76 | /// Return True to show the form 77 | /// 78 | function GetShowForm: Boolean; 79 | /// 80 | /// Return True to show the source 81 | /// 82 | function GetShowSource: Boolean; 83 | /// 84 | /// Create and return the Form resource for this new module if applicable 85 | /// 86 | function NewFormFile(const FormIdent, AncestorIdent: string): IOTAFile; 87 | /// 88 | /// Create and return the Implementation source for this module. (C++ .cpp 89 | /// file or Delphi unit) 90 | /// 91 | function NewImplSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile; 92 | /// 93 | /// Create and return the Interface (C++ header) source for this module 94 | /// 95 | function NewIntfSource(const ModuleIdent, FormIdent, AncestorIdent: string): IOTAFile; 96 | /// 97 | /// Called when the new form/datamodule/custom module is created 98 | /// 99 | procedure FormCreated(const FormEditor: IOTAFormEditor); 100 | 101 | property ImplementationSource: string read FImplementationSource write 102 | FImplementationSource; 103 | property InterfaceSource: string read FInterfaceSource write 104 | FInterfaceSource; 105 | 106 | property InterfaceStream: TStream read GetInterfaceStream; 107 | property ImplementationStream: TStream read GetImplementationStream; 108 | end; 109 | 110 | implementation 111 | 112 | { TDelphiUnitCreator } 113 | 114 | constructor TDelphiUnitCreator.Create(const APersonality: string); 115 | begin 116 | inherited Create; 117 | FPersonality := APersonality; 118 | end; 119 | 120 | destructor TDelphiUnitCreator.Destroy; 121 | begin 122 | FImplementationStream.Free; 123 | FInterfaceStream.Free; 124 | inherited; 125 | end; 126 | 127 | procedure TDelphiUnitCreator.FormCreated(const FormEditor: IOTAFormEditor); 128 | begin 129 | // Do nothing? 130 | end; 131 | 132 | function TDelphiUnitCreator.GetAncestorName: string; 133 | begin 134 | Result := ''; 135 | end; 136 | 137 | function TDelphiUnitCreator.GetCreatorType: string; 138 | begin 139 | Result := ''; 140 | end; 141 | 142 | function TDelphiUnitCreator.GetExisting: Boolean; 143 | begin 144 | Result := False; 145 | end; 146 | 147 | function TDelphiUnitCreator.GetFileSystem: string; 148 | begin 149 | Result := ''; 150 | end; 151 | 152 | function TDelphiUnitCreator.GetFormName: string; 153 | begin 154 | Result := ''; 155 | end; 156 | 157 | function TDelphiUnitCreator.GetImplementationStream: TStream; 158 | begin 159 | if not Assigned(FImplementationStream) then 160 | FImplementationStream := TStringStream.Create; 161 | Result := FImplementationStream; 162 | end; 163 | 164 | function TDelphiUnitCreator.GetImplFileName: string; 165 | begin 166 | Result := ''; 167 | end; 168 | 169 | function TDelphiUnitCreator.GetInterfaceStream: TStream; 170 | begin 171 | if not Assigned(FInterfaceStream) then 172 | FInterfaceStream := TStringStream.Create; 173 | Result := FInterfaceStream; 174 | end; 175 | 176 | function TDelphiUnitCreator.GetIntfFileName: string; 177 | begin 178 | Result := ''; 179 | end; 180 | 181 | function TDelphiUnitCreator.GetMainForm: Boolean; 182 | begin 183 | Result := False; 184 | end; 185 | 186 | function TDelphiUnitCreator.GetOwner: IOTAModule; 187 | begin 188 | Result := GetActiveProject; 189 | end; 190 | 191 | function TDelphiUnitCreator.GetShowForm: Boolean; 192 | begin 193 | Result := False; 194 | end; 195 | 196 | function TDelphiUnitCreator.GetShowSource: Boolean; 197 | begin 198 | Result := True; 199 | end; 200 | 201 | function TDelphiUnitCreator.GetUnnamed: Boolean; 202 | begin 203 | Result := True; 204 | end; 205 | 206 | function TDelphiUnitCreator.NewFormFile(const FormIdent, 207 | AncestorIdent: string): IOTAFile; 208 | begin 209 | Result := nil; 210 | end; 211 | 212 | function TDelphiUnitCreator.NewImplSource(const ModuleIdent, FormIdent, 213 | AncestorIdent: string): IOTAFile; 214 | begin 215 | if (FImplementationSource = '') and Assigned(FImplementationStream) then 216 | FImplementationSource := TStringStream(FImplementationStream).DataString; 217 | Result := TOTAFile.Create(FImplementationSource); 218 | end; 219 | 220 | function TDelphiUnitCreator.NewIntfSource(const ModuleIdent, FormIdent, 221 | AncestorIdent: string): IOTAFile; 222 | begin 223 | if (FInterfaceSource = '') and Assigned(FInterfaceStream) then 224 | FInterfaceSource := TStringStream(FInterfaceStream).DataString; 225 | Result := TOTAFile.Create(FInterfaceSource); 226 | end; 227 | 228 | end. 229 | -------------------------------------------------------------------------------- /Wizard/JSONRPC.Wizard.Consts.pas: -------------------------------------------------------------------------------- 1 | {---------------------------------------------------------------------------} 2 | { } 3 | { File: JSONRPC.Wizard.Consts.pas } 4 | { Function: JSON RPC wizard constants } 5 | { } 6 | { Language: Delphi version XE11 or later } 7 | { Author: Chee-Wee Chua } 8 | { Copyright: (c) 2023,2024 Chee-Wee Chua } 9 | {---------------------------------------------------------------------------} 10 | unit JSONRPC.Wizard.Consts; 11 | 12 | interface 13 | 14 | {$IF CompilerVersion < 36.00 } 15 | {$MESSAGE ERROR 'This requires Delphi 12.0 or later!'} 16 | {$ELSE} 17 | 18 | const 19 | 20 | SInvalidIdentifierFmt: string = 'Invalid identifier: "%s"'; 21 | 22 | SAuthenticationSource: string = 23 | ''' 24 | if (AUserName <> '') or (APassword <> '') then 25 | begin 26 | LJSONRPCWrapper.OnBeforeInitializeHeaders := procedure (var VNetHeaders: TNetHeaders) 27 | begin 28 | var LUserNamePassword := Format('%s:%s', [AUserName, APassword]); 29 | VNetHeaders := [TNameValuePair.Create('Authorization', 'Basic ' + 30 | TNetEncoding.Base64String.Encode(LUserNamePassword))]; 31 | end; 32 | end; 33 | '''; 34 | 35 | SMethodSource: string = 36 | ''' 37 | unit %s; 38 | {$ALIGN 16} 39 | {$CODEALIGN 16} 40 | 41 | interface 42 | 43 | uses 44 | // Helpful units 45 | // JSONRPC.Common.Types, System.Classes, System.JSON.Serializers, 46 | JSONRPC.RIO, %s; 47 | 48 | %s; 49 | 50 | implementation 51 | 52 | uses 53 | // Helpful units 54 | // System.JSON, System.Rtti, 55 | JSONRPC.InvokeRegistry%s; 56 | 57 | %2:s; 58 | begin 59 | RegisterJSONRPCWrapper(TypeInfo(%4:s)); 60 | var LJSONRPCWrapper := TJSONRPCWrapper.Create(nil); 61 | %s 62 | Result := LJSONRPCWrapper as %4:s; 63 | end; 64 | 65 | end. 66 | '''; 67 | 68 | SInterfaceUnitSource: string = 69 | ''' 70 | unit %s; 71 | 72 | interface 73 | 74 | uses 75 | JSONRPC.RIO; 76 | 77 | type 78 | 79 | %s = interface(IJSONRPCMethods) 80 | ['%s'] 81 | end; 82 | 83 | implementation 84 | 85 | uses 86 | JSONRPC.InvokeRegistry; 87 | 88 | initialization 89 | InvRegistry.RegisterInterface(TypeInfo(%1:s)); 90 | end. 91 | '''; 92 | 93 | {$ENDIF} 94 | implementation 95 | 96 | end. 97 | --------------------------------------------------------------------------------