본문으로 건너뛰기

WebAssembly와 template pattern

이 기능은 web에서 Move bytecode serialization 및 deserialization을 가능하게 하기 위해 개발되었다. 본질적으로 web environment에서 existing contract를 edit할 수 있게 한다.

asset tokenization의 경우 이러한 edit을 통해 tokenize하려는 physical 또는 digital asset을 나타내는 새 type을 만들고 publish할 수 있다.

bytecode 조작

주의

template package를 수정하면 이 process를 반복해야 한다. constant name 변경 같은 일부 alteration은 생성된 bytecode에 영향을 주지 않는다.

이러한 edit을 수행하기 전에 library가 template module bytecode를 노출하는 방식을 이해해야 한다. 이 process는 현재 수동이다. compiled bytecode를 build하고 가져와야 한다. 이를 위해 template folder 안으로 이동해 다음 command를 실행한다:

$ xxd -c 0 -p build/template/bytecode_modules/template.mv | head -n 1
Click to open

console response

받는 response는 다음과 유사하다:

a11ceb0b060000000a010010021026033637046d0a05776807df01ec0108cb03800106cb043
e0a8905050c8e0549001303140107010d01120215021602170004020001000c01000101010c
010001020307000302070100000403070006050200070607000009000100010a0a0b0102021
2050700030c010401000311060401000418050800050e0601010c050f1001010c06100d0e00
070b050300030304030109060c070f02080007080600040b040108070b010108000b0201080
00b04010807010807010b04010900010a020109000108030108050108000809000308030805
08050b0401080701070806020b010109000b02010900010b02010800010608060105010b010
10800020900050841737365744361700d41737365744d65746164617461064f7074696f6e06
537472696e670854454d504c415445095478436f6e746578740355726c0561736369690b647
56d6d795f6669656c6404696e6974096e65775f6173736574156e65775f756e736166655f66
726f6d5f6279746573046e6f6e65066f7074696f6e137075626c69635f73686172655f6f626
a6563740f7075626c69635f7472616e736665720673656e64657204736f6d6506737472696e
670874656d706c6174650f746f6b656e697a65645f6173736574087472616e736665720a747
85f636f6e746578740375726c04757466380000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000100000000000000000000000000000000000000000000000000000000000000
02d9ebdef1e3cb5eb135362572b18faeb61259afe651a463f1384745ebd7fd51da030864000
000000000000a02070653796d626f6c0a0205044e616d650a020c0b4465736372697074696f
6e0a02090869636f6e5f75726c0101010a02010000020108010000000002230704070621040
738000c02050b0704110938010c020b020c050b0007000701110207021105070311050b0507
050a0138020c040c030b0438030b030b012e110838040200

받은 output을 bytecode-template.ts file 안의 getBytecode method return instruction에 paste한다.

template package는 두 module을 포함하므로 다른 dependency가 하나 더 있다. 따라서 genesis module의 bytecode도 비슷한 방식으로 가져와야 한다. 이 module bytecode는 edit되지 않고 그대로 사용된다. 이 operation은 WASM library와 직접 관련되지는 않지만, edited template module을 성공적으로 deploy하는 데 필요하다. genesis용 bytecode를 얻으려면 template folder로 이동해 다음을 실행한다:

$ xxd -c 0 -p build/template/bytecode_modules/genesis.mv | head -n 1

output format은 template module과 비슷하지만 길이가 더 짧다. 이 output을 copy하여 genesis_bytecode.ts file에 있는 bytecode constant variable에 paste한다.

위 setup을 마치면 library가 bytecode를 deserialize하고 edit한 뒤 다시 serialize하여 publish할 수 있다.

template module 자세히 보기

template module을 살펴보면 몇 가지 constant가 정의되어 있음을 볼 수 있다:

...
const TOTAL_SUPPLY: u64 = 100;
const SYMBOL: vector<u8> = b"Symbol";
const NAME: vector<u8> = b"Name";
const DESCRIPTION: vector<u8> = b"Description";
const ICON_URL: vector<u8> = b"icon_url";
const BURNABLE: bool = true;
...

이 constant들은 WASM library가 수정할 수 있는 reference point 역할을 한다. edit과 deploy를 수행하는 TypeScript code를 보면 이러한 field가 어떻게 식별되고 update되는지 확인할 수 있다:

...
const template = getBytecode();

const compiledModule = new CompiledModule(
JSON.parse(wasm.deserialize(template))
)
.updateConstant(0, totalSupply, "100", "u64")
.updateConstant(1, symbol, "Symbol", "string")
.updateConstant(2, asset_name, "Name", "string")
.updateConstant(3, description, "Description", "string")
.updateConstant(4, iconUrl, "icon_url", "string")
.updateConstant(5, burnable, "true", "bool")
.changeIdentifiers({
template: moduleName,
TEMPLATE: moduleName.toUpperCase(),
});

const bytesToPublish = wasm.serialize(JSON.stringify(compiledModule));
...

updateConstant method는 constant를 update하며 네 argument를 받는다:

  • idx (index): declared constant가 constant pool에서 갖는 position이다. 순서는 Move file에서 정의된 첫 constant의 0부터 시작해 각 consecutive constant마다 1씩 증가한다.
  • value: 변경하려는 constant의 updated value이다.
  • expectedValue: constant의 current value이다.
  • expectedType: constant의 current type이다.

이 library는 compiled bytecode를 직접 조작하므로, 실수로 잘못된 constant를 update할 risk를 최소화하기 위해 마지막 두 argument가 필요하다.

changeIdentifiers method는 identifier를 update하며, 이 경우 module name과 struct name이 대상이다. 이 method는 module 안의 current identifier name을 key로, 바꾸려는 desired name을 value로 갖는 JSON object를 argument로 받는다.

변경된 template module을 deploy하려면 build하고 publish한다:

...
const tx = new Transaction();
tx.setGasBudget(100000000);
const [upgradeCap] = tx.publish({
modules: [[...fromHex(bytesToPublish)], [...fromHex(genesis_bytecode)]],
dependencies: [
normalizeSuiObjectId("0x1"),
normalizeSuiObjectId("0x2"),
normalizeSuiObjectId(packageId),
],
});

tx.transferObjects(
[upgradeCap],
tx.pure(signer.getPublicKey().toSuiAddress(), "address")
);
...

bytecode 조작 section에서 언급했듯이 publish해야 하는 module은 template과 genesis이므로 modules array에는 2개의 element가 있다. 관련 package의 Move.toml file에 정의된 모든 dependency를 포함하는 것도 중요하다. 사용되는 packageIdasset_tokenization package가 deploy된 address이다.