From 963d4fcf66a734554badbb5c97d1f1cf9ce53d3f Mon Sep 17 00:00:00 2001 From: Quint Daenen Date: Fri, 22 Mar 2024 14:12:55 +0100 Subject: [PATCH] Move ecid to agent. --- agent.go | 29 ++ agent_test.go | 70 +++- candid/idl/variant.go | 14 +- go.mod | 6 +- go.sum | 8 +- ic/ic/actor.mo | 88 ++++ {mgmt => ic/ic}/agent.go | 151 +++++-- ic/ic/agent_test.go | 860 +++++++++++++++++++++++++++++++++++++++ ic/ic/types.mo | 64 +++ ic/ids.go | 2 + ic/testdata/gen.go | 2 - identity/anonymous.go | 2 + identity/ed25519.go | 5 +- identity/prime256v1.go | 9 + identity/secp256k1.go | 33 +- request.go | 6 +- 16 files changed, 1288 insertions(+), 61 deletions(-) create mode 100755 ic/ic/actor.mo rename {mgmt => ic/ic}/agent.go (87%) create mode 100755 ic/ic/agent_test.go create mode 100755 ic/ic/types.mo diff --git a/agent.go b/agent.go index 71f7067..e17d71b 100644 --- a/agent.go +++ b/agent.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "fmt" "net/url" + "reflect" "time" "github.com/aviate-labs/agent-go/candid/idl" @@ -25,6 +26,32 @@ var DefaultConfig = Config{} // icp0 is the default host for the Internet Computer. var icp0, _ = url.Parse("https://icp0.io/") +func effectiveCanisterID(canisterId principal.Principal, args []any) principal.Principal { + // If the canisterId is not aaaaa-aa, return it. + if len(canisterId.Raw) > 0 || len(args) == 0 { + return canisterId + } + + v := reflect.ValueOf(args[0]) + if v.Kind() == reflect.Struct { + t := v.Type() + // Get the field with the ic tag "canister_id". + for idx := range t.NumField() { + if tag := t.Field(idx).Tag.Get("ic"); tag == "canister_id" { + ecid := v.Field(idx).Interface() + switch ecid := ecid.(type) { + case principal.Principal: + return ecid + default: + // If the field is not a principal, return the original canisterId. + return canisterId + } + } + } + } + return canisterId +} + func uint64FromBytes(raw []byte) uint64 { switch len(raw) { case 1: @@ -108,6 +135,7 @@ func (a Agent) Call(canisterID principal.Principal, methodName string, args []an if err != nil { return err } + canisterID = effectiveCanisterID(canisterID, args) a.logger.Printf("[AGENT] CALL %s %s", canisterID, methodName) if _, err := a.call(canisterID, data); err != nil { return err @@ -208,6 +236,7 @@ func (a Agent) Query(canisterID principal.Principal, methodName string, args []a if err != nil { return err } + canisterID = effectiveCanisterID(canisterID, args) a.logger.Printf("[AGENT] QUERY %s %s", canisterID, methodName) resp, err := a.query(canisterID, data) if err != nil { diff --git a/agent_test.go b/agent_test.go index fbbb528..37f2068 100644 --- a/agent_test.go +++ b/agent_test.go @@ -6,13 +6,15 @@ import ( "github.com/aviate-labs/agent-go" "github.com/aviate-labs/agent-go/candid/idl" "github.com/aviate-labs/agent-go/ic" + mgmt "github.com/aviate-labs/agent-go/ic/ic" "github.com/aviate-labs/agent-go/ic/icpledger" "github.com/aviate-labs/agent-go/identity" - "github.com/aviate-labs/agent-go/mgmt" "github.com/aviate-labs/agent-go/principal" "testing" ) +var _ = new(testLogger) + func Example_anonymous_query() { a, _ := agent.New(agent.DefaultConfig) type Account struct { @@ -96,10 +98,8 @@ func Example_query_secp256k1() { // 0 } -func TestAgent_Call(t *testing.T) { - a, err := mgmt.NewAgent(agent.Config{ - Logger: &testLogger{}, - }) +func TestAgent_Call_bitcoinGetBalanceQuery(t *testing.T) { + a, err := mgmt.NewAgent(ic.MANAGEMENT_CANISTER_PRINCIPAL, agent.DefaultConfig) if err != nil { t.Fatal(err) } @@ -112,7 +112,63 @@ func TestAgent_Call(t *testing.T) { if err != nil { t.Fatal(err) } - fmt.Println(r) + if r == nil { + t.Fatal() + } +} + +func TestAgent_Call_provisionalTopUpCanister(t *testing.T) { + a, err := mgmt.NewAgent(ic.MANAGEMENT_CANISTER_PRINCIPAL, agent.DefaultConfig) + if err != nil { + t.Fatal(err) + } + if err := a.ProvisionalTopUpCanister(mgmt.ProvisionalTopUpCanisterArgs{ + CanisterId: ic.LEDGER_PRINCIPAL, + }); err == nil { + t.Fatal() + } +} + +func TestAgent_Query_Ed25519(t *testing.T) { + id, err := identity.NewRandomEd25519Identity() + if err != nil { + t.Fatal(err) + } + a, _ := agent.New(agent.Config{ + Identity: id, + }) + type Account struct { + Account string `ic:"account"` + } + var balance struct { + E8S uint64 `ic:"e8s"` + } + if err := a.Query(ic.LEDGER_PRINCIPAL, "account_balance_dfx", []any{ + Account{"9523dc824aa062dcd9c91b98f4594ff9c6af661ac96747daef2090b7fe87037d"}, + }, []any{&balance}); err != nil { + t.Fatal(err) + } +} + +func TestAgent_Query_Secp256k1(t *testing.T) { + id, err := identity.NewRandomSecp256k1Identity() + if err != nil { + t.Fatal(err) + } + a, _ := agent.New(agent.Config{ + Identity: id, + }) + type Account struct { + Account string `ic:"account"` + } + var balance struct { + E8S uint64 `ic:"e8s"` + } + if err := a.Query(ic.LEDGER_PRINCIPAL, "account_balance_dfx", []any{ + Account{"9523dc824aa062dcd9c91b98f4594ff9c6af661ac96747daef2090b7fe87037d"}, + }, []any{&balance}); err != nil { + t.Fatal(err) + } } func TestICPLedger_queryBlocks(t *testing.T) { @@ -130,6 +186,6 @@ func TestICPLedger_queryBlocks(t *testing.T) { type testLogger struct{} -func (l *testLogger) Printf(format string, v ...interface{}) { +func (t testLogger) Printf(format string, v ...interface{}) { fmt.Printf("[TEST]"+format+"\n", v...) } diff --git a/candid/idl/variant.go b/candid/idl/variant.go index df5ae1e..666b6cd 100644 --- a/candid/idl/variant.go +++ b/candid/idl/variant.go @@ -210,16 +210,26 @@ func (variant VariantType) structToVariant(value any) (*Variant, error) { } tag := ParseTags(field) + if !tag.VariantType { + return nil, fmt.Errorf("invalid variant field: %s", v.Type()) + } if !v.Field(i).IsNil() { return &Variant{ Name: tag.Name, Value: v.Field(i).Elem().Interface(), }, nil } + if i == v.NumField()-1 { + return &Variant{ + Name: tag.Name, + Value: nil, + }, nil + } } + return nil, fmt.Errorf("invalid variant: %s", v.Type()) + default: + return nil, fmt.Errorf("invalid value kind: %s", v.Kind()) } - fmt.Printf("%#v\n", value) - return nil, fmt.Errorf("invalid value kind: %s", v.Kind()) } func (variant VariantType) unmarshalMap(name string, value any, _v *map[string]any) error { diff --git a/go.mod b/go.mod index c64ff17..7ad3e1d 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,13 @@ module github.com/aviate-labs/agent-go -go 1.21.0 +go 1.22.1 require ( github.com/aviate-labs/leb128 v0.3.0 github.com/aviate-labs/secp256k1 v0.0.0-5e6736a github.com/di-wu/parser v0.3.0 - github.com/fxamacker/cbor/v2 v2.5.0 - github.com/herumi/bls-go-binary v1.32.0 + github.com/fxamacker/cbor/v2 v2.6.0 + github.com/herumi/bls-go-binary v1.33.0 ) require github.com/x448/float16 v0.8.4 // indirect diff --git a/go.sum b/go.sum index a94b23b..9a67952 100644 --- a/go.sum +++ b/go.sum @@ -4,9 +4,9 @@ github.com/aviate-labs/secp256k1 v0.0.0-5e6736a h1:aQkG/D+l8Y7tr809l8pN+KebH2jza github.com/aviate-labs/secp256k1 v0.0.0-5e6736a/go.mod h1:C/lr3F9TimrVkdZckG5mz+VU0TrmpeyVKUjzv2YyGwA= github.com/di-wu/parser v0.3.0 h1:NMOvy5ifswgt4gsdhySVcKOQtvjC43cHZIfViWctqQY= github.com/di-wu/parser v0.3.0/go.mod h1:SLp58pW6WamdmznrVRrw2NTyn4wAvT9rrEFynKX7nYo= -github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE= -github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= -github.com/herumi/bls-go-binary v1.32.0 h1:QX0+mmrCyBNpaVwYahl85yWnxYKDPpNAPIZWOIpP+eU= -github.com/herumi/bls-go-binary v1.32.0/go.mod h1:O4Vp1AfR4raRGwFeQpr9X/PQtncEicMoOe6BQt1oX0Y= +github.com/fxamacker/cbor/v2 v2.6.0 h1:sU6J2usfADwWlYDAFhZBQ6TnLFBHxgesMrQfQgk1tWA= +github.com/fxamacker/cbor/v2 v2.6.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/herumi/bls-go-binary v1.33.0 h1:OJwWkXTsxF7SLHT8cBLJfb6i97KHfrG4DkgejLcDm78= +github.com/herumi/bls-go-binary v1.33.0/go.mod h1:O4Vp1AfR4raRGwFeQpr9X/PQtncEicMoOe6BQt1oX0Y= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= diff --git a/ic/ic/actor.mo b/ic/ic/actor.mo new file mode 100755 index 0000000..bfc672e --- /dev/null +++ b/ic/ic/actor.mo @@ -0,0 +1,88 @@ +// Do NOT edit this file. It was automatically generated by https://github.com/aviate-labs/agent-go. +import T "types"; + +import { principalOfBlob } = "mo:⛔"; + +actor class _ic() : async actor {} { + public shared func create_canister(_arg0 : T.CreateCanisterArgs) : async (T.CreateCanisterResult) { + ({ canister_id = principalOfBlob("x869AF7A6140D470862C22E5F4C779F515D2190E37D31EEC1BDFD5BBCE1B03FA0") }) + }; + public shared func update_settings(_arg0 : T.UpdateSettingsArgs) : async () { + () + }; + public shared func upload_chunk(_arg0 : T.UploadChunkArgs) : async (T.UploadChunkResult) { + ({ hash = "x869AF7A6140D470862C22E5F4C779F515D2190E37D31EEC1BDFD5BBCE1B03FA0" }) + }; + public shared func clear_chunk_store(_arg0 : T.ClearChunkStoreArgs) : async () { + () + }; + public shared func stored_chunks(_arg0 : T.StoredChunksArgs) : async (T.StoredChunksResult) { + ([ { hash = "x0862C22E5F4C779F515D2190E37D31EEC1BDFD5BBCE1B03FA00DA2FE1A254CA2" }, { hash = "x3D005FB6E22DF7BA41EBE7B21A1C13F932DE5C88E3F7CBBA21D83DB973446660" }, { hash = "x1A2AA3EF195DD53147822C629DF98B40FE3A93E721D185BD47D7EEE55135BB08" }, { hash = "x88544768FAFB19D706D81F6BD23CB10726A014187038BCE35CB2F3ECCB7DD75F" } ]) + }; + public shared func install_code(_arg0 : T.InstallCodeArgs) : async () { + () + }; + public shared func install_chunked_code(_arg0 : T.InstallChunkedCodeArgs) : async () { + () + }; + public shared func uninstall_code(_arg0 : T.UninstallCodeArgs) : async () { + () + }; + public shared func start_canister(_arg0 : T.StartCanisterArgs) : async () { + () + }; + public shared func stop_canister(_arg0 : T.StopCanisterArgs) : async () { + () + }; + public shared func canister_status(_arg0 : T.CanisterStatusArgs) : async (T.CanisterStatusResult) { + ({ status = #running; settings = { controllers = [ principalOfBlob("x9F515D2190E37D31EEC1BDFD5BBCE1B03FA00DA2FE1A254CA23FD9613D005FB6"), principalOfBlob("xBA41EBE7B21A1C13F932DE5C88E3F7CBBA21D83DB97344666081C6741A2AA3EF"), principalOfBlob("x3147822C629DF98B40FE3A93E721D185BD47D7EEE55135BB0860874988544768"), principalOfBlob("xD706D81F6BD23CB10726A014187038BCE35CB2F3ECCB7DD75F4647487E926B57"), principalOfBlob("x1AB600EF4AE294D7E2D2267FA77832A886DE6E4B72F4197FF183421A910092C0"), principalOfBlob("x472B7A3158CE1700CC21E6E714AF1108697FFC6D45094AEDFBE2A29AD1939D09"), principalOfBlob("x30190C629CD14D0FC80915A4320DA282A98A18083753F3DE7592A2198D6B99C8"), principalOfBlob("xEC8A4F529F93BB58C59A87D62A7717691617B8B442AFB32C31DF22DF57966FEA") ]; compute_allocation = 7181374305377412901; memory_allocation = 8483647216729911020; freezing_threshold = 14994143942249040469; reserved_cycles_limit = 14039119793643782529 }; module_hash = ?"xB34811D335EB789A5543731482481F165AAA1560662B8E9D514E23991BA4248F"; memory_size = 16803621580220603980; cycles = 9736605414087480391; reserved_cycles = 14670472641987634058; idle_cycles_burned_per_day = 2674853784875525116 }) + }; + public shared func canister_info(_arg0 : T.CanisterInfoArgs) : async (T.CanisterInfoResult) { + ({ total_num_changes = 15656497011928570502; recent_changes = [ { timestamp_nanos = 14519010981886906783; canister_version = 3800013330962312753; origin = #from_canister({ canister_id = principalOfBlob("x1A254CA23FD9613D005FB6E22DF7BA41EBE7B21A1C13F932DE5C88E3F7CBBA21"); canister_version = ?13363524253285500019 }); details = #code_deployment({ mode = #install; module_hash = "x8B40FE3A93E721D185BD47D7EEE55135BB0860874988544768FAFB19D706D81F" }) }, { timestamp_nanos = 18045950183738836913; canister_version = 5831303564926106680; origin = #from_canister({ canister_id = principalOfBlob("x7E926B574D40DD1AB600EF4AE294D7E2D2267FA77832A886DE6E4B72F4197FF1"); canister_version = ?15832102157618905233 }); details = #controllers_change({ controllers = [ principalOfBlob("x1108697FFC6D45094AEDFBE2A29AD1939D09B4D94630190C629CD14D0FC80915"), principalOfBlob("xA282A98A18083753F3DE7592A2198D6B99C8F949A2EC8A4F529F93BB58C59A87"), principalOfBlob("x17691617B8B442AFB32C31DF22DF57966FEA580488256723D7E15DA9ECEEEA00"), principalOfBlob("x554AD41C79E61581014BE311F9D4B34811D335EB789A5543731482481F165AAA"), principalOfBlob("x2B8E9D514E23991BA4248FFA389E4C1E233DCC74324754D490095F1F8A63C2F0"), principalOfBlob("xFC639D6958FD1EA1E5B346359864D5BE44010FF463BBE3FC7A6969524896FE46"), principalOfBlob("xC23A172820B58468A0172ED6160AAAD5CD022CD31A758DAED770BD742E48D130"), principalOfBlob("xF8C698FD6E1D95443E119353DE510A61BC14E1216A7498623DB922273C26F534") ] }) }, { timestamp_nanos = 10541212000563527943; canister_version = 2689134793603183504; origin = #from_canister({ canister_id = principalOfBlob("xFD0E74B0990E0078D2B236027D6B7FC5C5F87878D58678F82484F4E75D2F951C"); canister_version = ?14834280829257491391 }); details = #creation({ controllers = [ principalOfBlob("xD92065148671911683101A133588AE791A21EC626F4BF9C04EFC0618773EAA16"), principalOfBlob("xE6C4C477AF447EC1D59F4DE45FA855620A308ACE5E7985E23EEC83B6DE9E7A45"), principalOfBlob("x5C4698C942208D3A6C38A387F9DD652E440339C1E0698E3FF7D098E5ADF0DE50"), principalOfBlob("xEC36CC81E040F2487088112A24F71279CFCEF6E28B80B686F9CB5EF661C10795"), principalOfBlob("xDA90DE1A63AF6E2336D10DD0AA6B73AD0792645EEBDDE279F464613D0D3FEEFD"), principalOfBlob("xD7273B138C7BA77B24762E9719827530A112A44E62E38FBB862EA149FDD66F9A") ] }) }, { timestamp_nanos = 14116231344195082928; canister_version = 4523606734605955336; origin = #from_user({ user_id = principalOfBlob("x9A1B4EEAF85713EE92E855F1BEE87F3FE35C84FDD06850DAC8F040ACD17D576A") }); details = #code_deployment({ mode = #reinstall; module_hash = "x25B00214F7C6B8BA3F69EC1FBD8BC9CC09D1B95EB57A8B1D022B04E7DCDFA58E" }) }, { timestamp_nanos = 3481921817742942786; canister_version = 9192667871694660610; origin = #from_canister({ canister_id = principalOfBlob("x3A16C322D334F8042ED922291CB854D60A33E746222A023EA5020B7D41655642"); canister_version = ?10449616418252478675 }); details = #controllers_change({ controllers = [ principalOfBlob("xC4ED20EBB0444E73617ECA0ABBC443EDF0163E4F4B23AF8CCCD2A3190579A59D") ] }) }, { timestamp_nanos = 14686404346102099380; canister_version = 2250618464655299498; origin = #from_user({ user_id = principalOfBlob("x374DA7D7B5F718177360AE769AE8F5B227269DA9D837857A4238F0C809FCF065") }); details = #code_uninstall }, { timestamp_nanos = 9568659421456693105; canister_version = 848519729038390968; origin = #from_user({ user_id = principalOfBlob("xEC395D74A4E4E610A0DCE6AD5E24D0FC4A81F68D8B9F8E9A874E3492BAC55757") }); details = #controllers_change({ controllers = [ principalOfBlob("xC1B42179ADA7FAB19B81214F32C5CB41BA44AEB1B0A285FCA96DC7529E31667A"), principalOfBlob("x6F4A3BF6B1C5F5B4DA96F373CE56A20DF3491E602A349325524A8D03331CE083") ] }) }, { timestamp_nanos = 5550019485348043196; canister_version = 12412919251015282992; origin = #from_user({ user_id = principalOfBlob("xCDE635272898479BC9935BEF0A6C51CEB1EED82A478AFE75A02F087067D12A9F") }); details = #code_deployment({ mode = #upgrade; module_hash = "x75A4DDAF64344788F0A5E08AEF31457D2629F301DF60AB8177C3FFAC498B9074" }) } ]; module_hash = ?"x17E7C82BF52CA609FA741633E6A4BF64B753791583EE9B0C78A073DE0E38B9BD"; controllers = [ principalOfBlob("xEB51862AB2B4A466C1D3F906E8986CF0284AD909DE18D8F5933BFAE314FFEABD"), principalOfBlob("xDE3ACE7BC63AABA7506A20E9C93555300ABC7CD8ED3EB286AEDCB24CAB0812C6"), principalOfBlob("x9A18B820BE6164576BBE8F88910CBF148176C3B86DDA0B3E165458750059B587"), principalOfBlob("xD6BFE31BFBCAF99A799D55B2CA3E017C90144C96C3DE646E93B8D6136B7D83E0") ] }) + }; + public shared func delete_canister(_arg0 : T.DeleteCanisterArgs) : async () { + () + }; + public shared func deposit_cycles(_arg0 : T.DepositCyclesArgs) : async () { + () + }; + public shared func raw_rand() : async (T.RawRandResult) { + ("x869AF7A6140D470862C22E5F4C779F515D2190E37D31EEC1BDFD5BBCE1B03FA0") + }; + public shared func http_request(_arg0 : T.HttpRequestArgs) : async (T.HttpRequestResult) { + ({ status = 15656497011928570502; headers = [ { name = "14519010981886906783"; value = "3800013330962312753" }, { name = "6412741098828968161"; value = "11484699392100541722" }, { name = "17507512528171630653"; value = "17445848412223914426" }, { name = "2946348513676687635"; value = "628601621483015159" }, { name = "13363524253285500019"; value = "17786224669345655322" }, { name = "11671532954286442289"; value = "18312172179401097355" }, { name = "11810108206237976017"; value = "8739665398422254929" }, { name = "6996900549006677128"; value = "11041931743943198423" } ]; body = "xB10726A014187038BCE35CB2F3ECCB7DD75F4647487E926B574D40DD1AB600EF" }) + }; + public shared func ecdsa_public_key(_arg0 : T.EcdsaPublicKeyArgs) : async (T.EcdsaPublicKeyResult) { + ({ public_key = "x869AF7A6140D470862C22E5F4C779F515D2190E37D31EEC1BDFD5BBCE1B03FA0"; chain_code = "x1A254CA23FD9613D005FB6E22DF7BA41EBE7B21A1C13F932DE5C88E3F7CBBA21" }) + }; + public shared func sign_with_ecdsa(_arg0 : T.SignWithEcdsaArgs) : async (T.SignWithEcdsaResult) { + ({ signature = "x869AF7A6140D470862C22E5F4C779F515D2190E37D31EEC1BDFD5BBCE1B03FA0" }) + }; + public shared func bitcoin_get_balance(_arg0 : T.BitcoinGetBalanceArgs) : async (T.BitcoinGetBalanceResult) { + (15656497011928570502) + }; + public query func bitcoin_get_balance_query(_arg0 : T.BitcoinGetBalanceQueryArgs) : async (T.BitcoinGetBalanceQueryResult) { + (15656497011928570502) + }; + public shared func bitcoin_get_utxos(_arg0 : T.BitcoinGetUtxosArgs) : async (T.BitcoinGetUtxosResult) { + ({ utxos = [ { outpoint = { txid = "x0862C22E5F4C779F515D2190E37D31EEC1BDFD5BBCE1B03FA00DA2FE1A254CA2"; vout = 2840997408 }; value = 17445848412223914426; height = 118915440 }, { outpoint = { txid = "xF7CBBA21D83DB97344666081C6741A2AA3EF195DD53147822C629DF98B40FE3A"; vout = 3953357992 }; value = 8739665398422254929; height = 3378598018 }, { outpoint = { txid = "xD706D81F6BD23CB10726A014187038BCE35CB2F3ECCB7DD75F4647487E926B57"; vout = 2056624229 }; value = 1763343418669589207; height = 3388535713 }, { outpoint = { txid = "xF4197FF183421A910092C007EDB6472B7A3158CE1700CC21E6E714AF1108697F"; vout = 92794092 }; value = 4919859010227508177; height = 2337925836 } ]; tip_block_hash = "x0FC80915A4320DA282A98A18083753F3DE7592A2198D6B99C8F949A2EC8A4F52"; tip_height = 2903633966; next_page = ?"x17691617B8B442AFB32C31DF22DF57966FEA580488256723D7E15DA9ECEEEA00" }) + }; + public query func bitcoin_get_utxos_query(_arg0 : T.BitcoinGetUtxosQueryArgs) : async (T.BitcoinGetUtxosQueryResult) { + ({ utxos = [ { outpoint = { txid = "x0862C22E5F4C779F515D2190E37D31EEC1BDFD5BBCE1B03FA00DA2FE1A254CA2"; vout = 2840997408 }; value = 17445848412223914426; height = 118915440 }, { outpoint = { txid = "xF7CBBA21D83DB97344666081C6741A2AA3EF195DD53147822C629DF98B40FE3A"; vout = 3953357992 }; value = 8739665398422254929; height = 3378598018 }, { outpoint = { txid = "xD706D81F6BD23CB10726A014187038BCE35CB2F3ECCB7DD75F4647487E926B57"; vout = 2056624229 }; value = 1763343418669589207; height = 3388535713 }, { outpoint = { txid = "xF4197FF183421A910092C007EDB6472B7A3158CE1700CC21E6E714AF1108697F"; vout = 92794092 }; value = 4919859010227508177; height = 2337925836 } ]; tip_block_hash = "x0FC80915A4320DA282A98A18083753F3DE7592A2198D6B99C8F949A2EC8A4F52"; tip_height = 2903633966; next_page = ?"x17691617B8B442AFB32C31DF22DF57966FEA580488256723D7E15DA9ECEEEA00" }) + }; + public shared func bitcoin_send_transaction(_arg0 : T.BitcoinSendTransactionArgs) : async () { + () + }; + public shared func bitcoin_get_current_fee_percentiles(_arg0 : T.BitcoinGetCurrentFeePercentilesArgs) : async (T.BitcoinGetCurrentFeePercentilesResult) { + ([ 14445098301504250376, 14519010981886906783, 3800013330962312753, 6412741098828968161 ]) + }; + public shared func node_metrics_history(_arg0 : T.NodeMetricsHistoryArgs) : async (T.NodeMetricsHistoryResult) { + ([ { timestamp_nanos = 14445098301504250376; node_metrics = [ { node_id = principalOfBlob("x31EEC1BDFD5BBCE1B03FA00DA2FE1A254CA23FD9613D005FB6E22DF7BA41EBE7"); num_blocks_total = 2946348513676687635; num_block_failures_total = 628601621483015159 }, { node_id = principalOfBlob("x7344666081C6741A2AA3EF195DD53147822C629DF98B40FE3A93E721D185BD47"); num_blocks_total = 8739665398422254929; num_block_failures_total = 6996900549006677128 }, { node_id = principalOfBlob("xD706D81F6BD23CB10726A014187038BCE35CB2F3ECCB7DD75F4647487E926B57"); num_blocks_total = 10057912679290418714; num_block_failures_total = 1763343418669589207 }, { node_id = principalOfBlob("x32A886DE6E4B72F4197FF183421A910092C007EDB6472B7A3158CE1700CC21E6"); num_blocks_total = 16736904521429092369; num_block_failures_total = 692044588527733257 }, { node_id = principalOfBlob("xD1939D09B4D94630190C629CD14D0FC80915A4320DA282A98A18083753F3DE75"); num_blocks_total = 5377942242194975629; num_block_failures_total = 14536374534758435564 } ] }, { timestamp_nanos = 2699673602518336856; node_metrics = [ { node_id = principalOfBlob("xAFB32C31DF22DF57966FEA580488256723D7E15DA9ECEEEA0032F8BB554AD41C"); num_blocks_total = 14039119793643782529; num_block_failures_total = 3420742533394811059 }, { node_id = principalOfBlob("x9A5543731482481F165AAA1560662B8E9D514E23991BA4248FFA389E4C1E233D"); num_blocks_total = 9736605414087480391; num_block_failures_total = 14670472641987634058 }, { node_id = principalOfBlob("xFC639D6958FD1EA1E5B346359864D5BE44010FF463BBE3FC7A6969524896FE46"); num_blocks_total = 5874018963714161346; num_block_failures_total = 12468803627480752232 } ] }, { timestamp_nanos = 6060388434559489450; node_metrics = [ { node_id = principalOfBlob("x2E48D130F2D796F8C698FD6E1D95443E119353DE510A61BC14E1216A7498623D"); num_blocks_total = 14370068839309583932; num_block_failures_total = 10541212000563527943 }, { node_id = principalOfBlob("x9073DCDDD8B951CDB2FC3A3922F1FD0E74B0990E0078D2B236027D6B7FC5C5F8"); num_blocks_total = 4965205962592385158; num_block_failures_total = 11603411761932611421 }, { node_id = principalOfBlob("xBFA3479ED1F3DDB8E186099D10294826ED8361D159D92065148671911683101A"); num_blocks_total = 14947274454573152686; num_block_failures_total = 7716925642222139723 }, { node_id = principalOfBlob("x773EAA160280F8E6C4C477AF447EC1D59F4DE45FA855620A308ACE5E7985E23E"); num_blocks_total = 8782559658733379294; num_block_failures_total = 4291121491176080988 }, { node_id = principalOfBlob("x3A6C38A387F9DD652E440339C1E0698E3FF7D098E5ADF0DE507011E9EC36CC81"); num_blocks_total = 11022318376113958984; num_block_failures_total = 17477312328600877330 } ] }, { timestamp_nanos = 16930824079303685760; node_metrics = [ { node_id = principalOfBlob("xDA90DE1A63AF6E2336D10DD0AA6B73AD0792645EEBDDE279F464613D0D3FEEFD"); num_blocks_total = 13738085029865269207; num_block_failures_total = 17402500047223268475 }, { node_id = principalOfBlob("x7530A112A44E62E38FBB862EA149FDD66F9AA60B04B09AFBD59DEDE608B1C0A7"); num_blocks_total = 8262129053821897548; num_block_failures_total = 7283261748982717338 }, { node_id = principalOfBlob("xEE92E855F1BEE87F3FE35C84FDD06850DAC8F040ACD17D576AEF2F3A2A75B35E"); num_blocks_total = 8934560208994098493; num_block_failures_total = 11869455582429884453 } ] } ]) + }; + public shared func provisional_create_canister_with_cycles(_arg0 : T.ProvisionalCreateCanisterWithCyclesArgs) : async (T.ProvisionalCreateCanisterWithCyclesResult) { + ({ canister_id = principalOfBlob("x869AF7A6140D470862C22E5F4C779F515D2190E37D31EEC1BDFD5BBCE1B03FA0") }) + }; + public shared func provisional_top_up_canister(_arg0 : T.ProvisionalTopUpCanisterArgs) : async () { + () + }; +} diff --git a/mgmt/agent.go b/ic/ic/agent.go similarity index 87% rename from mgmt/agent.go rename to ic/ic/agent.go index d697fc8..1882fa9 100755 --- a/mgmt/agent.go +++ b/ic/ic/agent.go @@ -1,7 +1,8 @@ -package mgmt +// Package ic provides a client for the "ic" canister. +// Do NOT edit this file. It was automatically generated by https://github.com/aviate-labs/agent-go. +package ic import ( - "fmt" "github.com/aviate-labs/agent-go" "github.com/aviate-labs/agent-go/candid/idl" "github.com/aviate-labs/agent-go/principal" @@ -14,20 +15,29 @@ type Agent struct { } // NewAgent creates a new agent for the "ic" canister. -func NewAgent(config agent.Config) (*Agent, error) { +func NewAgent(canisterId principal.Principal, config agent.Config) (*Agent, error) { a, err := agent.New(config) if err != nil { return nil, err } return &Agent{ a: a, - canisterId: principal.Principal{}, // aaaaa-aa + canisterId: canisterId, }, nil } // BitcoinGetBalance calls the "bitcoin_get_balance" method on the "ic" canister. -func (a Agent) BitcoinGetBalance(_ BitcoinGetBalanceArgs) (*BitcoinGetBalanceResult, error) { - return nil, fmt.Errorf("bitcoin_get_balance is not accepted as an ingress message") +func (a Agent) BitcoinGetBalance(arg0 BitcoinGetBalanceArgs) (*BitcoinGetBalanceResult, error) { + var r0 BitcoinGetBalanceResult + if err := a.a.Call( + a.canisterId, + "bitcoin_get_balance", + []any{arg0}, + []any{&r0}, + ); err != nil { + return nil, err + } + return &r0, nil } // BitcoinGetBalanceQuery calls the "bitcoin_get_balance_query" method on the "ic" canister. @@ -45,13 +55,31 @@ func (a Agent) BitcoinGetBalanceQuery(arg0 BitcoinGetBalanceQueryArgs) (*Bitcoin } // BitcoinGetCurrentFeePercentiles calls the "bitcoin_get_current_fee_percentiles" method on the "ic" canister. -func (a Agent) BitcoinGetCurrentFeePercentiles(_ BitcoinGetCurrentFeePercentilesArgs) (*BitcoinGetCurrentFeePercentilesResult, error) { - return nil, fmt.Errorf("bitcoin_get_current_fee_percentiles is not accepted as an ingress message") +func (a Agent) BitcoinGetCurrentFeePercentiles(arg0 BitcoinGetCurrentFeePercentilesArgs) (*BitcoinGetCurrentFeePercentilesResult, error) { + var r0 BitcoinGetCurrentFeePercentilesResult + if err := a.a.Call( + a.canisterId, + "bitcoin_get_current_fee_percentiles", + []any{arg0}, + []any{&r0}, + ); err != nil { + return nil, err + } + return &r0, nil } // BitcoinGetUtxos calls the "bitcoin_get_utxos" method on the "ic" canister. -func (a Agent) BitcoinGetUtxos(_ BitcoinGetUtxosArgs) (*BitcoinGetUtxosResult, error) { - return nil, fmt.Errorf("bitcoin_get_utxos is not accepted as an ingress message") +func (a Agent) BitcoinGetUtxos(arg0 BitcoinGetUtxosArgs) (*BitcoinGetUtxosResult, error) { + var r0 BitcoinGetUtxosResult + if err := a.a.Call( + a.canisterId, + "bitcoin_get_utxos", + []any{arg0}, + []any{&r0}, + ); err != nil { + return nil, err + } + return &r0, nil } // BitcoinGetUtxosQuery calls the "bitcoin_get_utxos_query" method on the "ic" canister. @@ -69,8 +97,16 @@ func (a Agent) BitcoinGetUtxosQuery(arg0 BitcoinGetUtxosQueryArgs) (*BitcoinGetU } // BitcoinSendTransaction calls the "bitcoin_send_transaction" method on the "ic" canister. -func (a Agent) BitcoinSendTransaction(_ BitcoinSendTransactionArgs) error { - return fmt.Errorf("bitcoin_send_transaction is not accepted as an ingress message") +func (a Agent) BitcoinSendTransaction(arg0 BitcoinSendTransactionArgs) error { + if err := a.a.Call( + a.canisterId, + "bitcoin_send_transaction", + []any{arg0}, + []any{}, + ); err != nil { + return err + } + return nil } // CanisterInfo calls the "canister_info" method on the "ic" canister. @@ -91,9 +127,9 @@ func (a Agent) CanisterInfo(arg0 CanisterInfoArgs) (*CanisterInfoResult, error) func (a Agent) CanisterStatus(arg0 CanisterStatusArgs) (*CanisterStatusResult, error) { var r0 CanisterStatusResult if err := a.a.Call( - arg0.CanisterId, + a.canisterId, "canister_status", - []any{}, + []any{arg0}, []any{&r0}, ); err != nil { return nil, err @@ -104,7 +140,7 @@ func (a Agent) CanisterStatus(arg0 CanisterStatusArgs) (*CanisterStatusResult, e // ClearChunkStore calls the "clear_chunk_store" method on the "ic" canister. func (a Agent) ClearChunkStore(arg0 ClearChunkStoreArgs) error { if err := a.a.Call( - arg0.CanisterId, + a.canisterId, "clear_chunk_store", []any{arg0}, []any{}, @@ -115,14 +151,23 @@ func (a Agent) ClearChunkStore(arg0 ClearChunkStoreArgs) error { } // CreateCanister calls the "create_canister" method on the "ic" canister. -func (a Agent) CreateCanister(_ CreateCanisterArgs) (*CreateCanisterResult, error) { - return nil, fmt.Errorf("create_canister is not accepted as an ingress message") +func (a Agent) CreateCanister(arg0 CreateCanisterArgs) (*CreateCanisterResult, error) { + var r0 CreateCanisterResult + if err := a.a.Call( + a.canisterId, + "create_canister", + []any{arg0}, + []any{&r0}, + ); err != nil { + return nil, err + } + return &r0, nil } // DeleteCanister calls the "delete_canister" method on the "ic" canister. func (a Agent) DeleteCanister(arg0 DeleteCanisterArgs) error { if err := a.a.Call( - arg0.CanisterId, + a.canisterId, "delete_canister", []any{arg0}, []any{}, @@ -135,7 +180,7 @@ func (a Agent) DeleteCanister(arg0 DeleteCanisterArgs) error { // DepositCycles calls the "deposit_cycles" method on the "ic" canister. func (a Agent) DepositCycles(arg0 DepositCyclesArgs) error { if err := a.a.Call( - arg0.CanisterId, + a.canisterId, "deposit_cycles", []any{arg0}, []any{}, @@ -146,8 +191,17 @@ func (a Agent) DepositCycles(arg0 DepositCyclesArgs) error { } // EcdsaPublicKey calls the "ecdsa_public_key" method on the "ic" canister. -func (a Agent) EcdsaPublicKey(_ EcdsaPublicKeyArgs) (*EcdsaPublicKeyResult, error) { - return nil, fmt.Errorf("ecdsa_public_key is not accepted as an ingress message") +func (a Agent) EcdsaPublicKey(arg0 EcdsaPublicKeyArgs) (*EcdsaPublicKeyResult, error) { + var r0 EcdsaPublicKeyResult + if err := a.a.Call( + a.canisterId, + "ecdsa_public_key", + []any{arg0}, + []any{&r0}, + ); err != nil { + return nil, err + } + return &r0, nil } // HttpRequest calls the "http_request" method on the "ic" canister. @@ -167,7 +221,7 @@ func (a Agent) HttpRequest(arg0 HttpRequestArgs) (*HttpRequestResult, error) { // InstallChunkedCode calls the "install_chunked_code" method on the "ic" canister. func (a Agent) InstallChunkedCode(arg0 InstallChunkedCodeArgs) error { if err := a.a.Call( - arg0.TargetCanister, + a.canisterId, "install_chunked_code", []any{arg0}, []any{}, @@ -180,7 +234,7 @@ func (a Agent) InstallChunkedCode(arg0 InstallChunkedCodeArgs) error { // InstallCode calls the "install_code" method on the "ic" canister. func (a Agent) InstallCode(arg0 InstallCodeArgs) error { if err := a.a.Call( - arg0.CanisterId, + a.canisterId, "install_code", []any{arg0}, []any{}, @@ -191,8 +245,17 @@ func (a Agent) InstallCode(arg0 InstallCodeArgs) error { } // NodeMetricsHistory calls the "node_metrics_history" method on the "ic" canister. -func (a Agent) NodeMetricsHistory(_ NodeMetricsHistoryArgs) (*NodeMetricsHistoryResult, error) { - return nil, fmt.Errorf("node_metrics_history is not accepted as an ingress message") +func (a Agent) NodeMetricsHistory(arg0 NodeMetricsHistoryArgs) (*NodeMetricsHistoryResult, error) { + var r0 NodeMetricsHistoryResult + if err := a.a.Call( + a.canisterId, + "node_metrics_history", + []any{arg0}, + []any{&r0}, + ); err != nil { + return nil, err + } + return &r0, nil } // ProvisionalCreateCanisterWithCycles calls the "provisional_create_canister_with_cycles" method on the "ic" canister. @@ -212,7 +275,7 @@ func (a Agent) ProvisionalCreateCanisterWithCycles(arg0 ProvisionalCreateCaniste // ProvisionalTopUpCanister calls the "provisional_top_up_canister" method on the "ic" canister. func (a Agent) ProvisionalTopUpCanister(arg0 ProvisionalTopUpCanisterArgs) error { if err := a.a.Call( - arg0.CanisterId, + a.canisterId, "provisional_top_up_canister", []any{arg0}, []any{}, @@ -224,18 +287,36 @@ func (a Agent) ProvisionalTopUpCanister(arg0 ProvisionalTopUpCanisterArgs) error // RawRand calls the "raw_rand" method on the "ic" canister. func (a Agent) RawRand() (*RawRandResult, error) { - return nil, fmt.Errorf("raw_rand is not accepted as an ingress message") + var r0 RawRandResult + if err := a.a.Call( + a.canisterId, + "raw_rand", + []any{}, + []any{&r0}, + ); err != nil { + return nil, err + } + return &r0, nil } // SignWithEcdsa calls the "sign_with_ecdsa" method on the "ic" canister. -func (a Agent) SignWithEcdsa(_ SignWithEcdsaArgs) (*SignWithEcdsaResult, error) { - return nil, fmt.Errorf("sign_with_ecdsa is not accepted as an ingress message") +func (a Agent) SignWithEcdsa(arg0 SignWithEcdsaArgs) (*SignWithEcdsaResult, error) { + var r0 SignWithEcdsaResult + if err := a.a.Call( + a.canisterId, + "sign_with_ecdsa", + []any{arg0}, + []any{&r0}, + ); err != nil { + return nil, err + } + return &r0, nil } // StartCanister calls the "start_canister" method on the "ic" canister. func (a Agent) StartCanister(arg0 StartCanisterArgs) error { if err := a.a.Call( - arg0.CanisterId, + a.canisterId, "start_canister", []any{arg0}, []any{}, @@ -248,7 +329,7 @@ func (a Agent) StartCanister(arg0 StartCanisterArgs) error { // StopCanister calls the "stop_canister" method on the "ic" canister. func (a Agent) StopCanister(arg0 StopCanisterArgs) error { if err := a.a.Call( - arg0.CanisterId, + a.canisterId, "stop_canister", []any{arg0}, []any{}, @@ -262,7 +343,7 @@ func (a Agent) StopCanister(arg0 StopCanisterArgs) error { func (a Agent) StoredChunks(arg0 StoredChunksArgs) (*StoredChunksResult, error) { var r0 StoredChunksResult if err := a.a.Call( - arg0.CanisterId, + a.canisterId, "stored_chunks", []any{arg0}, []any{&r0}, @@ -275,7 +356,7 @@ func (a Agent) StoredChunks(arg0 StoredChunksArgs) (*StoredChunksResult, error) // UninstallCode calls the "uninstall_code" method on the "ic" canister. func (a Agent) UninstallCode(arg0 UninstallCodeArgs) error { if err := a.a.Call( - arg0.CanisterId, + a.canisterId, "uninstall_code", []any{arg0}, []any{}, @@ -288,7 +369,7 @@ func (a Agent) UninstallCode(arg0 UninstallCodeArgs) error { // UpdateSettings calls the "update_settings" method on the "ic" canister. func (a Agent) UpdateSettings(arg0 UpdateSettingsArgs) error { if err := a.a.Call( - arg0.CanisterId, + a.canisterId, "update_settings", []any{arg0}, []any{}, @@ -302,7 +383,7 @@ func (a Agent) UpdateSettings(arg0 UpdateSettingsArgs) error { func (a Agent) UploadChunk(arg0 UploadChunkArgs) (*UploadChunkResult, error) { var r0 UploadChunkResult if err := a.a.Call( - arg0.CanisterId, + a.canisterId, "upload_chunk", []any{arg0}, []any{&r0}, diff --git a/ic/ic/agent_test.go b/ic/ic/agent_test.go new file mode 100755 index 0000000..c7dbf66 --- /dev/null +++ b/ic/ic/agent_test.go @@ -0,0 +1,860 @@ +// Do NOT edit this file. It was automatically generated by https://github.com/aviate-labs/agent-go. +package ic_test + +import ( + "github.com/aviate-labs/agent-go" + "github.com/aviate-labs/agent-go/candid/idl" + "github.com/aviate-labs/agent-go/mock" + "github.com/aviate-labs/agent-go/principal" + "net/http/httptest" + "net/url" + "testing" + + "github.com/aviate-labs/agent-go/ic/ic" +) + +// Test_BitcoinGetBalance tests the "bitcoin_get_balance" method on the "ic" canister. +func Test_BitcoinGetBalance(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "bitcoin_get_balance", + Arguments: []any{new(ic.BitcoinGetBalanceArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{*new(ic.Satoshi)}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.BitcoinGetBalanceArgs{ + *new(string), + ic.BitcoinNetwork{ + Mainnet: new(idl.Null), + }, + *new(*uint32), + } + if _, err := a.BitcoinGetBalance(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_BitcoinGetBalanceQuery tests the "bitcoin_get_balance_query" method on the "ic" canister. +func Test_BitcoinGetBalanceQuery(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "bitcoin_get_balance_query", + Arguments: []any{new(ic.BitcoinGetBalanceQueryArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{*new(ic.Satoshi)}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.BitcoinGetBalanceQueryArgs{ + *new(string), + ic.BitcoinNetwork{ + Mainnet: new(idl.Null), + }, + *new(*uint32), + } + if _, err := a.BitcoinGetBalanceQuery(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_BitcoinGetCurrentFeePercentiles tests the "bitcoin_get_current_fee_percentiles" method on the "ic" canister. +func Test_BitcoinGetCurrentFeePercentiles(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "bitcoin_get_current_fee_percentiles", + Arguments: []any{new(ic.BitcoinGetCurrentFeePercentilesArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{*new([]ic.MillisatoshiPerByte)}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.BitcoinGetCurrentFeePercentilesArgs{ + ic.BitcoinNetwork{ + Mainnet: new(idl.Null), + }, + } + if _, err := a.BitcoinGetCurrentFeePercentiles(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_BitcoinGetUtxos tests the "bitcoin_get_utxos" method on the "ic" canister. +func Test_BitcoinGetUtxos(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "bitcoin_get_utxos", + Arguments: []any{new(ic.BitcoinGetUtxosArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{ic.BitcoinGetUtxosResult{ + []ic.Utxo{{ + ic.Outpoint{ + *new([]byte), + *new(uint32), + }, + *new(uint64), + *new(uint32), + }}, + *new([]byte), + *new(uint32), + *new(*[]byte), + }}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.BitcoinGetUtxosArgs{ + *new(string), + ic.BitcoinNetwork{ + Mainnet: new(idl.Null), + }, + *new(*struct { + MinConfirmations *uint32 `ic:"min_confirmations,variant"` + Page *[]byte `ic:"page,variant"` + }), + } + if _, err := a.BitcoinGetUtxos(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_BitcoinGetUtxosQuery tests the "bitcoin_get_utxos_query" method on the "ic" canister. +func Test_BitcoinGetUtxosQuery(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "bitcoin_get_utxos_query", + Arguments: []any{new(ic.BitcoinGetUtxosQueryArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{ic.BitcoinGetUtxosQueryResult{ + []ic.Utxo{{ + ic.Outpoint{ + *new([]byte), + *new(uint32), + }, + *new(uint64), + *new(uint32), + }}, + *new([]byte), + *new(uint32), + *new(*[]byte), + }}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.BitcoinGetUtxosQueryArgs{ + *new(string), + ic.BitcoinNetwork{ + Mainnet: new(idl.Null), + }, + *new(*struct { + MinConfirmations *uint32 `ic:"min_confirmations,variant"` + Page *[]byte `ic:"page,variant"` + }), + } + if _, err := a.BitcoinGetUtxosQuery(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_BitcoinSendTransaction tests the "bitcoin_send_transaction" method on the "ic" canister. +func Test_BitcoinSendTransaction(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "bitcoin_send_transaction", + Arguments: []any{new(ic.BitcoinSendTransactionArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.BitcoinSendTransactionArgs{ + *new([]byte), + ic.BitcoinNetwork{ + Mainnet: new(idl.Null), + }, + } + if err := a.BitcoinSendTransaction(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_CanisterInfo tests the "canister_info" method on the "ic" canister. +func Test_CanisterInfo(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "canister_info", + Arguments: []any{new(ic.CanisterInfoArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{ic.CanisterInfoResult{ + *new(uint64), + []ic.Change{{ + *new(uint64), + *new(uint64), + ic.ChangeOrigin{ + FromUser: idl.Ptr(struct { + UserId principal.Principal `ic:"user_id" json:"user_id"` + }{ + *new(principal.Principal), + }), + }, + ic.ChangeDetails{ + Creation: idl.Ptr(struct { + Controllers []principal.Principal `ic:"controllers" json:"controllers"` + }{ + []principal.Principal{*new(principal.Principal)}, + }), + }, + }}, + *new(*[]byte), + []principal.Principal{*new(principal.Principal)}, + }}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.CanisterInfoArgs{ + *new(principal.Principal), + *new(*uint64), + } + if _, err := a.CanisterInfo(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_CanisterStatus tests the "canister_status" method on the "ic" canister. +func Test_CanisterStatus(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "canister_status", + Arguments: []any{new(ic.CanisterStatusArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{ic.CanisterStatusResult{ + struct { + Running *idl.Null `ic:"running,variant"` + Stopping *idl.Null `ic:"stopping,variant"` + Stopped *idl.Null `ic:"stopped,variant"` + }{ + Running: new(idl.Null), + }, + ic.DefiniteCanisterSettings{ + []principal.Principal{*new(principal.Principal)}, + idl.NewNat(uint(0)), + idl.NewNat(uint(0)), + idl.NewNat(uint(0)), + idl.NewNat(uint(0)), + }, + *new(*[]byte), + idl.NewNat(uint(0)), + idl.NewNat(uint(0)), + idl.NewNat(uint(0)), + idl.NewNat(uint(0)), + }}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.CanisterStatusArgs{ + *new(principal.Principal), + } + if _, err := a.CanisterStatus(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_ClearChunkStore tests the "clear_chunk_store" method on the "ic" canister. +func Test_ClearChunkStore(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "clear_chunk_store", + Arguments: []any{new(ic.ClearChunkStoreArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.ClearChunkStoreArgs{ + *new(principal.Principal), + } + if err := a.ClearChunkStore(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_CreateCanister tests the "create_canister" method on the "ic" canister. +func Test_CreateCanister(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "create_canister", + Arguments: []any{new(ic.CreateCanisterArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{ic.CreateCanisterResult{ + *new(principal.Principal), + }}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.CreateCanisterArgs{ + *new(*ic.CanisterSettings), + *new(*uint64), + } + if _, err := a.CreateCanister(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_DeleteCanister tests the "delete_canister" method on the "ic" canister. +func Test_DeleteCanister(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "delete_canister", + Arguments: []any{new(ic.DeleteCanisterArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.DeleteCanisterArgs{ + *new(principal.Principal), + } + if err := a.DeleteCanister(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_DepositCycles tests the "deposit_cycles" method on the "ic" canister. +func Test_DepositCycles(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "deposit_cycles", + Arguments: []any{new(ic.DepositCyclesArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.DepositCyclesArgs{ + *new(principal.Principal), + } + if err := a.DepositCycles(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_EcdsaPublicKey tests the "ecdsa_public_key" method on the "ic" canister. +func Test_EcdsaPublicKey(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "ecdsa_public_key", + Arguments: []any{new(ic.EcdsaPublicKeyArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{ic.EcdsaPublicKeyResult{ + *new([]byte), + *new([]byte), + }}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.EcdsaPublicKeyArgs{ + *new(*ic.CanisterId), + [][]byte{*new([]byte)}, + struct { + Curve ic.EcdsaCurve `ic:"curve" json:"curve"` + Name string `ic:"name" json:"name"` + }{ + ic.EcdsaCurve{ + Secp256k1: new(idl.Null), + }, + *new(string), + }, + } + if _, err := a.EcdsaPublicKey(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_HttpRequest tests the "http_request" method on the "ic" canister. +func Test_HttpRequest(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "http_request", + Arguments: []any{new(ic.HttpRequestArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{ic.HttpRequestResult{ + idl.NewNat(uint(0)), + []ic.HttpHeader{{ + *new(string), + *new(string), + }}, + *new([]byte), + }}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.HttpRequestArgs{ + *new(string), + *new(*uint64), + struct { + Get *idl.Null `ic:"get,variant"` + Head *idl.Null `ic:"head,variant"` + Post *idl.Null `ic:"post,variant"` + }{ + Get: new(idl.Null), + }, + []ic.HttpHeader{{ + *new(string), + *new(string), + }}, + *new(*[]byte), + *new(*struct { + Function struct { /* NOT SUPPORTED */ + } `ic:"function" json:"function"` + Context []byte `ic:"context" json:"context"` + }), + } + if _, err := a.HttpRequest(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_InstallChunkedCode tests the "install_chunked_code" method on the "ic" canister. +func Test_InstallChunkedCode(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "install_chunked_code", + Arguments: []any{new(ic.InstallChunkedCodeArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.InstallChunkedCodeArgs{ + ic.CanisterInstallMode{ + Install: new(idl.Null), + }, + *new(principal.Principal), + *new(*ic.CanisterId), + []ic.ChunkHash{{ + *new([]byte), + }}, + *new([]byte), + *new([]byte), + *new(*uint64), + } + if err := a.InstallChunkedCode(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_InstallCode tests the "install_code" method on the "ic" canister. +func Test_InstallCode(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "install_code", + Arguments: []any{new(ic.InstallCodeArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.InstallCodeArgs{ + ic.CanisterInstallMode{ + Install: new(idl.Null), + }, + *new(principal.Principal), + *new([]byte), + *new([]byte), + *new(*uint64), + } + if err := a.InstallCode(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_NodeMetricsHistory tests the "node_metrics_history" method on the "ic" canister. +func Test_NodeMetricsHistory(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "node_metrics_history", + Arguments: []any{new(ic.NodeMetricsHistoryArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{*new([]struct { + TimestampNanos uint64 `ic:"timestamp_nanos" json:"timestamp_nanos"` + NodeMetrics []ic.NodeMetrics `ic:"node_metrics" json:"node_metrics"` + })}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.NodeMetricsHistoryArgs{ + *new(principal.Principal), + *new(uint64), + } + if _, err := a.NodeMetricsHistory(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_ProvisionalCreateCanisterWithCycles tests the "provisional_create_canister_with_cycles" method on the "ic" canister. +func Test_ProvisionalCreateCanisterWithCycles(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "provisional_create_canister_with_cycles", + Arguments: []any{new(ic.ProvisionalCreateCanisterWithCyclesArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{ic.ProvisionalCreateCanisterWithCyclesResult{ + *new(principal.Principal), + }}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.ProvisionalCreateCanisterWithCyclesArgs{ + *new(*idl.Nat), + *new(*ic.CanisterSettings), + *new(*ic.CanisterId), + *new(*uint64), + } + if _, err := a.ProvisionalCreateCanisterWithCycles(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_ProvisionalTopUpCanister tests the "provisional_top_up_canister" method on the "ic" canister. +func Test_ProvisionalTopUpCanister(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "provisional_top_up_canister", + Arguments: []any{new(ic.ProvisionalTopUpCanisterArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.ProvisionalTopUpCanisterArgs{ + *new(principal.Principal), + idl.NewNat(uint(0)), + } + if err := a.ProvisionalTopUpCanister(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_RawRand tests the "raw_rand" method on the "ic" canister. +func Test_RawRand(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "raw_rand", + Arguments: []any{}, + Handler: func(request mock.Request) ([]any, error) { + return []any{*new([]byte)}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + if _, err := a.RawRand(); err != nil { + t.Fatal(err) + } + +} + +// Test_SignWithEcdsa tests the "sign_with_ecdsa" method on the "ic" canister. +func Test_SignWithEcdsa(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "sign_with_ecdsa", + Arguments: []any{new(ic.SignWithEcdsaArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{ic.SignWithEcdsaResult{ + *new([]byte), + }}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.SignWithEcdsaArgs{ + *new([]byte), + [][]byte{*new([]byte)}, + struct { + Curve ic.EcdsaCurve `ic:"curve" json:"curve"` + Name string `ic:"name" json:"name"` + }{ + ic.EcdsaCurve{ + Secp256k1: new(idl.Null), + }, + *new(string), + }, + } + if _, err := a.SignWithEcdsa(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_StartCanister tests the "start_canister" method on the "ic" canister. +func Test_StartCanister(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "start_canister", + Arguments: []any{new(ic.StartCanisterArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.StartCanisterArgs{ + *new(principal.Principal), + } + if err := a.StartCanister(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_StopCanister tests the "stop_canister" method on the "ic" canister. +func Test_StopCanister(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "stop_canister", + Arguments: []any{new(ic.StopCanisterArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.StopCanisterArgs{ + *new(principal.Principal), + } + if err := a.StopCanister(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_StoredChunks tests the "stored_chunks" method on the "ic" canister. +func Test_StoredChunks(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "stored_chunks", + Arguments: []any{new(ic.StoredChunksArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{*new([]ic.ChunkHash)}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.StoredChunksArgs{ + *new(principal.Principal), + } + if _, err := a.StoredChunks(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_UninstallCode tests the "uninstall_code" method on the "ic" canister. +func Test_UninstallCode(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "uninstall_code", + Arguments: []any{new(ic.UninstallCodeArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.UninstallCodeArgs{ + *new(principal.Principal), + *new(*uint64), + } + if err := a.UninstallCode(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_UpdateSettings tests the "update_settings" method on the "ic" canister. +func Test_UpdateSettings(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "update_settings", + Arguments: []any{new(ic.UpdateSettingsArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.UpdateSettingsArgs{ + *new(principal.Principal), + ic.CanisterSettings{ + *new(*[]principal.Principal), + *new(*idl.Nat), + *new(*idl.Nat), + *new(*idl.Nat), + *new(*idl.Nat), + }, + *new(*uint64), + } + if err := a.UpdateSettings(a0); err != nil { + t.Fatal(err) + } + +} + +// Test_UploadChunk tests the "upload_chunk" method on the "ic" canister. +func Test_UploadChunk(t *testing.T) { + a, err := newAgent([]mock.Method{ + { + Name: "upload_chunk", + Arguments: []any{new(ic.UploadChunkArgs)}, + Handler: func(request mock.Request) ([]any, error) { + return []any{*new(ic.ChunkHash)}, nil + }, + }, + }) + if err != nil { + t.Fatal(err) + } + + var a0 = ic.UploadChunkArgs{ + *new(principal.Principal), + *new([]byte), + } + if _, err := a.UploadChunk(a0); err != nil { + t.Fatal(err) + } + +} + +// newAgent creates a new agent with the given (mock) methods. +// Runs a mock replica in the background. +func newAgent(methods []mock.Method) (*ic.Agent, error) { + replica := mock.NewReplica() + canisterId := principal.Principal{Raw: []byte("ic")} + replica.AddCanister(canisterId, methods) + s := httptest.NewServer(replica) + u, _ := url.Parse(s.URL) + a, err := ic.NewAgent(canisterId, agent.Config{ + ClientConfig: &agent.ClientConfig{Host: u}, + FetchRootKey: true, + }) + if err != nil { + return nil, err + } + return a, nil +} diff --git a/ic/ic/types.mo b/ic/ic/types.mo new file mode 100755 index 0000000..26e717b --- /dev/null +++ b/ic/ic/types.mo @@ -0,0 +1,64 @@ +// Do NOT edit this file. It was automatically generated by https://github.com/aviate-labs/agent-go. +module T { + public type CanisterId = Principal; + public type WasmModule = Blob; + public type CanisterSettings = { controllers : ?[Principal]; compute_allocation : ?Nat; memory_allocation : ?Nat; freezing_threshold : ?Nat; reserved_cycles_limit : ?Nat }; + public type DefiniteCanisterSettings = { controllers : [Principal]; compute_allocation : Nat; memory_allocation : Nat; freezing_threshold : Nat; reserved_cycles_limit : Nat }; + public type ChangeOrigin = { #from_user : { user_id : Principal }; #from_canister : { canister_id : Principal; canister_version : ?Nat64 } }; + public type ChangeDetails = { #creation : { controllers : [Principal] }; #code_uninstall; #code_deployment : { mode : { #install; #reinstall; #upgrade }; module_hash : Blob }; #controllers_change : { controllers : [Principal] } }; + public type Change = { timestamp_nanos : Nat64; canister_version : Nat64; origin : T.ChangeOrigin; details : T.ChangeDetails }; + public type ChunkHash = { hash : Blob }; + public type HttpHeader = { name : Text; value : Text }; + public type HttpRequestResult = { status : Nat; headers : [T.HttpHeader]; body : Blob }; + public type EcdsaCurve = { #secp256k1 }; + public type Satoshi = Nat64; + public type BitcoinNetwork = { #mainnet; #testnet }; + public type BitcoinAddress = Text; + public type BlockHash = Blob; + public type Outpoint = { txid : Blob; vout : Nat32 }; + public type Utxo = { outpoint : T.Outpoint; value : T.Satoshi; height : Nat32 }; + public type BitcoinGetUtxosArgs = { address : T.BitcoinAddress; network : T.BitcoinNetwork; filter : ?{ #min_confirmations : Nat32; #page : Blob } }; + public type BitcoinGetUtxosQueryArgs = { address : T.BitcoinAddress; network : T.BitcoinNetwork; filter : ?{ #min_confirmations : Nat32; #page : Blob } }; + public type BitcoinGetCurrentFeePercentilesArgs = { network : T.BitcoinNetwork }; + public type BitcoinGetUtxosResult = { utxos : [T.Utxo]; tip_block_hash : T.BlockHash; tip_height : Nat32; next_page : ?Blob }; + public type BitcoinGetUtxosQueryResult = { utxos : [T.Utxo]; tip_block_hash : T.BlockHash; tip_height : Nat32; next_page : ?Blob }; + public type BitcoinGetBalanceArgs = { address : T.BitcoinAddress; network : T.BitcoinNetwork; min_confirmations : ?Nat32 }; + public type BitcoinGetBalanceQueryArgs = { address : T.BitcoinAddress; network : T.BitcoinNetwork; min_confirmations : ?Nat32 }; + public type BitcoinSendTransactionArgs = { transaction : Blob; network : T.BitcoinNetwork }; + public type MillisatoshiPerByte = Nat64; + public type NodeMetrics = { node_id : Principal; num_blocks_total : Nat64; num_block_failures_total : Nat64 }; + public type CreateCanisterArgs = { settings : ?T.CanisterSettings; sender_canister_version : ?Nat64 }; + public type CreateCanisterResult = { canister_id : T.CanisterId }; + public type UpdateSettingsArgs = { canister_id : Principal; settings : T.CanisterSettings; sender_canister_version : ?Nat64 }; + public type UploadChunkArgs = { canister_id : Principal; chunk : Blob }; + public type ClearChunkStoreArgs = { canister_id : T.CanisterId }; + public type StoredChunksArgs = { canister_id : T.CanisterId }; + public type CanisterInstallMode = { #install; #reinstall; #upgrade : ?{ skip_pre_upgrade : ?Bool } }; + public type InstallCodeArgs = { mode : T.CanisterInstallMode; canister_id : T.CanisterId; wasm_module : T.WasmModule; arg : Blob; sender_canister_version : ?Nat64 }; + public type InstallChunkedCodeArgs = { mode : T.CanisterInstallMode; target_canister : T.CanisterId; store_canister : ?T.CanisterId; chunk_hashes_list : [T.ChunkHash]; wasm_module_hash : Blob; arg : Blob; sender_canister_version : ?Nat64 }; + public type UninstallCodeArgs = { canister_id : T.CanisterId; sender_canister_version : ?Nat64 }; + public type StartCanisterArgs = { canister_id : T.CanisterId }; + public type StopCanisterArgs = { canister_id : T.CanisterId }; + public type CanisterStatusArgs = { canister_id : T.CanisterId }; + public type CanisterStatusResult = { status : { #running; #stopping; #stopped }; settings : T.DefiniteCanisterSettings; module_hash : ?Blob; memory_size : Nat; cycles : Nat; reserved_cycles : Nat; idle_cycles_burned_per_day : Nat }; + public type CanisterInfoArgs = { canister_id : T.CanisterId; num_requested_changes : ?Nat64 }; + public type CanisterInfoResult = { total_num_changes : Nat64; recent_changes : [T.Change]; module_hash : ?Blob; controllers : [Principal] }; + public type DeleteCanisterArgs = { canister_id : T.CanisterId }; + public type DepositCyclesArgs = { canister_id : T.CanisterId }; + public type HttpRequestArgs = { url : Text; max_response_bytes : ?Nat64; method : { #get; #head; #post }; headers : [T.HttpHeader]; body : ?Blob; transform : ?{ function : { /* func */ }; context : Blob } }; + public type EcdsaPublicKeyArgs = { canister_id : ?T.CanisterId; derivation_path : [Blob]; key_id : { curve : T.EcdsaCurve; name : Text } }; + public type EcdsaPublicKeyResult = { public_key : Blob; chain_code : Blob }; + public type SignWithEcdsaArgs = { message_hash : Blob; derivation_path : [Blob]; key_id : { curve : T.EcdsaCurve; name : Text } }; + public type SignWithEcdsaResult = { signature : Blob }; + public type NodeMetricsHistoryArgs = { subnet_id : Principal; start_at_timestamp_nanos : Nat64 }; + public type NodeMetricsHistoryResult = [{ timestamp_nanos : Nat64; node_metrics : [T.NodeMetrics] }]; + public type ProvisionalCreateCanisterWithCyclesArgs = { amount : ?Nat; settings : ?T.CanisterSettings; specified_id : ?T.CanisterId; sender_canister_version : ?Nat64 }; + public type ProvisionalCreateCanisterWithCyclesResult = { canister_id : T.CanisterId }; + public type ProvisionalTopUpCanisterArgs = { canister_id : T.CanisterId; amount : Nat }; + public type RawRandResult = Blob; + public type StoredChunksResult = [T.ChunkHash]; + public type UploadChunkResult = T.ChunkHash; + public type BitcoinGetBalanceResult = T.Satoshi; + public type BitcoinGetBalanceQueryResult = T.Satoshi; + public type BitcoinGetCurrentFeePercentilesResult = [T.MillisatoshiPerByte]; +}; diff --git a/ic/ids.go b/ic/ids.go index d1e7222..563faba 100644 --- a/ic/ids.go +++ b/ic/ids.go @@ -3,6 +3,8 @@ package ic import "github.com/aviate-labs/agent-go/principal" var ( + // https://internetcomputer.org/docs/current/references/ic-interface-spec#ic-management-canister + MANAGEMENT_CANISTER_PRINCIPAL, _ = principal.Decode("aaaaa-aa") // https://dashboard.internetcomputer.org/canister/rwlgt-iiaaa-aaaaa-aaaaa-cai REGISTRY_PRINCIPAL, _ = principal.Decode("rwlgt-iiaaa-aaaaa-aaaaa-cai") // https://dashboard.internetcomputer.org/canister/rrkah-fqaaa-aaaaa-aaaaq-cai diff --git a/ic/testdata/gen.go b/ic/testdata/gen.go index d09be00..bf86121 100644 --- a/ic/testdata/gen.go +++ b/ic/testdata/gen.go @@ -31,12 +31,10 @@ func checkLatest() error { filepath: "ic/testdata/did/cmc.did", remote: "https://raw.githubusercontent.com/dfinity/ic/master/rs/nns/cmc/cmc.did", }, - /* Needs custom implementation. { filepath: "ic/testdata/did/ic.did", remote: "https://raw.githubusercontent.com/dfinity/interface-spec/master/spec/_attachments/ic.did", }, - */ { filepath: "ic/testdata/did/icparchive.did", remote: "https://raw.githubusercontent.com/dfinity/ic/master/rs/rosetta-api/icp_ledger/ledger_archive.did", diff --git a/identity/anonymous.go b/identity/anonymous.go index 5d8d3e9..671d354 100644 --- a/identity/anonymous.go +++ b/identity/anonymous.go @@ -22,10 +22,12 @@ func (id AnonymousIdentity) Sign(_ []byte) []byte { return nil } +// ToPEM returns the PEM encoding of the public key. func (id AnonymousIdentity) ToPEM() ([]byte, error) { return nil, nil } +// Verify verifies the signature of the given message. func (id AnonymousIdentity) Verify(_, _ []byte) bool { return true } diff --git a/identity/ed25519.go b/identity/ed25519.go index ba6a86e..675068b 100644 --- a/identity/ed25519.go +++ b/identity/ed25519.go @@ -64,6 +64,7 @@ func NewEd25519IdentityFromPEM(data []byte) (*Ed25519Identity, error) { } } +// NewRandomEd25519Identity creates a new identity with a random key pair. func NewRandomEd25519Identity() (*Ed25519Identity, error) { publicKey, privateKey, _ := ed25519.GenerateKey(rand.Reader) return NewEd25519Identity(publicKey, privateKey) @@ -98,6 +99,6 @@ func (id Ed25519Identity) ToPEM() ([]byte, error) { } // Verify verifies the given signature. -func (id Ed25519Identity) Verify(data, signature []byte) bool { - return ed25519.Verify(id.publicKey, data, signature) +func (id Ed25519Identity) Verify(msg, sig []byte) bool { + return ed25519.Verify(id.publicKey, msg, sig) } diff --git a/identity/prime256v1.go b/identity/prime256v1.go index 6b841cc..b7ac6c2 100644 --- a/identity/prime256v1.go +++ b/identity/prime256v1.go @@ -27,11 +27,13 @@ func derEncodePrime256v1PublicKey(key *ecdsa.PublicKey) ([]byte, error) { }) } +// Prime256v1Identity is an identity based on a P-256 key pair. type Prime256v1Identity struct { privateKey *ecdsa.PrivateKey publicKey *ecdsa.PublicKey } +// NewPrime256v1Identity creates a new identity based on the given key pair. func NewPrime256v1Identity(privateKey *ecdsa.PrivateKey) *Prime256v1Identity { return &Prime256v1Identity{ privateKey: privateKey, @@ -39,6 +41,7 @@ func NewPrime256v1Identity(privateKey *ecdsa.PrivateKey) *Prime256v1Identity { } } +// NewPrime256v1IdentityFromPEM creates a new identity from the given PEM file. func NewPrime256v1IdentityFromPEM(data []byte) (*Prime256v1Identity, error) { block, remainder := pem.Decode(data) if block == nil || block.Type != "EC PRIVATE KEY" || len(remainder) != 0 { @@ -51,6 +54,7 @@ func NewPrime256v1IdentityFromPEM(data []byte) (*Prime256v1Identity, error) { return NewPrime256v1Identity(privateKey), nil } +// NewRandomPrime256v1Identity creates a new identity with a random key pair. func NewRandomPrime256v1Identity() (*Prime256v1Identity, error) { privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { @@ -59,15 +63,18 @@ func NewRandomPrime256v1Identity() (*Prime256v1Identity, error) { return NewPrime256v1Identity(privateKey), nil } +// PublicKey returns the public key of the identity. func (id Prime256v1Identity) PublicKey() []byte { der, _ := derEncodePrime256v1PublicKey(id.publicKey) return der } +// Sender returns the principal of the identity. func (id Prime256v1Identity) Sender() principal.Principal { return principal.NewSelfAuthenticating(id.PublicKey()) } +// Sign signs the given message. func (id Prime256v1Identity) Sign(msg []byte) []byte { hashData := sha256.Sum256(msg) sigR, sigS, _ := ecdsa.Sign(rand.Reader, id.privateKey, hashData[:]) @@ -79,6 +86,7 @@ func (id Prime256v1Identity) Sign(msg []byte) []byte { return buffer[:] } +// ToPEM returns the PEM encoding of the private key. func (id Prime256v1Identity) ToPEM() ([]byte, error) { data, err := x509.MarshalECPrivateKey(id.privateKey) if err != nil { @@ -90,6 +98,7 @@ func (id Prime256v1Identity) ToPEM() ([]byte, error) { }), nil } +// Verify verifies the signature of the given message. func (id Prime256v1Identity) Verify(msg, sig []byte) bool { r := new(big.Int).SetBytes(sig[:32]) s := new(big.Int).SetBytes(sig[32:]) diff --git a/identity/secp256k1.go b/identity/secp256k1.go index ddf9dfd..d7a9606 100644 --- a/identity/secp256k1.go +++ b/identity/secp256k1.go @@ -33,11 +33,13 @@ func isSecp256k1(actual asn1.ObjectIdentifier) bool { return slices.Equal(actual, secp256k1OID) } +// Secp256k1Identity is an identity based on a secp256k1 key pair. type Secp256k1Identity struct { privateKey *secp256k1.PrivateKey publicKey *secp256k1.PublicKey } +// NewRandomSecp256k1Identity creates a new identity with a random key pair. func NewRandomSecp256k1Identity() (*Secp256k1Identity, error) { privateKey, err := secp256k1.NewPrivateKey(secp256k1.S256()) if err != nil { @@ -46,6 +48,7 @@ func NewRandomSecp256k1Identity() (*Secp256k1Identity, error) { return NewSecp256k1Identity(privateKey) } +// NewSecp256k1Identity creates a new identity based on the given key pair. func NewSecp256k1Identity(privateKey *secp256k1.PrivateKey) (*Secp256k1Identity, error) { return &Secp256k1Identity{ privateKey: privateKey, @@ -53,13 +56,31 @@ func NewSecp256k1Identity(privateKey *secp256k1.PrivateKey) (*Secp256k1Identity, }, nil } +// NewSecp256k1IdentityFromPEM creates a new identity from the given PEM file. func NewSecp256k1IdentityFromPEM(data []byte) (*Secp256k1Identity, error) { blockParams, remainder := pem.Decode(data) - if blockParams.Type != "EC PARAMETERS" { - return nil, fmt.Errorf("invalid pem parameters") + if blockParams == nil || blockParams.Type != "EC PARAMETERS" { + return nil, fmt.Errorf("invalid pem file") + } + block, remainder := pem.Decode(remainder) + if block == nil || blockParams.Type != "EC PARAMETERS" || len(remainder) != 0 { + return nil, fmt.Errorf("invalid pem file") + } + var ecPrivateKey ecPrivateKey + if _, err := asn1.Unmarshal(block.Bytes, &ecPrivateKey); err != nil { + return nil, err } - block, _ := pem.Decode(remainder) - if blockParams.Type != "EC PARAMETERS" { + if !isSecp256k1(ecPrivateKey.NamedCurveOID) { + return nil, errors.New("invalid curve type") + } + privateKey, _ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), ecPrivateKey.PrivateKey) + return NewSecp256k1Identity(privateKey) +} + +// NewSecp256k1IdentityFromPEMWithoutParameters creates a new identity from the given PEM file. +func NewSecp256k1IdentityFromPEMWithoutParameters(data []byte) (*Secp256k1Identity, error) { + block, remainder := pem.Decode(data) + if block == nil || block.Type != "EC PRIVATE KEY" || len(remainder) != 0 { return nil, fmt.Errorf("invalid pem file") } var ecPrivateKey ecPrivateKey @@ -73,15 +94,18 @@ func NewSecp256k1IdentityFromPEM(data []byte) (*Secp256k1Identity, error) { return NewSecp256k1Identity(privateKey) } +// PublicKey returns the public key of the identity. func (id Secp256k1Identity) PublicKey() []byte { der, _ := derEncodeSecp256k1PublicKey(id.publicKey) return der } +// Sender returns the principal of the identity. func (id Secp256k1Identity) Sender() principal.Principal { return principal.NewSelfAuthenticating(id.PublicKey()) } +// Sign signs the given message. func (id Secp256k1Identity) Sign(msg []byte) []byte { hashData := sha256.Sum256(msg) sig, _ := id.privateKey.Sign(hashData[:]) @@ -93,6 +117,7 @@ func (id Secp256k1Identity) Sign(msg []byte) []byte { return buffer[:] } +// ToPEM returns the PEM encoding of the public key. func (id Secp256k1Identity) ToPEM() ([]byte, error) { der1, err := asn1.Marshal(secp256k1OID) if err != nil { diff --git a/request.go b/request.go index 04b75e4..870a40f 100644 --- a/request.go +++ b/request.go @@ -146,11 +146,13 @@ func NewRequestID(req Request) RequestID { // Sign signs the request ID with the given identity. func (r RequestID) Sign(id identity.Identity) []byte { - return id.Sign(append( + message := append( // \x0Aic-request []byte{0x0a, 0x69, 0x63, 0x2d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74}, r[:]..., - )) + ) + signature := id.Sign(message) + return signature } // RequestType is the type of request.