Skip to content

Commit 4a3b4c6

Browse files
Allow multiple dynamic params on function calls, fix for param length on TCPBridge comms
1 parent f2fd05c commit 4a3b4c6

File tree

9 files changed

+155
-48
lines changed

9 files changed

+155
-48
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@
66

77
What's New:
88

9+
v1.41:
10+
- Allow multiple dynamic params on function calls.
11+
- Fix/allow unlimited length params on TcpBridge.
12+
913
v1.4:
1014
- Add Sepolia testnet.
1115
- Ensure Polygon and Mumbai are working correctly.
12-
- Optimse and fix contract call result handling.
16+
- Optimise and fix contract call result handling.
1317
- Handle String return correctly.
1418

1519
v1.34:

library.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@
2727
"Smart Tokens"
2828
],
2929
"name": "Web3E",
30-
"version": "1.4",
30+
"version": "1.41",
3131
"homepage": "https://www.smarttokenlabs.com/"
3232
}

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=Web3E
2-
version=1.4
2+
version=1.41
33
author=James Brown<[email protected]>
44
maintainer=James Brown <[email protected]>
55
sentence=Web3E (Ethereum For Embedded) interface for Arduino and compitable devices.

src/Contract.cpp

Lines changed: 76 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,43 +64,91 @@ string Contract::SetupContractData(const char* func, ...)
6464
}
6565
}
6666

67+
vector<string> abiBlocks;
68+
vector<bool> isDynamic;
69+
int dynamicStartPointer = 0;
70+
6771
va_list args;
6872
va_start(args, func);
6973
for( int i = 0; i < paramCount; ++i ) {
7074
if (strstr(params[i].c_str(), "uint") != NULL && strstr(params[i].c_str(), "[]") != NULL)
7175
{
7276
// value array
7377
string output = GenerateBytesForUIntArray(va_arg(args, vector<uint32_t> *));
74-
ret = ret + output;
78+
abiBlocks.push_back(output);
79+
isDynamic.push_back(false);
80+
dynamicStartPointer += 0x20;
7581
}
7682
else if (strncmp(params[i].c_str(), "uint", sizeof("uint")) == 0 || strncmp(params[i].c_str(), "uint256", sizeof("uint256")) == 0)
7783
{
7884
string output = GenerateBytesForUint(va_arg(args, uint256_t *));
79-
ret = ret + output;
85+
abiBlocks.push_back(output);
86+
isDynamic.push_back(false);
87+
dynamicStartPointer += 0x20;
8088
}
8189
else if (strncmp(params[i].c_str(), "int", sizeof("int")) == 0 || strncmp(params[i].c_str(), "bool", sizeof("bool")) == 0)
8290
{
8391
string output = GenerateBytesForInt(va_arg(args, int32_t));
84-
ret = ret + string(output);
92+
abiBlocks.push_back(output);
93+
isDynamic.push_back(false);
94+
dynamicStartPointer += 0x20;
8595
}
8696
else if (strncmp(params[i].c_str(), "address", sizeof("address")) == 0)
8797
{
8898
string output = GenerateBytesForAddress(va_arg(args, string *));
89-
ret = ret + string(output);
99+
abiBlocks.push_back(output);
100+
isDynamic.push_back(false);
101+
dynamicStartPointer += 0x20;
90102
}
91103
else if (strncmp(params[i].c_str(), "string", sizeof("string")) == 0)
92104
{
93105
string output = GenerateBytesForString(va_arg(args, string *));
94-
ret = ret + string(output);
106+
abiBlocks.push_back(output);
107+
isDynamic.push_back(true);
108+
dynamicStartPointer += 0x20;
95109
}
96110
else if (strncmp(params[i].c_str(), "bytes", sizeof("bytes")) == 0) //if sending bytes, take the value in hex
97111
{
98112
string output = GenerateBytesForHexBytes(va_arg(args, string *));
99-
ret = ret + string(output);
113+
abiBlocks.push_back(output);
114+
isDynamic.push_back(true);
115+
dynamicStartPointer += 0x20;
116+
}
117+
else if (strncmp(params[i].c_str(), "struct", sizeof("struct")) == 0) //if sending bytes, take the value in hex
118+
{
119+
string output = GenerateBytesForStruct(va_arg(args, string *));
120+
abiBlocks.push_back(output);
121+
isDynamic.push_back(true);
122+
dynamicStartPointer += 0x20;
100123
}
101124
}
102125
va_end(args);
103126

