Skip to content

Commit 56423d2

Browse files
committed
feat: Backend, tests, frontend
1 parent ef41c05 commit 56423d2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1716
-9724
lines changed

.github/workflows/backend-tests.yml

Lines changed: 0 additions & 34 deletions
This file was deleted.

backend/.env-template

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ OC_HYBRID_ACCOUNT=0x734ab78da8f5ad3290b6abf784d0bea6bd480be1
33
ENTRY_POINTS=0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789
44
CHAIN_ID=28882
55
HC_HELPER_ADDR=0x1c64EC0A5E2C58295c3208a63209A2A719dF68D8
6-
COINRANKING_API_KEY=
7-
OC_PRIVKEY=
6+
OC_PRIVKEY=
7+
OC_OWNER=
8+
OPENAI_APIKEY=

backend/Dockerfile

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
1-
# Stage 1: Build the application
2-
FROM node:18 AS builder
1+
# Use an official Python runtime as a parent image
2+
FROM python:3.9-slim
33

4+
# Set the working directory in the container
45
WORKDIR /app
56

6-
# Copy package.json and package-lock.json (if available)
7-
COPY ./package*.json ./
7+
# Copy the requirements file into the container
8+
COPY requirements.txt .
89

9-
# Install dependencies
10-
RUN npm i
10+
# Install any needed packages specified in requirements.txt
11+
RUN pip install --no-cache-dir -r requirements.txt
1112

1213
# Copy the rest of the application code
13-
COPY *.ts .
14+
COPY *.py .
1415

15-
# Expose the port the app runs on
16+
# Make port 1234 available to the world outside this container
1617
EXPOSE ${OC_LISTEN_PORT:-1234}
1718

18-
# Build the TypeScript application
19-
CMD ["npm", "start"]
19+
# Run the application when the container launches
20+
CMD ["python", "offchain.py"]

backend/common/environment.d.ts

Lines changed: 0 additions & 15 deletions
This file was deleted.

backend/common/types.ts

Lines changed: 0 additions & 7 deletions
This file was deleted.

backend/common/utils.ts

Lines changed: 0 additions & 45 deletions
This file was deleted.

backend/jest.config.js

Lines changed: 0 additions & 10 deletions
This file was deleted.

backend/offchain/offchain.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from web3 import Web3
2+
from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer, SimpleJSONRPCRequestHandler
3+
from text2call import offchain_text2multi
4+
5+
def selector(name):
6+
nameHash = Web3.to_hex(Web3.keccak(text=name))
7+
return nameHash[2:10]
8+
9+
class RequestHandler(SimpleJSONRPCRequestHandler):
10+
rpc_paths = ('/', '/hc')
11+
12+
def offchain_hello(ver, sk, src_addr, src_nonce, oo_nonce, payload, *args):
13+
return { "success":True, "response":payload, "signature":"0x" }
14+
15+
def server_loop():
16+
server = SimpleJSONRPCServer(('0.0.0.0', 1234), requestHandler=RequestHandler)
17+
server.register_function(offchain_hello, "hello")
18+
server.register_function(offchain_text2multi, selector("text2multi(string)"))
19+
print("Serving ")
20+
print("PORT => {}".format(1234))
21+
server.serve_forever()
22+
23+
server_loop() # Run until killed

