@@ -2,142 +2,114 @@ import Blob "mo:base/Blob";
2
2
import Cycles "mo:base/ExperimentalCycles" ;
3
3
import Nat64 "mo:base/Nat64" ;
4
4
import Text "mo:base/Text" ;
5
-
6
- // import the custom types we have in Types.mo
7
- import Types "Types" ;
8
-
5
+ import IC "ic:aaaaa-aa" ;
9
6
10
7
// Actor
11
8
actor {
12
9
13
- // This method sends a GET request to a URL with a free API we can test.
14
- // This method returns Coinbase data on the exchange rate between USD and ICP
15
- // for a certain day.
16
- // The API response looks like this:
17
- // [
18
- // [
19
- // 1682978460, <-- start timestamp
20
- // 5.714, <-- lowest price during time range
21
- // 5.718, <-- highest price during range
22
- // 5.714, <-- price at open
23
- // 5.714, <-- price at close
24
- // 243.5678 <-- volume of ICP traded
25
- // ],
26
- // ]
10
+ // This method sends a GET request to a URL with a free API we can test.
11
+ // This method returns Coinbase data on the exchange rate between USD and ICP
12
+ // for a certain day.
13
+ // The API response looks like this:
14
+ // [
15
+ // [
16
+ // 1682978460, <-- start timestamp
17
+ // 5.714, <-- lowest price during time range
18
+ // 5.718, <-- highest price during range
19
+ // 5.714, <-- price at open
20
+ // 5.714, <-- price at close
21
+ // 243.5678 <-- volume of ICP traded
22
+ // ],
23
+ // ]
27
24
28
25
// function to transform the response
29
- public query func transform(raw : Types . TransformArgs ) : async Types . CanisterHttpResponsePayload {
30
- let transformed : Types . CanisterHttpResponsePayload = {
31
- status = raw. response. status;
32
- body = raw. response. body;
33
- headers = [
34
- {
35
- name = "Content-Security-Policy" ;
36
- value = "default-src 'self'" ;
37
- },
38
- { name = "Referrer-Policy" ; value = "strict-origin" },
39
- { name = "Permissions-Policy" ; value = "geolocation=(self)" },
40
- {
41
- name = "Strict-Transport-Security" ;
42
- value = "max-age=63072000" ;
43
- },
44
- { name = "X-Frame-Options" ; value = "DENY" },
45
- { name = "X-Content-Type-Options" ; value = "nosniff" },
46
- ];
47
- };
48
- transformed;
26
+ public query func transform({
27
+ context : Blob ;
28
+ response : IC . http_request_result;
29
+ }) : async IC . http_request_result {
30
+ {
31
+ response with headers = []; // not intersted in the headers
32
+ };
49
33
};
50
-
51
- public func get_icp_usd_exchange() : async Text {
52
34
53
- // 1. DECLARE IC MANAGEMENT CANISTER
54
- // We need this so we can use it to make the HTTP request
55
- let ic : Types . IC = actor ("aaaaa-aa" );
56
-
57
- // 2. SETUP ARGUMENTS FOR HTTP GET request
35
+ public func get_icp_usd_exchange() : async Text {
58
36
59
- // 2.1 Setup the URL and its query parameters
37
+ // 1. SETUP ARGUMENTS FOR HTTP GET request
60
38
let ONE_MINUTE : Nat64 = 60 ;
61
- let start_timestamp : Types . Timestamp = 1682978460 ; // May 1, 2023 22:01:00 GMT
39
+ let start_timestamp : Nat64 = 1682978460 ; // May 1, 2023 22:01:00 GMT
62
40
let host : Text = "api.exchange.coinbase.com" ;
63
41
let url = "https://" # host # "/products/ICP-USD/candles?start=" # Nat64 . toText(start_timestamp) # "&end=" # Nat64 . toText(start_timestamp) # "&granularity=" # Nat64 . toText(ONE_MINUTE );
64
42
65
- // 2 .2 prepare headers for the system http_request call
43
+ // 1 .2 prepare headers for the system http_request call
66
44
let request_headers = [
67
- { name = "Host" ; value = host # ":443" },
68
- { name = "User-Agent" ; value = "exchange_rate_canister" },
45
+ { name = "User-Agent" ; value = "price-feed" },
69
46
];
70
47
71
- // 2.2.1 Transform context
72
- let transform_context : Types . TransformContext = {
73
- function = transform;
74
- context = Blob . fromArray([]);
75
- };
76
-
77
- // 2.3 The HTTP request
78
- let http_request : Types . HttpRequestArgs = {
79
- url = url;
80
- max_response_bytes = null ; // optional for request
81
- headers = request_headers;
82
- body = null ; // optional for request
83
- method = #get;
84
- transform = ?transform_context;
48
+ // 1.3 The HTTP request
49
+ let http_request : IC . http_request_args = {
50
+ url = url;
51
+ max_response_bytes = null ; // optional for request
52
+ headers = request_headers;
53
+ body = null ; // optional for request
54
+ method = #get;
55
+ transform = ?{
56
+ function = transform;
57
+ context = Blob . fromArray([]);
58
+ };
85
59
};
86
60
87
- // 3 . ADD CYCLES TO PAY FOR HTTP REQUEST
61
+ // 2 . ADD CYCLES TO PAY FOR HTTP REQUEST
88
62
89
- // The IC specification spec says, "Cycles to pay for the call must be explicitly transferred with the call"
90
63
// IC management canister will make the HTTP request so it needs cycles
91
64
// See: https://internetcomputer.org/docs/current/motoko/main/cycles
92
-
65
+
93
66
// The way Cycles.add() works is that it adds those cycles to the next asynchronous call
94
- // "Function add(amount) indicates the additional amount of cycles to be transferred in the next remote call"
95
- // See: https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-http_request
67
+ // See:
68
+ // - https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-http_request
69
+ // - https://internetcomputer.org/docs/current/references/https-outcalls-how-it-works#pricing
70
+ // - https://internetcomputer.org/docs/current/developer-docs/gas-cost
96
71
Cycles . add< system > (230_949_972_000 );
97
-
98
- // 4. MAKE HTTPS REQUEST AND WAIT FOR RESPONSE
99
- // Since the cycles were added above, we can just call the IC management canister with HTTPS outcalls below
100
- let http_response : Types . HttpResponsePayload = await ic. http_request(http_request);
101
-
102
- // 5. DECODE THE RESPONSE
103
-
104
- // As per the type declarations in `src/Types.mo`, the BODY in the HTTP response
105
- // comes back as [Nat8s] (e.g. [2, 5, 12, 11, 23]). Type signature:
106
-
107
- // public type HttpResponsePayload = {
72
+
73
+ // 3. MAKE HTTPS REQUEST AND WAIT FOR RESPONSE
74
+ let http_response : IC . http_request_result = await IC . http_request(http_request);
75
+
76
+ // 4. DECODE THE RESPONSE
77
+
78
+ // As per the type declarations, the BODY in the HTTP response
79
+ // comes back as Blob. Type signature:
80
+
81
+ // public type http_request_result = {
108
82
// status : Nat;
109
83
// headers : [HttpHeader];
110
- // body : [Nat8] ;
84
+ // body : Blob ;
111
85
// };
112
86
113
- // We need to decode that [Nat8] array that is the body into readable text.
87
+ // We need to decode that Blob that is the body into readable text.
114
88
// To do this, we:
115
- // 1. Convert the [Nat8] into a Blob
116
- // 2. Use Blob.decodeUtf8() method to convert the Blob to a ?Text optional
117
- // 3. We use a switch to explicitly call out both cases of decoding the Blob into ?Text
118
- let response_body: Blob = Blob . fromArray(http_response. body);
119
- let decoded_text: Text = switch (Text . decodeUtf8(response_body)) {
120
- case (null ) { "No value returned" };
121
- case (?y) { y };
89
+ // 1. Use Text.decodeUtf8() method to convert the Blob to a ?Text optional
90
+ // 2. We use a switch to explicitly call out both cases of decoding the Blob into ?Text
91
+ let decoded_text : Text = switch (Text . decodeUtf8(http_response. body)) {
92
+ case (null ) { "No value returned" };
93
+ case (?y) { y };
122
94
};
123
95
124
- // 6 . RETURN RESPONSE OF THE BODY
96
+ // 5 . RETURN RESPONSE OF THE BODY
125
97
// The API response will looks like this:
126
-
98
+ //
127
99
// ("[[1682978460,5.714,5.718,5.714,5.714,243.5678]]")
128
-
129
- // Which can be formatted as this
100
+ //
101
+ // The API response looks like this:
130
102
// [
131
103
// [
132
- // 1682978460, <-- start/ timestamp
133
- // 5.714, <-- low
134
- // 5.718, <-- high
135
- // 5.714, <-- open
136
- // 5.714, <-- close
137
- // 243.5678 <-- volume
104
+ // 1682978460, <-- start timestamp
105
+ // 5.714, <-- lowest price during time range
106
+ // 5.718, <-- highest price during range
107
+ // 5.714, <-- price at open
108
+ // 5.714, <-- price at close
109
+ // 243.5678 <-- volume of ICP traded
138
110
// ],
139
111
// ]
140
- decoded_text
112
+ decoded_text;
141
113
};
142
114
143
115
};
0 commit comments