127+
uint256_t abiOffet = uint256_t(dynamicStartPointer);
128+
//now build output - parse 1, standard params
129+
for( int i = 0; i < paramCount; ++i )
130+
{
131+
if (isDynamic[i])
132+
{
133+
ret = ret + abiOffet.str(16, 64);
134+
string *outputHex = &abiBlocks[i];
135+
abiOffet += outputHex->size() / 2;
136+
}
137+
else
138+
{
139+
ret = ret + abiBlocks[i];
140+
}
141+
}
142+
143+
//parse 2: add dynamic params
144+
for( int i = 0; i < paramCount; ++i )
145+
{
146+
if (isDynamic[i])
147+
{
148+
ret = ret + abiBlocks[i];
149+
}
150+
}
151+
104152
return ret;
105153
}
106154

@@ -137,6 +185,15 @@ string Contract::SendTransaction(uint32_t nonceVal, unsigned long long gasPriceV
137185
return web3->EthSendSignedTransaction(&paramStr, param.size());
138186
}
139187

188+
/**
189+
* Utility functions
190+
**/
191+
192+
void Contract::ReplaceFunction(std::string &param, const char* func)
193+
{
194+
param = GenerateContractBytes(func) + param.substr(10);
195+
}
196+
140197
/**
141198
* Private functions
142199
**/
@@ -217,18 +274,26 @@ string Contract::GenerateBytesForHexBytes(const string *value)
217274
else if (value->at(1) == 'x') cleaned = value->substr(2);
218275
string digitsStr = Util::intToHex(cleaned.length() / 2); //bytes length will be hex length / 2
219276
string lengthDesignator = string(64 - digitsStr.length(), '0') + digitsStr;
220-
//write designator. TODO: This should be done for multiple inputs not just single inputs
221-
lengthDesignator = "0000000000000000000000000000000000000000000000000000000000000020" + lengthDesignator;
222277
cleaned = lengthDesignator + cleaned;
223278
size_t digits = cleaned.length() % 64;
224-
return cleaned + string(64 - digits, '0');
279+
return cleaned + (digits > 0 ? string(64 - digits, '0') : "");
280+
}
281+
282+
string Contract::GenerateBytesForStruct(const string *value)
283+
{
284+
//struct has no length params: not required
285+
string cleaned = *value;
286+
if (value->at(0) == 'x') cleaned = value->substr(1);
287+
else if (value->at(1) == 'x') cleaned = value->substr(2);
288+
size_t digits = cleaned.length() % 64;
289+
return cleaned + (digits > 0 ? string(64 - digits, '0') : "");
225290
}
226291

227292
string Contract::GenerateBytesForBytes(const char *value, const int len)
228293
{
229294
string bytesStr = Util::ConvertBytesToHex((const uint8_t *)value, len).substr(2); //clean hex prefix;
230-
size_t digits = bytesStr.length();
231-
return bytesStr + string(64 - digits, '0');
295+
size_t digits = bytesStr.length() % 64;
296+
return bytesStr + (digits > 0 ? string(64 - digits, '0') : "");
232297
}
233298

