create-near-app 8.2.0 → 8.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js +11 -1
- package/dist/make.js +23 -1
- package/dist/messages.js +68 -29
- package/dist/tracking.js +1 -1
- package/dist/types.js +1 -1
- package/dist/user-input.js +1 -0
- package/dist/utils/checkCargoNear.js +15 -0
- package/dist/utils/donwloadFile.js +25 -0
- package/dist/utils/index.js +11 -0
- package/package.json +1 -1
- package/templates/contracts/py/.python-version +1 -0
- package/templates/contracts/py/README.md +74 -0
- package/templates/contracts/py/contract.py +31 -0
- package/templates/contracts/py/pyproject.toml +10 -0
- package/templates/contracts/py/tests/test_mod.py +53 -0
- package/templates/contracts/py/uv.lock +878 -0
- package/templates/contracts/rs/.github/workflows/deploy-production.yml +2 -4
- package/templates/contracts/rs/.github/workflows/deploy-staging.yml +4 -8
- package/templates/contracts/rs/.github/workflows/test.yml +2 -0
- package/templates/contracts/rs/.github/workflows/undeploy-staging.yml +2 -4
- package/templates/contracts/rs/Cargo.toml +15 -9
- package/templates/contracts/rs/README.md +6 -0
- package/templates/contracts/rs/rust-toolchain.toml +2 -2
- package/templates/frontend/next-app/package.json +19 -18
- package/templates/frontend/next-app/src/wallets/web3modal.js +0 -7
- package/templates/frontend/next-page/package.json +19 -18
- package/templates/frontend/next-page/src/wallets/web3modal.js +0 -7
- package/templates/frontend/vite-react/package.json +2 -1
- package/templates/frontend/vite-react/src/wallets/web3modal.js +0 -7
- package/templates/contracts/rs/Cargo.lock +0 -4348
package/dist/app.js
CHANGED
|
@@ -31,6 +31,7 @@ const semver_1 = __importDefault(require("semver"));
|
|
|
31
31
|
const make_1 = require("./make");
|
|
32
32
|
const user_input_1 = require("./user-input");
|
|
33
33
|
const show = __importStar(require("./messages"));
|
|
34
|
+
const utils_1 = require("./utils");
|
|
34
35
|
(async function () {
|
|
35
36
|
const supportedNodeVersion = require('../package.json').engines.node;
|
|
36
37
|
if (!semver_1.default.satisfies(process.version, supportedNodeVersion)) {
|
|
@@ -54,9 +55,18 @@ const show = __importStar(require("./messages"));
|
|
|
54
55
|
console.error(e);
|
|
55
56
|
createSuccess = false;
|
|
56
57
|
}
|
|
58
|
+
let needsToInstallCargoNear = false;
|
|
59
|
+
if (contract === 'rs') {
|
|
60
|
+
show.checkingCargoNear();
|
|
61
|
+
let cargoNearInstalled = await (0, utils_1.isCargoNearInstalled)();
|
|
62
|
+
if (!cargoNearInstalled) {
|
|
63
|
+
needsToInstallCargoNear = true;
|
|
64
|
+
show.cargoNearIsNotInstalled();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
57
67
|
if (createSuccess) {
|
|
58
68
|
install && await (0, make_1.runDepsInstall)(projectPath);
|
|
59
|
-
show.setupSuccess(projectName, contract, frontend, install);
|
|
69
|
+
show.setupSuccess(projectName, contract, frontend, install, needsToInstallCargoNear);
|
|
60
70
|
}
|
|
61
71
|
else {
|
|
62
72
|
return show.setupFailed();
|
package/dist/make.js
CHANGED
|
@@ -27,11 +27,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.runDepsInstall = exports.copyDir = exports.createProject = void 0;
|
|
30
|
-
const show = __importStar(require("./messages"));
|
|
31
30
|
const cross_spawn_1 = __importDefault(require("cross-spawn"));
|
|
32
31
|
const fs_1 = __importDefault(require("fs"));
|
|
33
32
|
const ncp_1 = require("ncp");
|
|
34
33
|
const path_1 = __importDefault(require("path"));
|
|
34
|
+
const show = __importStar(require("./messages"));
|
|
35
|
+
const utils_1 = require("./utils");
|
|
35
36
|
async function createProject({ contract, frontend, projectPath, templatesDir }) {
|
|
36
37
|
if (contract !== 'none') {
|
|
37
38
|
await createContract({ contract, projectPath, templatesDir });
|
|
@@ -43,11 +44,32 @@ async function createProject({ contract, frontend, projectPath, templatesDir })
|
|
|
43
44
|
}
|
|
44
45
|
exports.createProject = createProject;
|
|
45
46
|
async function createContract({ contract, projectPath, templatesDir }) {
|
|
47
|
+
await createContractFromTemplate({ contract, projectPath, templatesDir });
|
|
48
|
+
if (contract === 'rs') {
|
|
49
|
+
await updateTemplateFiles(projectPath);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async function createContractFromTemplate({ contract, projectPath, templatesDir }) {
|
|
46
53
|
// contract folder
|
|
47
54
|
const sourceContractDir = path_1.default.resolve(templatesDir, 'contracts', contract);
|
|
48
55
|
fs_1.default.mkdirSync(projectPath, { recursive: true });
|
|
49
56
|
await copyDir(sourceContractDir, projectPath);
|
|
50
57
|
}
|
|
58
|
+
async function updateTemplateFiles(projectPath) {
|
|
59
|
+
const targetDir = path_1.default.join(projectPath);
|
|
60
|
+
const cargoTomlRemotePath = 'https://raw.githubusercontent.com/near/cargo-near/refs/heads/main/cargo-near/src/commands/new/new-project-template/Cargo.template.toml';
|
|
61
|
+
const cargoTomlFilePath = path_1.default.join(targetDir, 'Cargo.toml');
|
|
62
|
+
const rustToolchainRemotePath = 'https://raw.githubusercontent.com/near/cargo-near/refs/heads/main/cargo-near/src/commands/new/new-project-template/rust-toolchain.toml';
|
|
63
|
+
const rustToolchainFilePath = path_1.default.join(targetDir, 'rust-toolchain.toml');
|
|
64
|
+
show.updatingFiles();
|
|
65
|
+
try {
|
|
66
|
+
await (0, utils_1.downloadFile)(cargoTomlRemotePath, cargoTomlFilePath);
|
|
67
|
+
await (0, utils_1.downloadFile)(rustToolchainRemotePath, rustToolchainFilePath);
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
show.updateFilesFailed();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
51
73
|
async function createGateway({ frontend, projectPath, templatesDir }) {
|
|
52
74
|
const sourceFrontendDir = path_1.default.resolve(`${templatesDir}/frontend/${frontend}`);
|
|
53
75
|
fs_1.default.mkdirSync(projectPath, { recursive: true });
|
package/dist/messages.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.depsInstallError = exports.depsInstall = exports.creatingApp = exports.directoryExists = exports.windowsWarning = exports.unsupportedNodeVersion = exports.argsError = exports.gatewayInstructions = exports.contractInstructions = exports.setupSuccess = exports.successFrontendToText = exports.successContractToText = exports.setupFailed = exports.welcome = exports.show = void 0;
|
|
6
|
+
exports.cargoNearIsNotInstalled = exports.checkingCargoNear = exports.updateFilesFailed = exports.updatingFiles = exports.depsInstallError = exports.depsInstall = exports.creatingApp = exports.directoryExists = exports.windowsWarning = exports.unsupportedNodeVersion = exports.argsError = exports.gatewayInstructions = exports.contractInstructions = exports.setupSuccess = exports.successFrontendToText = exports.successContractToText = exports.setupFailed = exports.welcome = exports.show = void 0;
|
|
7
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
8
|
const tracking_1 = require("./tracking");
|
|
9
9
|
if (process.env.NEAR_NO_COLOR) {
|
|
@@ -24,9 +24,21 @@ Please refer to https://github.com/near/create-near-app README to troubleshoot.
|
|
|
24
24
|
Notice: some platforms aren't supported (yet).
|
|
25
25
|
{bold {red ==========================================}}`);
|
|
26
26
|
exports.setupFailed = setupFailed;
|
|
27
|
+
const mapContractLanguage = (contract) => {
|
|
28
|
+
switch (contract) {
|
|
29
|
+
case 'ts':
|
|
30
|
+
return 'Typescript';
|
|
31
|
+
case 'rs':
|
|
32
|
+
return 'Rust';
|
|
33
|
+
case 'py':
|
|
34
|
+
return 'Python';
|
|
35
|
+
default:
|
|
36
|
+
return '';
|
|
37
|
+
}
|
|
38
|
+
};
|
|
27
39
|
const successContractToText = (contract) => contract === 'none'
|
|
28
40
|
? ''
|
|
29
|
-
: (0, chalk_1.default) `a smart contract in {bold ${contract
|
|
41
|
+
: (0, chalk_1.default) `a smart contract in {bold ${mapContractLanguage(contract)}}`;
|
|
30
42
|
exports.successContractToText = successContractToText;
|
|
31
43
|
const frontendTemplates = {
|
|
32
44
|
'next-page': 'NextJS (Classic)',
|
|
@@ -37,34 +49,52 @@ const successFrontendToText = (frontend) => frontend === 'none'
|
|
|
37
49
|
? ''
|
|
38
50
|
: (0, chalk_1.default) `a web-app using ${frontendTemplates[frontend]}`;
|
|
39
51
|
exports.successFrontendToText = successFrontendToText;
|
|
40
|
-
const setupSuccess = (projectName, contract, frontend, install) => (0, exports.show)((0, chalk_1.default) `
|
|
41
|
-
{
|
|
42
|
-
✅ Success! Created '${projectName}', ${(0, exports.successContractToText)(contract)}${(0, exports.successFrontendToText)(frontend)}.
|
|
52
|
+
const setupSuccess = (projectName, contract, frontend, install, needsToInstallCargoNear) => (0, exports.show)((0, chalk_1.default) `
|
|
53
|
+
✅ Success! Created '${projectName}', ${(0, exports.successContractToText)(contract)}${(0, exports.successFrontendToText)(frontend)}.
|
|
43
54
|
${contract === 'rs'
|
|
44
55
|
? (0, chalk_1.default) `🦀 If you are new to Rust please visit {bold {green https://www.rust-lang.org }}\n`
|
|
45
56
|
: ''}
|
|
46
57
|
{bold {bgYellow {black Next steps}}}:
|
|
47
|
-
${(0, exports.contractInstructions)(projectName, contract, install)}${(0, exports.gatewayInstructions)(projectName, frontend, install)}`);
|
|
58
|
+
${(0, exports.contractInstructions)(projectName, contract, install, needsToInstallCargoNear)}${(0, exports.gatewayInstructions)(projectName, frontend, install)}`);
|
|
48
59
|
exports.setupSuccess = setupSuccess;
|
|
49
|
-
const contractInstructions = (projectName, contract, install) =>
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
{blue
|
|
57
|
-
|
|
58
|
-
- {inverse
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
60
|
+
const contractInstructions = (projectName, contract, install, needsToInstallCargoNear) => {
|
|
61
|
+
if (contract === 'none') {
|
|
62
|
+
return '';
|
|
63
|
+
}
|
|
64
|
+
let message = '';
|
|
65
|
+
if (needsToInstallCargoNear) {
|
|
66
|
+
message += (0, chalk_1.default) ` - {inverse Install cargo-near}:
|
|
67
|
+
{blue Go to {bold https://github.com/near/cargo-near}}\n`;
|
|
68
|
+
}
|
|
69
|
+
message += (0, chalk_1.default) ` - {inverse Navigate to your project}:
|
|
70
|
+
{blue cd {bold ${projectName}}}\n`;
|
|
71
|
+
if (contract === 'ts' && !install) {
|
|
72
|
+
message += (0, chalk_1.default) ` - {inverse Install all dependencies}
|
|
73
|
+
{blue npm {bold install}}\n`;
|
|
74
|
+
}
|
|
75
|
+
message += (0, chalk_1.default) ` - {inverse Build your contract}:\n`;
|
|
76
|
+
if (contract === 'ts') {
|
|
77
|
+
message += (0, chalk_1.default) ` {blue npm {bold run build}}\n`;
|
|
78
|
+
}
|
|
79
|
+
else if (contract === 'py') {
|
|
80
|
+
message += (0, chalk_1.default) ` {blue {bold uvx nearc contract.py --create-venv}}\n`;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
message += (0, chalk_1.default) ` {blue {bold cargo near build}}\n`;
|
|
84
|
+
}
|
|
85
|
+
message += (0, chalk_1.default) ` - {inverse Test your contract} in the Sandbox:\n`;
|
|
86
|
+
if (contract === 'ts') {
|
|
87
|
+
message += (0, chalk_1.default) ` {blue npm {bold run test}}\n`;
|
|
88
|
+
}
|
|
89
|
+
else if (contract === 'py') {
|
|
90
|
+
message += (0, chalk_1.default) ` {blue {bold uv run pytest}}\n`;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
message += (0, chalk_1.default) ` {blue {bold cargo near test}}\n`;
|
|
94
|
+
}
|
|
95
|
+
message += (0, chalk_1.default) `\n🧠 Read {bold {greenBright README.md}} to explore further`;
|
|
96
|
+
return message;
|
|
97
|
+
};
|
|
68
98
|
exports.contractInstructions = contractInstructions;
|
|
69
99
|
const gatewayInstructions = (projectName, frontend, install) => frontend === 'none'
|
|
70
100
|
? ''
|
|
@@ -91,12 +121,21 @@ const windowsWarning = () => (0, exports.show)((0, chalk_1.default) `{red Please
|
|
|
91
121
|
exports.windowsWarning = windowsWarning;
|
|
92
122
|
const directoryExists = (dirName) => (0, exports.show)((0, chalk_1.default) `{red This directory already exists! ${dirName}}`);
|
|
93
123
|
exports.directoryExists = directoryExists;
|
|
94
|
-
const creatingApp = () => (0, exports.show)((0, chalk_1.default) `\
|
|
124
|
+
const creatingApp = () => (0, exports.show)((0, chalk_1.default) `\n- Creating a new {bold NEAR dApp}...`);
|
|
95
125
|
exports.creatingApp = creatingApp;
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
`);
|
|
126
|
+
// Installing dependencies messages
|
|
127
|
+
const depsInstall = () => (0, exports.show)((0, chalk_1.default) `- Installing dependencies in a few folders, this might take a while...`);
|
|
99
128
|
exports.depsInstall = depsInstall;
|
|
100
129
|
const depsInstallError = () => (0, exports.show)(chalk_1.default.red('Error installing NEAR project dependencies'));
|
|
101
130
|
exports.depsInstallError = depsInstallError;
|
|
131
|
+
// Updating files messages
|
|
132
|
+
const updatingFiles = () => (0, exports.show)((0, chalk_1.default) `- Updating Cargo.toml and rust-toolchain.toml files from the remote source...`);
|
|
133
|
+
exports.updatingFiles = updatingFiles;
|
|
134
|
+
const updateFilesFailed = () => (0, exports.show)((0, chalk_1.default) ` {yellow There was a problem during the Cargo.toml and rust-toolchain.toml files remote updating. Check your internet connection.}\n`);
|
|
135
|
+
exports.updateFilesFailed = updateFilesFailed;
|
|
136
|
+
// Checking cargo-near messages
|
|
137
|
+
const checkingCargoNear = () => (0, exports.show)((0, chalk_1.default) `- Checking if cargo-near extension is installed...`);
|
|
138
|
+
exports.checkingCargoNear = checkingCargoNear;
|
|
139
|
+
const cargoNearIsNotInstalled = () => (0, exports.show)((0, chalk_1.default) ` {bold {yellow Did not find cargo-near, please install it to build and deploy Rust contracts: https://github.com/near/cargo-near}}`);
|
|
140
|
+
exports.cargoNearIsNotInstalled = cargoNearIsNotInstalled;
|
|
102
141
|
//# sourceMappingURL=messages.js.map
|
package/dist/tracking.js
CHANGED
|
@@ -45,7 +45,7 @@ const trackUsage = async (frontend, contract) => {
|
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
47
|
catch (e) {
|
|
48
|
-
console.error('Warning: problem while sending tracking data
|
|
48
|
+
console.error(' Warning: problem while sending tracking data\n');
|
|
49
49
|
}
|
|
50
50
|
};
|
|
51
51
|
exports.trackUsage = trackUsage;
|
package/dist/types.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.APPS = exports.FRONTENDS = exports.CONTRACTS = void 0;
|
|
4
|
-
exports.CONTRACTS = ['ts', 'rs', 'none'];
|
|
4
|
+
exports.CONTRACTS = ['ts', 'rs', 'py', 'none'];
|
|
5
5
|
exports.FRONTENDS = ['next-app', 'next-page', 'vite-react', 'none'];
|
|
6
6
|
exports.APPS = ['contract', 'gateway'];
|
|
7
7
|
//# sourceMappingURL=types.js.map
|
package/dist/user-input.js
CHANGED
|
@@ -57,6 +57,7 @@ const appChoices = [
|
|
|
57
57
|
const contractChoices = [
|
|
58
58
|
{ title: 'JS/TS Contract', description: 'A Near contract written in javascript/typescript', value: 'ts' },
|
|
59
59
|
{ title: 'Rust Contract', description: 'A Near contract written in Rust', value: 'rs' },
|
|
60
|
+
{ title: 'Python Contract', description: 'A Near contract written in Python', value: 'py' },
|
|
60
61
|
];
|
|
61
62
|
const frontendChoices = [
|
|
62
63
|
{ title: 'NextJs (Classic)', description: 'A web-app built using Next.js Page Router', value: 'next-page' },
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const { execSync } = require('child_process');
|
|
4
|
+
function isCargoNearInstalled() {
|
|
5
|
+
try {
|
|
6
|
+
// execute but hide output
|
|
7
|
+
execSync('cargo near --version', { stdio: 'ignore' });
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
exports.default = isCargoNearInstalled;
|
|
15
|
+
//# sourceMappingURL=checkCargoNear.js.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const https_1 = __importDefault(require("https"));
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const stream_1 = require("stream");
|
|
9
|
+
const util_1 = require("util");
|
|
10
|
+
const streamPipeline = (0, util_1.promisify)(stream_1.pipeline);
|
|
11
|
+
async function downloadFile(url, destination) {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
https_1.default.get(url, (response) => {
|
|
14
|
+
if (response.statusCode !== 200) {
|
|
15
|
+
reject(new Error(`Downloading failed: ${response.statusCode}`));
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
streamPipeline(response, fs_1.default.createWriteStream(destination))
|
|
19
|
+
.then(resolve)
|
|
20
|
+
.catch(reject);
|
|
21
|
+
}).on('error', reject);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
exports.default = downloadFile;
|
|
25
|
+
//# sourceMappingURL=donwloadFile.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.isCargoNearInstalled = exports.downloadFile = void 0;
|
|
7
|
+
const donwloadFile_1 = __importDefault(require("./donwloadFile"));
|
|
8
|
+
exports.downloadFile = donwloadFile_1.default;
|
|
9
|
+
const checkCargoNear_1 = __importDefault(require("./checkCargoNear"));
|
|
10
|
+
exports.isCargoNearInstalled = checkCargoNear_1.default;
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# contract-py
|
|
2
|
+
|
|
3
|
+
cargo-near-new-project-description
|
|
4
|
+
|
|
5
|
+
## How to Build Locally?
|
|
6
|
+
|
|
7
|
+
Install Python and Emscripten:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Install Python (if not already installed)
|
|
11
|
+
# Use your system's package manager or download from https://www.python.org/downloads/
|
|
12
|
+
|
|
13
|
+
# Install Emscripten (required for compiling Python contracts to WebAssembly)
|
|
14
|
+
# For Linux/macOS:
|
|
15
|
+
git clone https://github.com/emscripten-core/emsdk.git
|
|
16
|
+
cd emsdk
|
|
17
|
+
./emsdk install latest
|
|
18
|
+
./emsdk activate latest
|
|
19
|
+
source ./emsdk_env.sh
|
|
20
|
+
# Add to your .bashrc or .zshrc for permanent installation:
|
|
21
|
+
# echo 'source "/path/to/emsdk/emsdk_env.sh"' >> ~/.bashrc
|
|
22
|
+
cd ..
|
|
23
|
+
|
|
24
|
+
# For Windows:
|
|
25
|
+
# Download and extract: https://github.com/emscripten-core/emsdk
|
|
26
|
+
# Then in Command Prompt:
|
|
27
|
+
# cd emsdk
|
|
28
|
+
# emsdk install latest
|
|
29
|
+
# emsdk activate latest
|
|
30
|
+
# emsdk_env.bat
|
|
31
|
+
|
|
32
|
+
# Verify installation with:
|
|
33
|
+
emcc --version
|
|
34
|
+
|
|
35
|
+
# Install uv for Python package management
|
|
36
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
37
|
+
|
|
38
|
+
# Install NEAR CLI-RS to deploy and interact with the contract
|
|
39
|
+
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/near/near-cli-rs/releases/latest/download/near-cli-rs-installer.sh | sh
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Then run:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
uvx nearc greeting_contract.py
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## How to Test Locally?
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
uv run pytest
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## How to Deploy?
|
|
55
|
+
|
|
56
|
+
To deploy manually, install [`cargo-near`](https://github.com/near/cargo-near) and run:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# Create a new account
|
|
60
|
+
cargo near create-dev-account
|
|
61
|
+
|
|
62
|
+
# Deploy the contract on it
|
|
63
|
+
cargo near deploy <account-id>
|
|
64
|
+
```
|
|
65
|
+
## Useful Links
|
|
66
|
+
|
|
67
|
+
- [cargo-near](https://github.com/near/cargo-near) - NEAR smart contract development toolkit for Rust
|
|
68
|
+
- [near CLI](https://near.cli.rs) - Iteract with NEAR blockchain from command line
|
|
69
|
+
- [NEAR Python SDK Documentation](https://github.com/r-near/near-sdk-py)
|
|
70
|
+
- [NEAR Documentation](https://docs.near.org)
|
|
71
|
+
- [NEAR StackOverflow](https://stackoverflow.com/questions/tagged/nearprotocol)
|
|
72
|
+
- [NEAR Discord](https://near.chat)
|
|
73
|
+
- [NEAR Telegram Developers Community Group](https://t.me/neardev)
|
|
74
|
+
- NEAR DevHub: [Telegram](https://t.me/neardevhub), [Twitter](https://twitter.com/neardevhub)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from near_sdk_py import Contract, view, call, init
|
|
2
|
+
|
|
3
|
+
class GreetingContract(Contract):
|
|
4
|
+
"""
|
|
5
|
+
A simple greeting contract that stores and returns a message.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
@init
|
|
9
|
+
def initialize(self, default_message="Hello, NEAR world!"):
|
|
10
|
+
"""
|
|
11
|
+
Initialize the contract with a default greeting message.
|
|
12
|
+
"""
|
|
13
|
+
self.storage["greeting"] = default_message
|
|
14
|
+
return {"success": True}
|
|
15
|
+
|
|
16
|
+
@call
|
|
17
|
+
def set_greeting(self, message: str):
|
|
18
|
+
"""
|
|
19
|
+
Change the greeting message.
|
|
20
|
+
"""
|
|
21
|
+
self.storage["greeting"] = message
|
|
22
|
+
self.log_info(f"Saving greeting: {message}")
|
|
23
|
+
return {"success": True}
|
|
24
|
+
|
|
25
|
+
@view
|
|
26
|
+
def get_greeting(self):
|
|
27
|
+
"""
|
|
28
|
+
Retrieve the current greeting message.
|
|
29
|
+
"""
|
|
30
|
+
return self.storage.get("greeting", "Hello, NEAR world!")
|
|
31
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from near_pytest.testing import NearTestCase
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
class TestGreetingContract(NearTestCase):
|
|
5
|
+
@classmethod
|
|
6
|
+
def setup_class(cls):
|
|
7
|
+
"""Compile and deploy the greeting contract."""
|
|
8
|
+
super().setup_class()
|
|
9
|
+
|
|
10
|
+
# Compile the contract
|
|
11
|
+
wasm_path = cls.compile_contract(
|
|
12
|
+
"contract.py",
|
|
13
|
+
single_file=True
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
# Deploy the contract
|
|
17
|
+
cls.contract_account = cls.create_account("contract")
|
|
18
|
+
cls.instance = cls.deploy_contract(cls.contract_account, wasm_path)
|
|
19
|
+
|
|
20
|
+
# Initialize the contract
|
|
21
|
+
cls.instance.call_as(
|
|
22
|
+
account=cls.contract_account,
|
|
23
|
+
method_name="initialize",
|
|
24
|
+
args={"default_message": "Initial greeting"},
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# Create test user
|
|
28
|
+
cls.user = cls.create_account("user")
|
|
29
|
+
|
|
30
|
+
# Save state for future resets
|
|
31
|
+
cls.save_state()
|
|
32
|
+
|
|
33
|
+
def setup_method(self):
|
|
34
|
+
"""Reset state before each test method."""
|
|
35
|
+
self.reset_state()
|
|
36
|
+
|
|
37
|
+
def test_greeting(self):
|
|
38
|
+
# Set greeting as user
|
|
39
|
+
result = self.instance.call_as(
|
|
40
|
+
account=self.user,
|
|
41
|
+
method_name="set_greeting",
|
|
42
|
+
args={"message": "Hello from test!"}
|
|
43
|
+
)
|
|
44
|
+
result = json.loads(result.text)
|
|
45
|
+
assert result["success"] == True
|
|
46
|
+
|
|
47
|
+
# Get greeting
|
|
48
|
+
greeting = self.instance.call_as(
|
|
49
|
+
account=self.user,
|
|
50
|
+
method_name="get_greeting"
|
|
51
|
+
)
|
|
52
|
+
assert greeting.text == "Hello from test!"
|
|
53
|
+
|