-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
207 lines (173 loc) · 5.5 KB
/
index.ts
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
import { TezosToolkit } from "@taquito/taquito";
import { RpcClient } from "@taquito/rpc";
import { packDataBytes } from "@taquito/michel-codec";
import blake2b from "blake2b";
import { hex2buf } from "@taquito/utils";
/**
* index.ts: Interacting with the Tezos blockchain, allowing users to perform token
* transfers and obtain permits for certain operations.
*/
/**
* Settings: Describes the settings object expected by the GasStation class, with an apiURL property.
*/
export type Settings = {
apiURL: string;
};
/**
* Operation: Represents a generic blockchain operation with destination and parameters properties
*/
export type Operation = {
destination: string;
parameters: any;
};
/**
* TransferOperation: Represents a specific type of operation for transferring tokens,
* with from_ as the sender's address and an array of transactions (txs)
*/
export type TransferOperation = {
from_: string;
txs: [
{
to_: string;
token_id: number;
amount: number;
}
];
};
/**
* PermitOperation: Represents an operation for obtaining a permit,
* including publicKey, signature, and transferHash properties
*/
export type PermitOperation = {
publicKey: string;
signature: string;
transferHash: string;
};
export const GAS_STATION_PUBLIC_API_GHOSTNET =
"https://ghostnet.gas-station-api.marigold.dev";
export const GAS_STATION_PUBLIC_API_MAINNET =
"https://gas-station-api.marigold.dev";
/**
* GasStation is responsible for interacting with a remote API to post blockchain operations.
*/
export class GasStation {
url: string;
/**
*
* @param settings (optional) object
* - apiURL: the URL of Gas Station API. /!\ For this version, the URL must redirect to the endpoint /operation
*
* Takes a Settings object and initializes the url property.
*/
constructor(settings?: Settings) {
this.url = settings?.apiURL || GAS_STATION_PUBLIC_API_GHOSTNET;
}
/**
* postOperations: Sends a POST request to the specified API endpoint with the provided operations.
*/
async postOperations(sender: string, ops: Array<Operation>) {
const post_content = {
sender_address: sender,
operations: ops,
};
const response = await fetch(`${this.url}/operation`, {
method: "POST",
mode: "cors",
cache: "no-cache",
credentials: "same-origin",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(post_content),
});
return await response.json();
}
/**
* postOperation: A convenience method to post a single operation using postOperations
*/
postOperation(sender: string, op: Operation) {
return this.postOperations(sender, [op]);
}
}
/**
* PermitContract: interacts with a Tezos smart contract, specifically for
* generating permits related to token transfers.
*
* It uses the Tezos toolkit to interact with the Tezos blockchain,
* fetch contract information, and perform operations.
*
* The code utilizes various Tezos-specific functions and conventions for
* encoding data, hashing, and interacting with smart contracts
*/
export class PermitContract {
address: string;
tezos: TezosToolkit;
constructor(address: string, tezos: TezosToolkit) {
this.address = address;
this.tezos = tezos;
}
/**
* getCounter: Retrieves the counter value from the contract's storage
*/
async getCounter() {
const contract = await this.tezos.wallet.at(this.address);
// @ts-ignore
return (await contract.storage()).extension.counter.c[0];
}
/**
* generatePermit: Generates a permit for a given transfer operation by computing a
* transfer hash and constructing permit data.
*/
async generatePermit(transfer: TransferOperation) {
// @ts-ignore
const rpcClient = new RpcClient(this.tezos._rpc, "main");
const chain_id = await rpcClient.getChainId();
const counter = await this.getCounter();
const contract = await this.tezos.wallet.at(this.address);
const transfer_type = contract.entrypoints.entrypoints.transfer.args?.[0];
// @ts-ignore
const transfer_data = contract.methodsObject
.transfer([transfer])
.toTransferParams().parameter.value[0];
// @ts-ignore
const byts = packDataBytes(transfer_data, transfer_type).bytes;
const blak = blake2b(32);
const transfer_hash = blak.update(hex2buf(byts)).digest("hex");
const permit_data = [
[{ string: chain_id }, { string: this.address }],
[{ int: counter }, { bytes: transfer_hash }],
];
// Same as in the Python demo, we cannot use the entrypoint to derive
// this object
const permit_type = {
prim: "pair",
args: [
{
prim: "pair",
args: [{ prim: "chain_id" }, { prim: "address" }],
},
{
prim: "pair",
args: [{ prim: "int" }, { prim: "bytes" }],
},
],
};
// @ts-ignore
const permit_bytes = packDataBytes(permit_data, permit_type).bytes;
console.info("Permit bytes :", permit_bytes);
console.info("Transfer hash : ", transfer_hash);
return { bytes: permit_bytes, transfer_hash: transfer_hash };
}
/**
* permitCall: Calls the permit entrypoint on the contract with
* the provided permit operation parameters.
*/
async permitCall(op: PermitOperation) {
const contract = await this.tezos.wallet.at(this.address);
const call = await contract.methods
.permit([[op.publicKey, op.signature, op.transferHash]])
.toTransferParams();
console.info("Transfer params", call);
return call;
}
}