234299
vector<uint8_t> Contract::RlpEncode(

src/Contract.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,23 @@ class Contract {
3838
string SendTransaction(uint32_t nonceVal, unsigned long long gasPriceVal, uint32_t gasLimitVal,
3939
string *toStr, uint256_t *valueStr, string *dataStr);
4040

41+
static void ReplaceFunction(std::string &param, const char* func);
42+
4143
private:
4244
Web3* web3;
4345
const char * contractAddress;
4446
Crypto* crypto;
4547

4648
private:
47-
string GenerateContractBytes(const char *func);
49+
static string GenerateContractBytes(const char *func);
4850
string GenerateBytesForInt(const int32_t value);
4951
string GenerateBytesForUint(const uint256_t *value);
5052
string GenerateBytesForAddress(const string *value);
5153
string GenerateBytesForString(const string *value);
5254
string GenerateBytesForBytes(const char* value, const int len);
5355
string GenerateBytesForUIntArray(const vector<uint32_t> *v);
5456
string GenerateBytesForHexBytes(const string *value);
57+
string GenerateBytesForStruct(const string *value);
5558

5659
void GenerateSignature(uint8_t* signature, int* recid, uint32_t nonceVal, unsigned long long gasPriceVal, uint32_t gasLimitVal,
5760
string* toStr, uint256_t* valueStr, string* dataStr);

src/TcpBridge.cpp

Lines changed: 55 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -53,40 +53,51 @@ void TcpBridge::checkClientAPI(TcpBridgeCallback callback)
5353
{
5454
maintainComms(millis());
5555

56-
if (!available())
56+
uint16_t rLen = available();
57+
58+
if (rLen <= 0)
5759
return;
5860

59-
int len = read(packetBuffer, PACKET_BUFFER_SIZE);
61+
Serial.print("Available: ");
62+
Serial.println(rLen);
63+
64+
int type = read();
6065

61-
if (len > 0)
66+
if (type > 0)
6267
{
63-
BYTE type = packetBuffer[0];
68+
int len;
6469
lastComms = millis();
6570
std::string result;
6671

67-
Serial.print("RCV: ");
68-
Serial.println(len);
69-
7072
switch (type)
7173
{
7274
case 0x02:
73-
signChallenge(&packetBuffer[1], len - 1);
75+
Serial.println("Challenge");
76+
len = read(packetBuffer, PACKET_BUFFER_SIZE);
77+
signChallenge(packetBuffer, len);
7478
// challenge, we sign it
7579
connectionState = confirmed;
7680
break;
7781

7882
case 0x04:
7983
// API call
80-
scanAPI(packetBuffer + 1, apiReturn, len - 1);
84+
scanAPI(apiReturn, rLen - 1);
8185
result = callback(apiReturn);
8286
Serial.print("Result ");
8387
Serial.println(result.c_str());
8488
sendResponse(result);
8589
break;
8690

8791
case 0x06:
92+
Serial.println("Keep Alive");
93+
read(packetBuffer, PACKET_BUFFER_SIZE);
8894
SendKeepAlive();
8995
break;
96+
97+
default:
98+
Serial.print("Unknown: ");
99+
Serial.println(type);
100+
break;
90101
}
91102
}
92103
}
@@ -146,54 +157,68 @@ void TcpBridge::SendKeepAlive()
146157
write(packetBuffer, 1);
147158
}
148159

149-
void TcpBridge::scanAPI(const BYTE *packet, APIReturn *apiReturn, int payloadLength)
160+
void TcpBridge::scanAPI(APIReturn *apiReturn, int available)
150161
{
151-
apiReturn->clear();
152-
153162
int index = 0;
154-
155-
// read length of API description
156-
apiReturn->apiName = getArg(packet, index, payloadLength);
163+
apiReturn->clear();
164+
apiReturn->apiName = getArg(index);
157165
Serial.print("API: ");
158166
Serial.println(apiReturn->apiName.c_str());
159167

160-
while (index < payloadLength)
168+
while (index < available)
161169
{
162-
std::string key = getArg(packet, index, payloadLength);
163-
std::string param = getArg(packet, index, payloadLength);
170+
std::string key = getArg(index);
171+
std::string param = getArg(index);
172+
164173
apiReturn->params[key] = param;
165-
Serial.print("PAIR: ");
174+
/*Serial.print("PAIR: ");
166175
Serial.print(key.c_str());
167176
Serial.print(" ");
168177
Serial.println(param.c_str());
178+
Serial.print("Index: ");
179+
Serial.println(index);*/
169180
}
170181
}
171182

172-
int TcpBridge::getArglen(const BYTE *packet, int &index)
183+
int TcpBridge::getArgLen(int &index)
173184
{
174-
int byteArgLen = packet[index++] & 0xFF;
175-
int argLen = byteArgLen;
185+
int byteArgLen = 0xFF;
186+
int argLen = 0;
176187

177188
while ((byteArgLen & 0xFF) == 0xFF)
178189
{
179-
byteArgLen = packet[index++] & 0xFF;
190+
byteArgLen = read();
180191
argLen += byteArgLen;
192+
index++;
181193
}
182194

183195
return argLen;
184196
}
185197

186-
std::string TcpBridge::getArg(const BYTE *packet, int &index, int payloadLength)
198+
std::string TcpBridge::bufferToString(const BYTE *packet, int endIndex)
187199
{
188-
int argLen = getArglen(packet, index);
189200
std::string retVal = "";
190-
int endIndex = index + argLen;
191-
if (endIndex > payloadLength)
192-
endIndex = payloadLength;
193-
for (; index < endIndex; index++)
201+
for (int index = 0; index < endIndex; index++)
194202
{
195203
retVal = retVal + (char)packet[index];
196204
}
197205

198206
return retVal;
199-
}
207+
}
208+
209+
std::string TcpBridge::getArg(int &index)
210+
{
211+
int argLen = getArgLen(index);
212+
std::string retVal = "";
213+
214+
while (argLen > 0)
215+
{
216+
int readAmount = argLen > PACKET_BUFFER_SIZE ? PACKET_BUFFER_SIZE : argLen;
217+
int len = read(packetBuffer, readAmount);
218+
index += len;
219+
argLen -= len;
220+
retVal += bufferToString(packetBuffer, len);
221+
}
222+
223+
return retVal;
224+
}