backend/offchain/offchain_utils.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import os
2+
from web3 import Web3
3+
from eth_abi import abi as ethabi
4+
import eth_account
5+
6+
HC_CHAIN = int(os.environ['CHAIN_ID'])
7+
assert (HC_CHAIN != 0)
8+
9+
EP_ADDR = os.environ['ENTRY_POINTS']
10+
if (len(EP_ADDR) == 0):
11+
EP_ADDR = os.environ['ENTRY_POINT'] # Fallback
12+
assert (len(EP_ADDR) == 42)
13+
EntryPointAddr = Web3.to_checksum_address(EP_ADDR)
14+
15+
HH_ADDR = os.environ['HC_HELPER_ADDR']
16+
assert (len(HH_ADDR) == 42)
17+
HelperAddr = Web3.to_checksum_address(HH_ADDR)
18+
19+
HA_ADDR = os.environ['OC_HYBRID_ACCOUNT']
20+
assert (len(HA_ADDR) == 42)
21+
HybridAcctAddr = Web3.to_checksum_address(HA_ADDR)
22+
23+
HA_OWNER = os.environ['OC_OWNER']
24+
assert (len(HA_OWNER) == 42)
25+
hc1_addr = Web3.to_checksum_address(HA_OWNER)
26+
27+
hc1_key = os.environ['OC_PRIVKEY']
28+
assert (len(hc1_key) == 66)
29+
30+
API_KEY = os.environ['OPENAI_APIKEY']
31+
assert (len(API_KEY) > 1)
32+
33+
34+
def selector(name):
35+
nameHash = Web3.to_hex(Web3.keccak(text=name))
36+
return nameHash[2:10]
37+
38+
39+
def gen_response(req, err_code, resp_payload):
40+
resp2 = ethabi.encode(['address', 'uint256', 'uint32', 'bytes'], [
41+
req['srcAddr'], req['srcNonce'], err_code, resp_payload])
42+
enc1 = ethabi.encode(['bytes32', 'bytes'], [req['skey'], resp2])
43+
p_enc1 = "0x" + selector("PutResponse(bytes32,bytes)") + \
44+
Web3.to_hex(enc1)[2:] # dfc98ae8
45+
46+
enc2 = ethabi.encode(['address', 'uint256', 'bytes'], [
47+
Web3.to_checksum_address(HelperAddr), 0, Web3.to_bytes(hexstr=p_enc1)])
48+
p_enc2 = "0x" + selector("execute(address,uint256,bytes)") + \
49+
Web3.to_hex(enc2)[2:] # b61d27f6
50+
51+
limits = {
52+
'verificationGasLimit': "0x10000",
53+
'preVerificationGas': "0x10000",
54+
}
55+
callGas = 705*len(resp_payload) + 170000
56+
57+
print("callGas calculation", len(resp_payload), 4+len(enc2), callGas)
58+
p = ethabi.encode([
59+
'address',
60+
'uint256',
61+
'bytes32',
62+
'bytes32',
63+
'uint256',
64+
'uint256',
65+
'uint256',
66+
'uint256',
67+
'uint256',
68+
'bytes32',
69+
], [
70+
HybridAcctAddr,
71+
req['opNonce'],
72+
Web3.keccak(Web3.to_bytes(hexstr='0x')), # initCode
73+
Web3.keccak(Web3.to_bytes(hexstr=p_enc2)),
74+
callGas,
75+
Web3.to_int(hexstr=limits['verificationGasLimit']),
76+
Web3.to_int(hexstr=limits['preVerificationGas']),
77+
0, # maxFeePerGas
78+
0, # maxPriorityFeePerGas
79+
Web3.keccak(Web3.to_bytes(hexstr='0x')), # paymasterANdData
80+
])
81+
ooHash = Web3.keccak(ethabi.encode(['bytes32', 'address', 'uint256'], [
82+
Web3.keccak(p), EntryPointAddr, HC_CHAIN]))
83+
signAcct = eth_account.account.Account.from_key(hc1_key)
84+
eMsg = eth_account.messages.encode_defunct(ooHash)
85+
sig = signAcct.sign_message(eMsg)
86+
87+
success = (err_code == 0)
88+
print("Method returning success={} response={} signature={}".format(
89+
success, Web3.to_hex(resp_payload), Web3.to_hex(sig.signature)))
90+
return ({
91+
"success": success,
92+
"response": Web3.to_hex(resp_payload),
93+
"signature": Web3.to_hex(sig.signature)
94+
})
95+
96+
return response
97+
98+
99+
def parse_req(sk, src_addr, src_nonce, oo_nonce, payload):
100+
req = dict()
101+
req['skey'] = Web3.to_bytes(hexstr=sk)
102+
req['srcAddr'] = Web3.to_checksum_address(src_addr)
103+
req['srcNonce'] = Web3.to_int(hexstr=src_nonce)
104+
req['opNonce'] = Web3.to_int(hexstr=oo_nonce)
105+
req['reqBytes'] = Web3.to_bytes(hexstr=payload)
106+
return req

backend/offchain/package.json

Lines changed: 0 additions & 23 deletions
This file was deleted.

0 commit comments

Comments
 (0)