Skip to content

Commit

Permalink
Add ERC: Request Method Types
Browse files Browse the repository at this point in the history
Merged by EIP-Bot.
  • Loading branch information
HelloRickey authored Jun 11, 2024
1 parent 6b99dc3 commit ccaf79a
Show file tree
Hide file tree
Showing 3 changed files with 448 additions and 0 deletions.
148 changes: 148 additions & 0 deletions ERCS/erc-7654.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
---
eip: 7654
title: Request Method Types
description: Use a set of request methods to indicate the type of action to take on the contract.
author: Rickey (@HelloRickey)
discussions-to: https://ethereum-magicians.org/t/erc-7654-request-method-types/19183
status: Draft
type: Standards Track
category: ERC
created: 2024-03-13
---

## Abstract

This proposal standardizes a set of request and response communication standards between clients and smart contracts, using POST, GET, and PUT requests to create, read, and update the states of smart contracts. You can customize different request method names, request parameters and response values, and each request method will be mapped to a specific operation.

## Motivation

Since each contract has different functions, the client cannot use a standard to call different functions of different contracts. Contract Request Methods redefines the request method of the contract, so that different functions of multiple different contracts can be called using a consistent set of rules and protocols.

By dividing the function types into POST, GET, and PUT, different operations can be performed on the contract. This clear operation type can not only help all parties limit the access and operation of contract data, but also effectively simplify the interaction between the client and the contract, making it easier for all parties to understand the functions and hierarchical structure of the contract. The request and response parameter data types of each function of this standard can express the expected operation of the contract and have the ability to describe its own structure, which is conducive to the parties and contracts to create a unified and predictable way of exchanging data.

## Specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.

It consists of four request method types:

**GET**: Request the contract to retrieve records.

**POST**: Request the contract to create a new record.

**PUT**: Request the contract to update a record.

**OPTIONS**: Supported request method types.

Workflow:

1. Call ```options``` to obtain supported request method types.
2. Call ```getMethods``` to obtain the request method name.
3. Call ```getMethodReqAndRes``` to obtain the request parameter data type and response value data type.
4. Encode request parameters and call ```get```, ```post```, and ```put```.
5. Decode response value.

### Interfaces

#### `IRequestMethodTypes.sol`

```solidity
// SPDX-License-Identifier: CC0-1.0
pragma solidity >=0.8.0;
import "./Types.sol";
interface IRequestMethodTypes{
/**
* Requested method type.
* GET, POST, PUT, OPTIONS
*/
enum MethodTypes{
GET,
POST,
PUT,
OPTIONS
}
/**
* Response data event.
* @param _response is the response value of the post request or put request.
*/
event Response(bytes _response);
/**
* Get method names based on request method type.
* @param _methodTypes is the request method type.
* @return Method names.
*/
function getMethods(MethodTypes _methodTypes)external view returns (string[] memory);
/**
* Get the data types of request parameters and responses based on the requested method name.
* @param _methodName is the method name.
* @return Data types of request parameters and responses.
*/
function getMethodReqAndRes(string memory _methodName) external view returns(Types.Type[] memory ,Types.Type[] memory );
/**
* Request the contract to retrieve records.
* @param _methodName is the method name.
* @param _methodReq is the method type.
* @return The response to the get request.
*/
function get(string memory _methodName,bytes memory _methodReq)external view returns(bytes memory);
/**
* Request the contract to create a new record.
* @param _methodName is the method name.
* @param _methodReq is the method type.
* @return The response to the post request.
*/
function post(string memory _methodName,bytes memory _methodReq)external returns(bytes memory);
/**
* Request the contract to update a record.
* @param _methodName is the method name.
* @param _methodReq is the method type.
* @return The response to the put request.
*/
function put(string memory _methodName,bytes memory _methodReq)external returns(bytes memory);
/**
* Supported request method types.
* @return Method types.
*/
function options()external returns(MethodTypes[] memory);
}
```

### Library

The library [`Types.sol`](../assets/eip-7654/Types.sol) contains an enumeration of Solidity types used in the above interfaces.

## Rationale

### Type of request method

In order to enable the client to operate the contract in a standardized and predictable way, three request method types ```GET```, ```POST```, and ```PUT``` are set. The functions of each need to be defined in these three types to facilitate the contract caller to understand and process the information required for the request. However, there is no ```DELETE``` operation type because deleting data in the contract is an inefficient operation. Developers can add a ```PUT``` request method by themselves to set the data to be valid and invalid, and only return valid data in the ```GET``` method.

