Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example of programmatic update of JS Smart Contract #287

Merged
merged 6 commits into from
Nov 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,5 @@ jobs:
run: cd examples && yarn build:parking-lot && yarn test:parking-lot
- name: standard nft
run: cd examples && yarn build-nft && yarn test:nft
- name: programmatic-update
run: cd examples && yarn build:programmatic-update && yarn test:programmatic-update
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ There are a couple of contract examples in the project:
- [Non fungible token receiver contract](https://github.com/near/near-sdk-js/tree/develop/examples/src/non-fungible-token-receiver.js)
- [Status message board](https://github.com/near/near-sdk-js/tree/develop/examples/src/status-message.js)
- [Status message board with unique messages](https://github.com/near/near-sdk-js/tree/develop/examples/src/status-message-collections.js)
- [Programmatic Update After Locking The Contract](https://github.com/near/near-sdk-js/tree/develop/examples/src/programmatic-update.js)

To build all examples, run `yarn build` in `examples/`. To test all examples, run `yarn test`. You can also build and test one specific example with `yarn build:<example-name>` and `yarn test:<example-name>`, see `examples/package.json`.

Expand Down
49 changes: 49 additions & 0 deletions examples/__tests__/test-programmatic-update.ava.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Worker } from "near-workspaces";
import test from "ava";
import * as fs from "fs";
import * as path from "path";

test.beforeEach(async (t) => {
const worker = await Worker.init();
const root = worker.rootAccount;

const ali = await root.createSubAccount("ali");

const contract = await root.devDeploy(
"build/programmatic-update-before.wasm"
);

await contract.call(contract, "init", { manager: ali.accountId });

t.context.worker = worker;
t.context.accounts = { root, contract, ali };
});

test.afterEach.always(async (t) => {
await t.context.worker.tearDown().catch((error) => {
console.log("Failed to tear down the worker:", error);
});
});

test("the contract can be programmatically updated", async (t) => {
const { ali, contract } = t.context.accounts;

// ASSERT BEFORE CODE UPDATE
const codeBefore = await contract.viewCodeRaw();
const beforeDefaultGreeting = await contract.view("get_greeting", {});
t.is(beforeDefaultGreeting, "Hello");

// ACT (UPDATE CODE)
const code = fs.readFileSync(
path.resolve("./build/programmatic-update-after.wasm")
);
await ali.call(contract, "updateContract", code, {
gas: "300" + "0".repeat(12), // 300 Tgas
});

// ASSERT AFTER CODE UPDATE
const codeAfter = await contract.viewCodeRaw();
const afterDefaultGreeting = await contract.view("view_greeting", {});
t.not(codeBefore, codeAfter, "code should be different after update");
t.is(afterDefaultGreeting, "Hi");
});
2 changes: 2 additions & 0 deletions examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"build:non-fungible-token": "near-sdk-js build src/non-fungible-token-receiver.js build/non-fungible-token-receiver.wasm && near-sdk-js build src/non-fungible-token.js build/non-fungible-token.wasm",
"build:status-message-collections": "near-sdk-js build src/status-message-collections.js build/status-message-collections.wasm",
"build:parking-lot": "near-sdk-js build src/parking-lot.ts build/parking-lot.wasm",
"build:programmatic-update": "near-sdk-js build src/programmatic-update-before.ts build/programmatic-update-before.wasm && near-sdk-js build src/programmatic-update-after.ts build/programmatic-update-after.wasm",
"build:nested-collections": "near-sdk-js build src/nested-collections.ts build/nested-collections.wasm",
"build-nft": "run-s build:nft-*",
"build:nft-contract": "near-sdk-js build src/standard-nft/my-nft.ts build/my-nft.wasm",
Expand All @@ -36,6 +37,7 @@
"test:non-fungible-token": "ava __tests__/test-non-fungible-token.ava.js",
"test:status-message-collections": "ava __tests__/test-status-message-collections.ava.js",
"test:parking-lot": "ava __tests__/test-parking-lot.ava.js",
"test:programmatic-update": "ava __tests__/test-programmatic-update.ava.js",
"test:nested-collections": "ava __tests__/test-nested-collections.ava.js"
},
"author": "Near Inc <hello@nearprotocol.com>",
Expand Down
30 changes: 30 additions & 0 deletions examples/src/programmatic-update-after.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { NearBindgen, near, initialize, assert, view } from "near-sdk-js";

@NearBindgen({ requireInit: true })
export class ProgrammaticUpdateAfter {
greeting = "Hello";

@initialize({ privateFunction: true })
init({ manager }: { manager: string }) {
near.log(`Setting manager to be ${manager}`);
near.storageWrite("MANAGER", manager);
}

@view({}) // Method renamed and return "Hi" when greeting is "Hello"
view_greeting(): string {
return this.greeting.replace("Hello", "Hi");
}
}

export function updateContract() {
const manager = near.storageRead("MANAGER");
assert(
near.predecessorAccountId() === manager,
"Only the manager can update the code"
);

const promiseId = near.promiseBatchCreate(near.currentAccountId());
near.promiseBatchActionDeployContract(promiseId, near.input());

return near.promiseReturn(promiseId);
}
30 changes: 30 additions & 0 deletions examples/src/programmatic-update-before.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { NearBindgen, near, initialize, assert, view } from "near-sdk-js";

@NearBindgen({ requireInit: true })
export class ProgrammaticUpdateBefore {
greeting = "Hello";

@initialize({ privateFunction: true })
init({ manager }: { manager: string }) {
near.log(`Setting manager to be ${manager}`);
near.storageWrite("MANAGER", manager);
}

@view({}) // This method will be renamed after update and will return "Hi" if greeting is "Hello"
get_greeting(): string {
return this.greeting;
}
}

export function updateContract() {
const manager = near.storageRead("MANAGER");
assert(
near.predecessorAccountId() === manager,
"Only the manager can update the code"
);

const promiseId = near.promiseBatchCreate(near.currentAccountId());
near.promiseBatchActionDeployContract(promiseId, near.input());

return near.promiseReturn(promiseId);
}