Skip to content

Commit

Permalink
Example of programmatic update of JS Smart Contract (#287)
Browse files Browse the repository at this point in the history
* Example of programmatic update of JS Smart Contract

Co-authored-by: Serhii Volovyk <SergeyVolovyk@gmail.com>
  • Loading branch information
nsejim and volovyks authored Nov 22, 2022
1 parent 852bf34 commit e90d9bf
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 0 deletions.
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);
}

0 comments on commit e90d9bf

Please sign in to comment.