### Request method parameter type

Some functions are defined in each request method type. They all include request parameter data type and response parameter data type, which need to be set in the ```constructor``` and then obtained according to the method name through ```getMethodReqAndRes```. The data type of the parameter is defined by the enumeration of the data type. When processing the request parameter, ```abi.decode``` is used to decode according to the request parameter type and the request value. When returning the response, ```abi.encode``` is used to encode according to the response value and the response parameter type.


## Reference Implementation

See [Request Method Types Example](../assets/eip-7654/RequestMethodTypes.sol)

## Security Considerations

Contract request methods are divided into safe methods and unsafe methods. If the method request is a read-only operation and will not change the state of the contract, then the method is safe.

**Safe Methods:** GET, OPTIONS
**Unsafe Methods:** POST, PUT

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).

95 changes: 95 additions & 0 deletions assets/erc-7654/RequestMethodTypes.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// SPDX-License-Identifier: CC0-1.0
pragma solidity >=0.8.0;
import "./Types.sol";
import "./IRequestMethodTypes.sol";
contract RequestMethodTypes is IRequestMethodTypes{

//@dev define the data type of this component
struct Profiles{
string name;
uint256 age;
}

mapping (address=>Profiles) users;

//@dev Types contains all data types in solidity
mapping (string=>Types.Type[]) methodRequests;
mapping (string=>Types.Type[]) methodResponses;
mapping (MethodTypes=>string[]) methods;

constructor(){
Types.Type[] memory getReqArray = new Types.Type[](1);
getReqArray[0] = Types.Type.ADDRESS;
Types.Type[] memory dataTypeArray = new Types.Type[](2);
dataTypeArray[0] = Types.Type.STRING;
dataTypeArray[1] = Types.Type.UINT256;
Types.Type[] memory putReqArray = new Types.Type[](2);
putReqArray[0] = Types.Type.ADDRESS;
putReqArray[1] = Types.Type.STRING;
// @dev initialize get, post, put request parameter data types and response data types
setMethod("getUser",MethodTypes.GET,getReqArray,dataTypeArray);
setMethod("createUser",MethodTypes.POST,dataTypeArray,new Types.Type[](0));
setMethod("updateUserName",MethodTypes.PUT,putReqArray,new Types.Type[](0));
}

function setMethod(string memory _methodName,MethodTypes _methodType,Types.Type[] memory _methodReq,Types.Type[] memory _methodRes) private {
methods[_methodType].push(_methodName);
methodRequests[_methodName]=_methodReq;
methodResponses[_methodName]=_methodRes;
}

function getMethodReqAndRes(string memory _methodName)public view returns(Types.Type[] memory ,Types.Type[] memory ){
return(
methodRequests[_methodName],
methodResponses[_methodName]
);
}

function getMethods(MethodTypes _methodTypes)public view returns (string[] memory){
return methods[_methodTypes];
}

function get(string memory _methodName,bytes memory _methodReq)public view returns(bytes memory){
if(compareStrings(_methodName,"getUser")){
address user=abi.decode(_methodReq, (address));
bytes memory userData=abi.encode(users[user].name,users[user].age);
return userData;
}else{
return abi.encode("");
}
}

function post(string memory _methodName,bytes memory _methodReq)public returns(bytes memory){
if(compareStrings(_methodName,"createUser")){
(string memory name,uint256 age)=abi.decode(_methodReq, (string,uint256));
users[msg.sender]=Profiles(name,age);

}
return abi.encode("");
}

function put(string memory _methodName,bytes memory _methodReq)public returns(bytes memory){
if(compareStrings(_methodName,"updateUserName")){
(address userAddress,string memory name)=abi.decode(_methodReq, (address,string));
require(userAddress==msg.sender);
users[userAddress].name=name;
}
return abi.encode("");
}

function options()public pure returns(MethodTypes[] memory){
MethodTypes[] memory methodTypes=new MethodTypes[](4);
methodTypes[0]=MethodTypes.GET;
methodTypes[1]=MethodTypes.POST;
methodTypes[2]=MethodTypes.PUT;
methodTypes[3]=MethodTypes.OPTIONS;
return methodTypes;
}

//@dev compares two strings for equality
function compareStrings(string memory _a, string memory _b) private pure returns (bool) {
return keccak256(abi.encodePacked(_a)) == keccak256(abi.encodePacked(_b));
}


}
Loading

0 comments on commit ccaf79a

Please sign in to comment.