Skip to content

Commit 8660afc

Browse files
authored
Merge pull request #18 from near/fix-and-keys
Fix and keys
2 parents 5d5c16a + 91953c2 commit 8660afc

File tree

17 files changed

+176
-410
lines changed

17 files changed

+176
-410
lines changed

package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "near-discovery-ide",
33
"displayName": "NEAR BOS IDE",
44
"description": "Build a decentralized frontend in minutes. Known before as NEAR Social / Discovery",
5-
"version": "2.0.0",
5+
"version": "2.1.2",
66
"publisher": "near-protocol",
77
"icon": "readme/near-protocol-near-logo.png",
88
"homepage": "https://github.com/near/near-vscode",
@@ -85,6 +85,11 @@
8585
"view": "near-discovery",
8686
"contents": "[Fetch Account Widgets](command:near.openWidgetsFromAccount)",
8787
"when": "BOS.enabled"
88+
},
89+
{
90+
"view": "near-discovery",
91+
"contents": "[Add Access Key](command:near.addKey)",
92+
"when": "BOS.enabled"
8893
}
8994
],
9095
"views": {

src/commands/add-key.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import * as vscode from 'vscode';
2+
import { APP_NAME } from '../config';
3+
import { KeyPair } from 'near-api-js';
4+
import { addToContext, getFromContext } from '../extension';
5+
6+
export const addKeyForContract = async (context: vscode.ExtensionContext, localWorkspace: string) => {
7+
const contractId = await vscode.window.showInputBox({ placeHolder: 'Which contract do you want to call?' });
8+
const accountId = getFromContext(localWorkspace, "accountId");
9+
10+
if(!accountId){
11+
return vscode.window.showErrorMessage('Please login first');
12+
}
13+
14+
if (contractId) {
15+
const publisher = context.extension.packageJSON.publisher;
16+
const name = context.extension.packageJSON.name;
17+
const callback = `${vscode.env.uriScheme}://${publisher}.${name}`;
18+
19+
// Create a private key to interact with the social contract
20+
const keyPair = KeyPair.fromRandom("ED25519");
21+
const publicKey = keyPair.getPublicKey().toString();
22+
23+
// Save the private access key in context.json
24+
await addToContext(localWorkspace, 'accessKey', keyPair.toString());
25+
26+
context.globalState.update('addKeyForContract', true);
27+
28+
// Create the login URL and redirect the user to login
29+
const networkId = await getFromContext(localWorkspace, 'networkId') || "mainnet";
30+
31+
let url = `https://wallet.${networkId}.near.org/login/?title=${APP_NAME}&success_url=${callback}&contract_id=${contractId}&public_key=${publicKey}&account_id=${accountId}`;
32+
vscode.env.openExternal(vscode.Uri.parse(url));
33+
} else {
34+
vscode.window.showErrorMessage('Invalid Contract ID');
35+
}
36+
};

src/commands/callbacks.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import * as vscode from 'vscode';
22
import { getTransactionStatus } from '../modules/social';
3-
import { addToContext } from '../extension';
3+
import { addToContext, getFromContext } from '../extension';
44

55
export const handleTransactionCallback = async (uri: vscode.Uri, context: vscode.ExtensionContext, localWorkspace: string | undefined) => {
66
const queryParams = new URLSearchParams(uri.query);
7+
const networkId = await getFromContext(localWorkspace, 'networkId') || "mainnet";
78

89
// Transaction callback
910
if (queryParams.has('transactionHashes')) {
1011
const tHash = queryParams.get('transactionHashes') as string;
1112

12-
const result = await getTransactionStatus(tHash);
13+
const result = await getTransactionStatus(tHash, networkId);
1314
const explorerURL = `https://explorer.near.org/transactions/${tHash}`;
1415
const action = (selection?: string) => { selection ? vscode.env.openExternal(vscode.Uri.parse(explorerURL)) : ""; };
1516

@@ -20,20 +21,24 @@ export const handleTransactionCallback = async (uri: vscode.Uri, context: vscode
2021
vscode.window.showErrorMessage(`Error: ${result.error}`, "View in Explorer")
2122
.then(action);
2223
}
24+
25+
return;
2326
}
2427

2528
// Passing an AccountID
2629
if (queryParams.has('account_id')) {
2730
const accountId = queryParams.get('account_id') as string;
2831

2932
await addToContext(localWorkspace, 'accountId', accountId);
30-
await addToContext(localWorkspace, 'networkId', "mainnet");
33+
34+
if(context.globalState.get('addKeyForContract') === true){
35+
context.globalState.update('addKeyForContract', false);
36+
vscode.window.showInformationMessage(`Successfully added key for account ${accountId}`);
37+
return;
38+
}
3139

3240
if (localWorkspace) {
3341
vscode.commands.executeCommand("near.openWidgetsFromAccount", accountId);
34-
} else {
35-
context.workspaceState.update('openAccount', accountId);
36-
vscode.commands.executeCommand("near.chooseLocalPath");
3742
}
3843
}
3944
};

src/commands/load.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@ import path from 'path';
22
import * as vscode from 'vscode';
33

44
import * as social from '../modules/social';
5+
import { getFromContext } from '../extension';
56

67
export const openAccountWidgets = async (localWorkspace:string, accountId?: string) => {
78
accountId = accountId || await vscode.window.showInputBox({ placeHolder: 'Mainnet AccountId [e.g. alice.near]' });
89

10+
const networkId = await getFromContext(localWorkspace, 'networkId') || "mainnet";
11+
912
if (accountId) {
1013
vscode.window.showInformationMessage(`Loading widgets for: ${accountId}`);
1114

12-
const widgetNames = await social.getWidgetsNames(accountId);
15+
const widgetNames = await social.getWidgetsNames(accountId, networkId);
1316

1417
if (!widgetNames.length) {
1518
return vscode.window.showErrorMessage('No widgets found');
@@ -28,7 +31,7 @@ export const openAccountWidgets = async (localWorkspace:string, accountId?: stri
2831
vscode.workspace.fs.createDirectory(vscode.Uri.parse(dir));
2932
}
3033

31-
const widgetCode = await social.getWidgetCode(accountId, name);
34+
const widgetCode = await social.getWidgetCode(accountId, name, networkId);
3235
vscode.workspace.fs.writeFile(vscode.Uri.parse(path.join(dir, `${file[0]}.jsx`)), Buffer.from(widgetCode));
3336
}
3437
} else {

src/commands/login.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
import * as vscode from 'vscode';
2-
import { APP_NAME } from '../config';
2+
import { APP_NAME, contractAccountForNetwork } from '../config';
33
import { KeyPair } from 'near-api-js';
4-
import { addToContext } from '../extension';
4+
import { addToContext, getFromContext } from '../extension';
55

6-
export const loginAccount = async (context: vscode.ExtensionContext, network: string, localWorkspace: string) => {
6+
export const loginAccount = async (context: vscode.ExtensionContext, localWorkspace: string) => {
77
const publisher = context.extension.packageJSON.publisher;
88
const name = context.extension.packageJSON.name;
99
const callback = `${vscode.env.uriScheme}://${publisher}.${name}`;
1010

1111
// Create a private key to interact with the social contract
12-
const contractId = "social.near";
1312
const keyPair = KeyPair.fromRandom("ED25519");
1413
const publicKey = keyPair.getPublicKey().toString();
1514

1615
// Save the private access key in context.json
1716
await addToContext(localWorkspace, 'accessKey', keyPair.toString());
1817

18+
const networkId = await getFromContext(localWorkspace, 'networkId') || "mainnet";
19+
const contractId = contractAccountForNetwork(networkId);
20+
1921
// Create the login URL and redirect the user to login
20-
let url = `https://wallet.${network}.near.org/login/?title=${APP_NAME}&success_url=${callback}&contract_id=${contractId}&public_key=${publicKey}`;
22+
let url = `https://wallet.${networkId}.near.org/login/?title=${APP_NAME}&success_url=${callback}&contract_id=${contractId}&public_key=${publicKey}&methodNames=set`;
2123
vscode.env.openExternal(vscode.Uri.parse(url));
2224
};

src/commands/publish.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,23 @@ import * as vscode from 'vscode';
22
import { WIDGET_EXT } from '../config';
33
import { transactionForPublishingCode } from '../modules/social';
44
import path from 'path';
5+
import { getFromContext } from '../extension';
56

6-
export const publishCode = async (context: vscode.ExtensionContext, network:string, localWorkspace: string) => {
7+
export const publishCode = async (context: vscode.ExtensionContext, localWorkspace: string) => {
78
// This will be called from an active panel
89
const code: string = vscode.window.activeTextEditor?.document?.getText() || "";
910
const uri: string = vscode.window.activeTextEditor?.document?.uri.path.toString() || "";
11+
const networkId = await getFromContext(localWorkspace, 'networkId') || "mainnet";
1012

1113
const [accountId, ...widgetName] = path.relative(localWorkspace, uri).split('/');
12-
let transaction = await transactionForPublishingCode(accountId, widgetName.join('.').replace(WIDGET_EXT, ''), code);
14+
let transaction = await transactionForPublishingCode(accountId, widgetName.join('.').replace(WIDGET_EXT, ''), code, networkId);
1315

1416
const publisher = context.extension.packageJSON.publisher;
1517
const name = context.extension.packageJSON.name;
1618
const callback = `${vscode.env.uriScheme}://${publisher}.${name}`;
1719

18-
const publishUrl = new URL('sign', 'https://wallet.' + network + '.near.org/');
20+
21+
const publishUrl = new URL('sign', 'https://wallet.' + networkId + '.near.org/');
1922
publishUrl.searchParams.set('transactions', transaction);
2023
publishUrl.searchParams.set('callbackUrl', callback);
2124

src/commands/start-ide.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export const startIDE = async (localWorkspace: string) => {
77
vscode.commands.executeCommand('setContext', 'BOS.enabled', true);
88

99
const files = ["props.json", "context.json", "flags.json"];
10-
const defaultValues = ["{}", JSON.stringify(defaultContext), "{}"];
10+
const defaultValues = ["{}", JSON.stringify(defaultContext), `{"components":{}}`];
1111

1212
for (let i = 0; i < files.length; i++) {
1313
const file = path.join(localWorkspace, files[i]);

src/config.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,18 @@ export const WIDGET_EXT = `.jsx`;
66
export const APP_NAME = 'vscode social';
77
export const COST_PER_BYTE = new BN("10000000000000000000");
88
export const DATA_OVERHEAD = 336; // TODO: Compute better
9-
export const TGAS30 = new BN("30"+"0".repeat(12));
9+
export const TGAS30 = new BN("30" + "0".repeat(12));
10+
11+
export function contractAccountForNetwork(network: string) {
12+
return network === "mainnet" ? "social.near" : "v1.social08.testnet";
13+
}
14+
15+
export function networkRPC(network: string) {
16+
return network === "mainnet" ? "https://rpc.near.org" : "https://rpc.testnet.near.org";
17+
}
1018

1119
export const defaultContext = {
1220
wrapperSrc: "near/widget/DIG.Theme",
13-
wrapperProps: {}
21+
wrapperProps: {},
22+
networkId: "mainnet"
1423
};

src/extension.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { WidgetPreviewPanel } from "./modules/preview-panel";
99
import { preview } from "./commands/preview";
1010
import { startIDE } from "./commands/start-ide";
1111
import { updateAllFlags, updateFlags } from "./flags";
12+
import { addKeyForContract } from "./commands/add-key";
1213

1314
let localWorkspace: string = "";
1415
const FS = vscode.workspace.fs;
@@ -48,7 +49,14 @@ export function activate(context: vscode.ExtensionContext) {
4849
// Login Account
4950
context.subscriptions.push(
5051
vscode.commands.registerCommand("near.login", () =>
51-
loginAccount(context, 'mainnet', localWorkspace)
52+
loginAccount(context, localWorkspace)
53+
)
54+
);
55+
56+
// Login Account
57+
context.subscriptions.push(
58+
vscode.commands.registerCommand("near.addKey", () =>
59+
addKeyForContract(context, localWorkspace)
5260
)
5361
);
5462

@@ -63,7 +71,7 @@ export function activate(context: vscode.ExtensionContext) {
6371
// Publish Code
6472
context.subscriptions.push(
6573
vscode.commands.registerCommand("near.publishWidget", () =>
66-
publishCode(context, 'mainnet', localWorkspace)
74+
publishCode(context, localWorkspace)
6775
)
6876
);
6977

@@ -100,4 +108,13 @@ export async function addToContext(localWorkspace: string | undefined, key: stri
100108
let contextData = JSON.parse(data?.toString() || "{}");
101109
contextData[key] = value;
102110
await FS.writeFile(contextUri, Buffer.from(JSON.stringify(contextData, null, 2)));
111+
}
112+
113+
export async function getFromContext(localWorkspace: string | undefined, key: string): Promise<string | undefined> {
114+
if (!localWorkspace) { return; }
115+
116+
const contextUri = vscode.Uri.parse(path.join(localWorkspace, `context.json`));
117+
let data = await FS.readFile(contextUri);
118+
let contextData = JSON.parse(data?.toString() || "{}");
119+
return key in contextData? contextData[key] : undefined;
103120
}

src/flags.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ export async function updateFlags(localWorkspace: string, uri: vscode.Uri, del:
2828
let data = await FS.readFile(flagsUri);
2929
let flagsData = JSON.parse(data?.toString() || `{"components": {}}`);
3030

31+
if (!("components" in flagsData)) { flagsData["components"] = {}; }
32+
3133
const [accountId, ...widgetName] = path.relative(localWorkspace, uri.path).split('/');
3234

3335
const socialPath = uriToSocialPath(accountId, widgetName);

0 commit comments

Comments
 (0)