반응형
# Reference APIs
init (초기 값 설정)
let user: Opt<typeof User> = None;
let reaction: Opt<typeof Reaction> = None;
let owner: Opt<Principal> = None;
export default Canister({
init: init( [User, Reaction, Principal], (initUser, initReaction, initOwner) => {
user = Some(initUser);
reaction = Some(initReaction);
owner = Some(initOwner);
}
),
getUser: query([], Opt(User), () => {
return user;
}),
getReaction: query([], Opt(Reaction), () => {
return reaction;
}),
getOwner: query([], Opt(Principal), () => {
return owner;
}),
});
배포
dfx deploy {캐니스터명} --argument '(record { id = "0" }, variant { Fire }, principal "rrkah-fqaaa-aaaaa-aaaaq-cai")'
# arg data raw (아큐먼트를 바이트타입으로 변환하여 반환)
import { blob, bool, Canister, ic, int8, query, text } from 'azle';
export default Canister({
// returns the argument data as bytes.
argDataRaw: query(
[blob, int8, bool, text],
blob,
(arg1, arg2, arg3, arg4) => {
return ic.argDataRaw();
}
),
argDataRawSize: query(
[blob, int8, bool, text],
nat,
(arg1, arg2, arg3, arg4) => {
return ic.argDataRawSize();
}
)
});
# cross canister
코드
- index.ts
import { Canister, ic, Principal, query, Record, text, update, Vec } from 'azle';
import SubCanister from './sub';
const Wrapper = Record({
sub : SubCanister
});
export default Canister({
canisterParam: query([SubCanister ], SubCanister , (sub) => {
return sub ;
}),
canisterReturnType: query([], SubCanister , () => {
return SubCanister (
Principal.fromText(
process.env.SOME_CANISTER_PRINCIPAL ??
ic.trap('process.env.SOME_CANISTER_PRINCIPAL is undefined')
)
);
}),
canisterNestedReturnType: update([], Wrapper, () => {
return {
sub : SubCanister (
Principal.fromText(
process.env.SOME_CANISTER_PRINCIPAL ??
ic.trap(
'process.env.SOME_CANISTER_PRINCIPAL is undefined'
)
)
)
};
}),
canisterList: update([Vec(SubCanister )], Vec(SubCanister ), (sub ) => {
return sub ;
}
),
crossUpdate: update([SubCanister ], text, async (sub ) => {
return await ic.call(sub.update1);
},
crossQuery: query( [SubCanister], bool, async (sub) => {
return await ic.call(sub.query1);
}
),
});
sub.ts
import { bool, Canister, query, text, update } from 'azle';
export default Canister({
query1: query([], bool, () => {
return true;
}),
update1: update([], text, () => {
return 'SomeCanister update1';
})
});
sub 캐니스터 생성을 진행
sub 캐니스터 생성을 진행
파일 구성 확인
index.did
service: () -> {
canisterCrossCanisterCall: (service {query1: () -> (bool) query; update1: () -> (text);}) -> (bool) query;
canisterList: (vec service {query1: () -> (bool) query; update1: () -> (text);}) -> (vec service {query1: () -> (bool) query; update1: () -> (text);});
canisterNestedReturnType: () -> (record {subCanister:service {query1: () -> (bool) query; update1: () -> (text);}});
canisterParam: (service {query1: () -> (bool) query; update1: () -> (text);}) -> (service {query1: () -> (bool) query; update1: () -> (text);}) query;
canisterReturnType: () -> (service {query1: () -> (bool) query; update1: () -> (text);}) query;
}
sub.did
service: () -> {
query1: () -> (bool) query;
update1: () -> (text);
}
dfx.json
{
"canisters": {
"{메인-캐니스터}": {
"type": "custom",
"main": "src/index.ts",
"candid": "src/index.did",
"build": "npx azle types",
"wasm": ".azle/types/types.wasm",
"gzip": true,
"declarations": {
"output": "temp/dfx_generated/types",
"node_compatibility": true
},
"env": ["SUB_PRINCIPAL"]
},
"sub" : {
"type": "custom",
"main": "src/sub.ts",
"candid": "src/sub.did",
"build": "npx azle sub",
"wasm": ".azle/sub/sub.wasm",
"gzip": true,
"declarations": {
"output": "temp/dfx_generated/sub",
"node_compatibility": true
}
}
}
}
배포
- 메인 캐니스터 배포
npx azle {메인-캐니스터}
- sub 캐니스터 배포 - 프로젝트 폴더내 .azle 구성을 먼저 진행해야함 배포 진행 dfx.json의 env 변수를 위해 - 위 sub 캐니스터의 id 입력
SUB_PRINCIPAL="{sub 캐니스터 입력}" dfx deploy
# candid UI - 브라우저 확인
결과 확인
Candid UI상 서비스 객채가 파라메터로 들어 가는 경우, 인코딩의 오류로 dfx로 결과확인이 간편
- canisterList 호출
- canisterParam 호출
- crossQuery 호출
- crossUpdate 호출
call
import { Canister, ic, init, nat64, Principal, update } from 'azle';
const TokenCanister = Canister({
transfer: update([Principal, nat64], nat64)
});
let tokenCanister: typeof TokenCanister;
export default Canister({
init: init([], setup),
postDeploy: init([], setup),
payout: update([Principal, nat64], nat64, async (to, amount) => {
return await ic.call(tokenCanister.transfer, {
args: [to, amount]
});
}),
executeCallRaw: update(
[Principal, text, text, nat64],
text,
async (canisterId, method, candidArgs, payment) => {
const candidBytes = await ic.callRaw(
canisterId,
method,
ic.candidEncode(candidArgs),
payment
);
return ic.candidDecode(candidBytes);
}
),
executeInstallCode: update(
[Principal, blob],
Void,
async (canisterId, wasmModule) => {
return await ic.call(managementCanister.install_code, {
args: [
{
mode: { install: null },
canister_id: canisterId,
wasm_module: wasmModule,
arg: Uint8Array.from([])
}
],
cycles: 100_000_000_000n
});
}
),
});
function setup() {
tokenCanister = TokenCanister(
Principal.fromText('r7inp-6aaaa-aaaaa-aaabq-cai')
);
}
caller
import { Canister, ic, Principal, update } from 'azle';
export default Canister({
// returns the principal of the identity that called this function
caller: update([], Principal, () => {
return ic.caller();
})
});
# 캐니스터 메소드
heartbeat
import { Canister, heartbeat } from 'azle';
export default Canister({
heartbeat: heartbeat(() => {
console.log('this runs ~1 time per second');
})
});
http
import { blob, bool, Canister, Func, nat16, None, Opt, query, Record,
text, Tuple, Variant, Vec } from 'azle';
const Token = Record({
// add whatever fields you'd like
arbitrary_data: text
});
const StreamingCallbackHttpResponse = Record({
body: blob,
token: Opt(Token)
});
export const Callback = Func([text], StreamingCallbackHttpResponse, 'query');
const CallbackStrategy = Record({
callback: Callback,
token: Token
});
const StreamingStrategy = Variant({
Callback: CallbackStrategy
});
type HeaderField = [text, text];
const HeaderField = Tuple(text, text);
const HttpResponse = Record({
status_code: nat16,
headers: Vec(HeaderField),
body: blob,
streaming_strategy: Opt(StreamingStrategy),
upgrade: Opt(bool)
});
const HttpRequest = Record({
method: text,
url: text,
headers: Vec(HeaderField),
body: blob,
certificate_version: Opt(nat16)
});
export default Canister({
http_request: query([HttpRequest], HttpResponse, (req) => {
return {
status_code: 200,
headers: [],
body: Buffer.from('hello'),
streaming_strategy: None,
upgrade: None
};
}),
http_request_update: update([HttpRequest], HttpResponse, (req) => {
return {
status_code: 200,
headers: [],
body: Buffer.from('hello'),
streaming_strategy: None,
upgrade: None
};
})
});
post upgrade
import { Canister, postUpgrade } from 'azle';
export default Canister({
postUpgrade: postUpgrade([], () => {
console.log('This runs after every canister upgrade');
})
});
# 캐니스터 메니지먼트
canister_status
import { Canister, ic, update } from 'azle';
import { CanisterStatusArgs, CanisterStatusResult, managementCanister
} from 'azle/canisters/management';
export default Canister({
getCanisterStatus: update([CanisterStatusArgs], CanisterStatusResult, async (args) => {
return await ic.call(managementCanister.canister_status, {
args: [args]
});
}
)
});
create_canister
import { Canister, ic, None, update } from 'azle';
import {
CreateCanisterResult,
managementCanister
} from 'azle/canisters/management';
export default Canister({
executeCreateCanister: update([], CreateCanisterResult, async () => {
return await ic.call(managementCanister.create_canister, {
args: [{ settings: None }],
cycles: 50_000_000_000_000n
});
})
});
deposit_cycles
import { bool, Canister, ic, Principal, update } from 'azle';
import { managementCanister } from 'azle/canisters/management';
export default Canister({
executeDepositCycles: update([Principal], bool, async (canisterId) => {
await ic.call(managementCanister.deposit_cycles, {
args: [
{
canister_id: canisterId
}
],
cycles: 10_000_000n
});
return true;
})
});
start
import { bool, Canister, ic, Principal, update } from 'azle';
import { managementCanister } from 'azle/canisters/management';
export default Canister({
executeStartCanister: update([Principal], bool, async (canisterId) => {
await ic.call(managementCanister.start_canister, {
args: [
{
canister_id: canisterId
}
]
});
return true;
})
});
Stop
import { bool, Canister, ic, Principal, update } from 'azle';
import { managementCanister } from 'azle/canisters/management';
export default Canister({
executeStopCanister: update([Principal], bool, async (canisterId) => {
await ic.call(managementCanister.stop_canister, {
args: [
{
canister_id: canisterId
}
]
});
return true;
})
});
delete_canister
import { bool, Canister, ic, Principal, update } from 'azle';
import { managementCanister } from 'azle/canisters/management';
export default Canister({
executeDeleteCanister: update([Principal], bool, async (canisterId) => {
await ic.call(managementCanister.delete_canister, {
args: [
{
canister_id: canisterId
}
]
});
return true;
})
});
ecdsa_public_key
import { blob, Canister, ic, None, Record, update } from 'azle';
import { managementCanister } from 'azle/canisters/management';
const PublicKey = Record({
publicKey: blob
});
export default Canister({
publicKey: update([], PublicKey, async () => {
const caller = ic.caller().toUint8Array();
const publicKeyResult = await ic.call(
managementCanister.ecdsa_public_key,
{
args: [
{
canister_id: None,
derivation_path: [caller],
key_id: {
curve: { secp256k1: null },
name: 'dfx_test_key'
}
}
]
}
);
return {
publicKey: publicKeyResult.public_key
};
})
});
http_request
import { Canister, ic, None, Principal, query, Some, update } from 'azle';
import {
HttpResponse,
HttpTransformArgs,
managementCanister
} from 'azle/canisters/management';
export default Canister({
xkcd: update([], HttpResponse, async () => {
return await ic.call(managementCanister.http_request, {
args: [
{
url: `https://xkcd.com/642/info.0.json`,
max_response_bytes: Some(2_000n),
method: {
get: null
},
headers: [],
body: None,
transform: Some({
function: [ic.id(), 'xkcdTransform'] as [
Principal,
string
],
context: Uint8Array.from([])
})
}
],
cycles: 50_000_000n
});
}),
xkcdTransform: query([HttpTransformArgs], HttpResponse, (args) => {
return {
...args.response,
headers: []
};
})
});
raw_rand
import { blob, Canister, ic, update } from 'azle';
import { managementCanister } from 'azle/canisters/management';
export default Canister({
getRawRand: update([], blob, async () => {
return await ic.call(managementCanister.raw_rand);
})
});
update setting
import { bool, Canister, ic, None, Principal, Some, update } from 'azle';
import { managementCanister } from 'azle/canisters/management';
export default Canister({
executeUpdateSettings: update([Principal], bool, async (canisterId) => {
await ic.call(managementCanister.update_settings, {
args: [
{
canister_id: canisterId,
settings: {
controllers: None,
compute_allocation: Some(1n),
memory_allocation: Some(3_000_000n),
freezing_threshold: Some(2_000_000n)
}
}
]
});
return true;
})
});
# 메모리
structures
import { bool, Canister, nat64, nat8, Opt, query, StableBTreeMap, text, Tuple,
update, Vec } from 'azle';
const Key = nat8;
const Value = text;
let map = StableBTreeMap(Key, Value, 0);
export default Canister({
containsKey: query([Key], bool, (key) => {
return map.containsKey(key);
}),
get: query([Key], Opt(Value), (key) => {
return map.get(key);
}),
mapInsert: update([Key, Value], Opt(Value), (key, value) => {
return map.insert(key, value);
}),
isEmpty: query([], bool, () => {
return map.isEmpty();
}),
items: query([], Vec(Tuple(Key, Value)), () => {
return map.items();
}),
keys: query([], Vec(Key), () => {
return map.keys();
}),
len: query([], nat64, () => {
return map.len();
}),
mapRemove: update([Key], Opt(Value), (key) => {
return map.remove(key);
}),
values: query([], Vec(Value), () => {
return map.values();
})
});
bytes
import { blob, Canister, ic, query } from 'azle';
export default Canister({
stableBytes: query([], blob, () => {
return ic.stableBytes();
})
});
grow
import { Canister, ic, nat32, update } from 'azle';
export default Canister({
stableGrow: update([nat32], nat32, (newPages) => {
return ic.stableGrow(newPages);
}),
stable64Grow: update([nat64], nat64, (newPages) => {
return ic.stable64Grow(newPages);
})
});
read
import { blob, Canister, ic, nat32, query } from 'azle';
export default Canister({
stableRead: query([nat32, nat32], blob, (offset, length) => {
return ic.stableRead(offset, length);
}),
stable64Read: query([nat64, nat64], blob, (offset, length) => {
return ic.stable64Read(offset, length);
})
});
size
import { Canister, ic, nat32, query } from 'azle';
export default Canister({
stableSize: query([], nat32, () => {
return ic.stableSize();
}),
stable64Size: query([], nat64, () => {
return ic.stable64Size();
})
});
write
import { blob, Canister, ic, nat32, update, Void } from 'azle';
export default Canister({
stableWrite: update([nat32, blob], Void, (offset, buf) => {
ic.stableWrite(offset, buf);
}),
stable64Write: update([nat64, blob], Void, (offset, buf) => {
ic.stable64Write(offset, buf);
})
});
# Timer
import { Canister, ic, TimerId, update, Void } from 'azle';
export default Canister({
clearTimer: update([TimerId], Void, (timerId) => {
ic.clearTimer(timerId);
}),
setTimers: update([Duration], Tuple(TimerId, TimerId), (delay) => {
const functionTimerId = ic.setTimer(delay, callback);
const capturedValue = '🚩';
const closureTimerId = ic.setTimer(delay, () => {
console.log(`closure called and captured value ${capturedValue}`);
});
return [functionTimerId, closureTimerId];
}),
setTimerIntervals: update(
[Duration],
Tuple(TimerId, TimerId),
(interval) => {
const functionTimerId = ic.setTimerInterval(interval, callback);
const capturedValue = '🚩';
const closureTimerId = ic.setTimerInterval(interval, () => {
console.log(
`closure called and captured value ${capturedValue}`
);
});
return [functionTimerId, closureTimerId];
}
),
});
function callback() {
console.log('callback called');
}
반응형
'신기술분석 > 블록체인' 카테고리의 다른 글
메타마스크 연동 가능 블록체인 List (0) | 2024.08.31 |
---|---|
ICP 실습 #2 (0) | 2023.10.23 |
ICP 실습 #1 (1) | 2023.10.21 |
우분투 Geth 설치 하기 (1) | 2022.06.12 |
Pinata IPFS 서비스 (0) | 2022.06.12 |
댓글