src/TcpBridge.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ class TcpBridge : public WiFiClient
2121
int getPort() { return port; }
2222

2323
private:
24-
void scanAPI(const BYTE *packet, APIReturn *apiReturn, int payloadLength);
25-
std::string getArg(const BYTE *packet, int &index, int payloadLength);
24+
void scanAPI(APIReturn *apiReturn, int available);
25+
std::string getArg(int &index);
26+
std::string bufferToString(const BYTE *packet, int index);
2627
void closeConnection();
2728
void SendKeepAlive();
2829
void maintainComms(long currentMillis);
@@ -31,7 +32,7 @@ class TcpBridge : public WiFiClient
3132
inline boolean isNewSession();
3233
void sendPing();
3334
void sendResponse(std::string resp);
34-
int getArglen(const BYTE *packet, int &index);
35+
int getArgLen(int &index);
3536

3637
Web3 *web3;
3738
KeyID *keyID;

src/Web3.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,14 @@ bool Web3::getBool(const string* json) {
280280
return v > 0;
281281
}
282282

283+
string Web3::getResult(const string* json) {
284+
TagReader reader;
285+
string res = reader.getTag(json, "result");
286+
if (res.at(0) == 'x') res = res.substr(1);
287+
else if (res.at(1) == 'x') res = res.substr(2);
288+
return res;
289+
}
290+
283291
//Currently only works for string return eg: function name() returns (string)
284292
string Web3::getString(const string *json)
285293
{

src/Web3.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class Web3 {
7272
string getString(const string* json);
7373
int getInt(const string* json);
7474
uint256_t getUint256(const string* json);
75+
string getResult(const string* json);
7576

7677
private:
7778
string exec(const string* data);

0 commit comments

Comments
 (0)