-
Notifications
You must be signed in to change notification settings - Fork 0
/
account.ts
124 lines (105 loc) · 5.2 KB
/
account.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
import axios from "axios"
import Archethic, { ArchethicWalletClient, Contract, Crypto, Utils } from "@archethicjs/sdk"
import { TransactionSuccess } from "@archethicjs/sdk/dist/api/types";
import { ExtendedTransactionBuilder } from "@archethicjs/sdk/dist/transaction";
import TransactionBuilder from "@archethicjs/sdk/dist/transaction_builder";
import { ConnectionType, getConnection } from "./connection";
import { Config } from "./config";
import { DeployTxDataOpt, getDeployContractTx, getUpgradeContractTx } from "./deployment";
export class Account {
constructor(public address: string, public connectionType: ConnectionType, public archethic: Archethic, public seed?: string) {}
async requestFaucet() {
let endpointUrl = this.archethic.endpoint.nodeEndpoint as URL;
if (endpointUrl.hostname == "mainnet.archethic.net") {
throw new Error("Faucet cannot be requested on mainnet")
}
const faucetURL = new URL("faucet", endpointUrl)
const faucetLink = faucetURL.href
let response = await axios.get(faucetLink, {
headers: {
Origin: endpointUrl.origin,
Referer: faucetLink,
Cookie: "_archethic_key=SFMyNTY.g3QAAAABbQAAAAtfY3NyZl90b2tlbm0AAAAYbUdHbWRVQWVvV1ZIcGtMazhxX0VmdG56.1_OFPYLSwLdkA7SnZNa7A5buhBL08fh6PaZRqu7SGh0"
}
})
const matches = response.data.match(/(?<=name="_csrf_token" value=").*?(?=">)/)
const csrf_token = matches[0]
const params = new URLSearchParams()
params.append('_csrf_token', csrf_token)
params.append('address', this.address)
response = await axios.post(faucetLink, params, {
headers: {
Origin: endpointUrl.origin,
Referer: faucetLink,
Cookie: "_archethic_key=SFMyNTY.g3QAAAABbQAAAAtfY3NyZl90b2tlbm0AAAAYbUdHbWRVQWVvV1ZIcGtMazhxX0VmdG56.1_OFPYLSwLdkA7SnZNa7A5buhBL08fh6PaZRqu7SGh0",
"Content-Type": "application/x-www-form-urlencoded"
}
})
if (!response.data.match(/Transaction submitted/)) {
throw new Error("Unable to send the transaction")
}
}
async sendTransaction(tx: TransactionBuilder): Promise<TransactionSuccess> {
if (this.connectionType == ConnectionType.Wallet) {
const rpcWallet = this.archethic.rpcWallet as ArchethicWalletClient;
const walletAccount = await rpcWallet.getCurrentAccount();
const signedTxs = await rpcWallet.signTransactions(walletAccount.serviceName, "", [tx]);
const signedTx = signedTxs[0].originSign(Utils.originPrivateKey) as ExtendedTransactionBuilder;
return rpcWallet.sendTransaction(signedTx)
}
const seed = this.seed as string;
const genesisAddress = Crypto.deriveAddress(seed)
const index = await this.archethic.transaction.getTransactionIndex(genesisAddress)
const signedTx = tx.build(seed, index).originSign(Utils.originPrivateKey) as ExtendedTransactionBuilder
return new Promise((resolve, reject) => {
signedTx
.on("error", (_context: string, error: string) => reject(error))
.on("requiredConfirmation", (nbConfirmations: number) => {
resolve({
transactionAddress: Utils.uint8ArrayToHex(signedTx.address),
nbConfirmations: nbConfirmations,
maxConfirmations: 0
})
})
.send()
})
}
}
export class AccountContext {
#config: Config
archethicClient!: Archethic;
constructor(client: Archethic, config: Config){
this.archethicClient = client;
this.#config = config;
}
static async fromConfig(config: Config): Promise<AccountContext> {
const client = await getConnection(config.endpoint)
return new AccountContext(client, config);
}
async getAccount(): Promise<Account> {
if (this.archethicClient.endpoint.isRpcAvailable && this.archethicClient.rpcWallet !== undefined) {
const walletAccount = await this.archethicClient.rpcWallet.getCurrentAccount();
return new Account(walletAccount.genesisAddress, ConnectionType.Wallet, this.archethicClient)
}
if (this.#config.seed == undefined) {
throw new Error("seed is required if the connection is not wallet based")
}
const genesisAddress = Crypto.deriveAddress(this.#config.seed)
return new Account(Utils.uint8ArrayToHex(genesisAddress), ConnectionType.Direct, this.archethicClient, this.#config.seed)
}
getRandomAccount(): Account {
const seed = Crypto.randomSecretKey()
const chainAddress = Crypto.deriveAddress(seed)
return new Account(Utils.uint8ArrayToHex(chainAddress), ConnectionType.Direct, this.archethicClient, Utils.uint8ArrayToHex(seed))
}
async deployContract(account: Account, additionalData?: DeployTxDataOpt): Promise<string> {
const contractTx = await getDeployContractTx(account, { additionalData: additionalData , upgradeAddress: this.#config.upgradeAddress })
const { transactionAddress } = await account.sendTransaction(contractTx)
return transactionAddress;
}
async updateContract(account: Account, contractAddress: string, additionalData?: DeployTxDataOpt): Promise<string> {
const contractTx = getUpgradeContractTx(account, contractAddress, { additionalData: additionalData, upgradeAddress: this.#config.upgradeAddress })
const { transactionAddress } = await account.sendTransaction(contractTx)
return transactionAddress;
}
}