-
Notifications
You must be signed in to change notification settings - Fork 60
/
WeatherFunctions.sol
162 lines (133 loc) · 4.97 KB
/
WeatherFunctions.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
// Deploy on Fuji
import {FunctionsClient} from "@chainlink/contracts/src/v0.8/functions/dev/v1_0_0/FunctionsClient.sol";
import {FunctionsRequest} from "@chainlink/contracts/src/v0.8/functions/dev/v1_0_0/libraries/FunctionsRequest.sol";
contract WeatherFunctions is FunctionsClient {
using FunctionsRequest for FunctionsRequest.Request;
// State variables to store the last request ID, response, and error
bytes32 public lastRequestId;
bytes public lastResponse;
bytes public lastError;
struct RequestStatus {
bool fulfilled; // whether the request has been successfully fulfilled
bool exists; // whether a requestId exists
bytes response;
bytes err;
}
mapping(bytes32 => RequestStatus) public requests; /* requestId --> requestStatus */
bytes32[] public requestIds;
// Event to log responses
event Response(
bytes32 indexed requestId,
string temperature,
bytes response,
bytes err
);
// Hardcoded for Fuji
// Supported networks https://docs.chain.link/chainlink-functions/supported-networks
address router = 0xA9d587a00A31A52Ed70D6026794a8FC5E2F5dCb0;
bytes32 donID =
0x66756e2d6176616c616e6368652d66756a692d31000000000000000000000000;
//Callback gas limit
uint32 gasLimit = 300000;
// Your subscription ID.
uint64 public subscriptionId;
// JavaScript source code
string public source =
"const city = args[0];"
"const apiResponse = await Functions.makeHttpRequest({"
"url: `https://wttr.in/${city}?format=3&m`,"
"responseType: 'text'"
"});"
"if (apiResponse.error) {"
"throw Error('Request failed');"
"}"
"const { data } = apiResponse;"
"return Functions.encodeString(data);";
string public lastCity;
string public lastTemperature;
address public lastSender;
struct CityStruct {
address sender;
uint timestamp;
string name;
string temperature;
}
CityStruct[] public cities;
mapping(string => uint256) public cityIndex;
mapping(bytes32 => string) public request_city; /* requestId --> city*/
constructor(uint64 functionsSubscriptionId) FunctionsClient(router) {
subscriptionId = functionsSubscriptionId;
}
function getTemperature(
string memory _city
) external returns (bytes32 requestId) {
string[] memory args = new string[](1);
args[0] = _city;
FunctionsRequest.Request memory req;
req.initializeRequestForInlineJavaScript(source); // Initialize the request with JS code
if (args.length > 0) req.setArgs(args); // Set the arguments for the request
// Send the request and store the request ID
lastRequestId = _sendRequest(
req.encodeCBOR(),
subscriptionId,
gasLimit,
donID
);
lastCity = _city;
request_city[lastRequestId] = _city;
CityStruct memory auxCityStruct = CityStruct({
sender: msg.sender,
timestamp: 0,
name: _city,
temperature: ""
});
cities.push(auxCityStruct);
cityIndex[_city] = cities.length-1;
requests[lastRequestId] = RequestStatus({
exists: true,
fulfilled: false,
response: "",
err: ""
});
requestIds.push(lastRequestId);
return lastRequestId;
}
// Receive the weather in the city requested
function fulfillRequest(
bytes32 requestId,
bytes memory response,
bytes memory err
) internal override {
require(requests[requestId].exists, "request not found");
lastError = err;
lastResponse = response;
requests[requestId].fulfilled = true;
requests[requestId].response = response;
requests[requestId].err = err;
string memory auxCity = request_city[requestId];
lastTemperature = string(response);
cities[cityIndex[auxCity]].temperature = lastTemperature;
cities[cityIndex[auxCity]].timestamp = block.timestamp;
// Emit an event to log the response
emit Response(requestId, lastTemperature, lastResponse, lastError);
}
function getCity(string memory city) public view returns (CityStruct memory) {
return cities[cityIndex[city]];
}
function listAllCities() public view returns (CityStruct[] memory) {
return cities;
}
function listCities(uint start, uint end) public view returns (CityStruct[] memory) {
if (end > cities.length)
end = cities.length-1;
require (start <= end, "start must <= end");
uint cityCount = end - start + 1;
CityStruct[] memory citiesAux = new CityStruct[](cityCount);
for (uint i = start; i < (end + 1); i++) {
citiesAux[i-start] = cities[i];
}
return citiesAux;
}
}