(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[2852],{56845:function(e,t,n){(window.__NEXT_P=window.__NEXT_P||[]).push(["/best-practices/dividing-into-systems",function(){return n(3803)}])},73307:function(e,t,n){"use strict";n.d(t,{Z:function(){return r}});var i=n(7505),s=n(11689);let o={logo:function(){return(0,i.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:"0.25em",fontSize:"32px",fontFamily:"PP Supply Mono",textTransform:"uppercase"},children:[(0,i.jsx)("img",{src:"/images/logos/mud-white.svg",style:{height:"calc(var(--nextra-navbar-height) - 35px)"},alt:"MUD logo"}),"MUD"]})},useNextSeoProps(){let{asPath:e}=(0,s.useRouter)();return{titleTemplate:"/"===e?"MUD – a framework for ambitious Ethereum applications":"%s – MUD"}},project:{link:"https://github.com/latticexyz/mud"},docsRepositoryBase:"https://github.com/latticexyz/mud/tree/main/docs",head:(0,i.jsx)(i.Fragment,{children:(0,i.jsx)("meta",{property:"title",content:"MUD documentation"})}),darkMode:!1,nextThemes:{defaultTheme:"dark"},footer:{text:"MIT 2023 \xa9 MUD"},primaryHue:28,sidebar:{defaultMenuCollapseLevel:1}};var r=o},3803:function(e,t,n){"use strict";n.r(t),n.d(t,{default:function(){return y}});var i=n(7505),s=n(42585),o=n(38288),r=n(73307);n(54693);var d=n(26736),a=n(98823),l=n.n(a),c={src:"/_next/static/media/batchCall.356ef274.svg",height:501,width:1e3,blurWidth:0,blurHeight:0},h={src:"/_next/static/media/libraries.deac3707.svg",height:501,width:1e3,blurWidth:0,blurHeight:0},m={src:"/_next/static/media/no-context.df5dc645.svg",height:501,width:1e3,blurWidth:0,blurHeight:0},u={src:"/_next/static/media/callFrom.6b124cdb.svg",height:501,width:1e3,blurWidth:0,blurHeight:0},x=n(64738);let g={MDXContent:function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},{wrapper:t}=Object.assign({},(0,d.ah)(),e.components);return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(p,{...e})}):p(e)},pageOpts:{filePath:"pages/best-practices/dividing-into-systems.mdx",route:"/best-practices/dividing-into-systems",headings:[{depth:1,value:"Dividing Code into Systems",id:"dividing-code-into-systems"},{depth:2,value:"Good reasons",id:"good-reasons"},{depth:3,value:"Modularity",id:"modularity"},{depth:3,value:"Access control considerations",id:"access-control-considerations"},{depth:4,value:"Access to the root namespace",id:"access-to-the-root-namespace"},{depth:2,value:"Bad reasons",id:"bad-reasons"},{depth:3,value:"Shared logic",id:"shared-logic"},{depth:3,value:"Contract size limit",id:"contract-size-limit"},{depth:2,value:"Calling multiple Systems",id:"calling-multiple-systems"},{depth:3,value:"Use batch calls (from the client)",id:"use-batch-calls-from-the-client"},{depth:3,value:"Move code into libraries",id:"move-code-into-libraries"},{depth:3,value:"More complicated solutions",id:"more-complicated-solutions"},{depth:4,value:"No trusted context",id:"no-trusted-context"},{depth:4,value:"Calling with the caller's identity",id:"calling-with-the-callers-identity"},{depth:4,value:"When root namespace is unavoidable",id:"when-root-namespace-is-unavoidable"}],pageMap:[{kind:"Meta",data:{introduction:{title:"What is MUD?",theme:{breadcrumb:!1}},quickstart:{title:"Get started",theme:{breadcrumb:!1}},protocol:{title:"Protocol",type:"separator"},store:"Store",world:"World",framework:{title:"Framework",type:"separator"},config:"Config",cli:"CLI","state-query":"State Query",indexer:"Indexer","world-explorer":{title:"World Explorer",theme:{breadcrumb:!1}},"---":{title:"",type:"separator"},guides:"Guides",templates:"Templates","best-practices":"Best Practices",contribute:{title:"Contribute",theme:{breadcrumb:!1}},changelog:"Changelog",retrospectives:"Retrospectives",audits:"Audits",version:{title:"2.2.9",type:"menu",items:{changelog:{title:"Changelog",href:"/changelog"},contribute:{title:"Contribute",href:"/contribute"}}},community:{title:"Community",type:"page",href:"https://community.mud.dev",newWindow:!0},twitter:{title:"Twitter",type:"page",href:"https://twitter.com/latticexyz",newWindow:!0},discord:{title:"Discord",type:"page",href:"https://lattice.xyz/discord",newWindow:!0}}},{kind:"Folder",name:"audits",route:"/audits",children:[{kind:"MdxPage",name:"2024-02-11-open-zeppelin",route:"/audits/2024-02-11-open-zeppelin"},{kind:"Meta",data:{"2024-02-11-open-zeppelin":"2024-02-11 OpenZeppelin",pdf:{display:"hidden"},icons:{display:"hidden"}}}]},{kind:"Folder",name:"best-practices",route:"/best-practices",children:[{kind:"Meta",data:{"dividing-into-systems":"Dividing Code into Systems",system:"System Best Practices","deployment-settings":"Recommended Deployment Settings","aws-kms":"Deploy production worlds using AWS KMS"}},{kind:"MdxPage",name:"aws-kms",route:"/best-practices/aws-kms"},{kind:"MdxPage",name:"deployment-settings",route:"/best-practices/deployment-settings"},{kind:"MdxPage",name:"dividing-into-systems",route:"/best-practices/dividing-into-systems"},{kind:"MdxPage",name:"system",route:"/best-practices/system"}]},{kind:"MdxPage",name:"changelog",route:"/changelog"},{kind:"Folder",name:"cli",route:"/cli",children:[{kind:"Meta",data:{tablegen:"mud tablegen",worldgen:"mud worldgen",test:"mud test",deploy:"mud deploy",verify:"mud verify","dev-contracts":"mud dev-contracts","abi-ts":"mud abi-ts","set-version":"mud set-version"}},{kind:"MdxPage",name:"abi-ts",route:"/cli/abi-ts"},{kind:"MdxPage",name:"deploy",route:"/cli/deploy"},{kind:"MdxPage",name:"dev-contracts",route:"/cli/dev-contracts"},{kind:"MdxPage",name:"set-version",route:"/cli/set-version"},{kind:"MdxPage",name:"tablegen",route:"/cli/tablegen"},{kind:"MdxPage",name:"test",route:"/cli/test"},{kind:"MdxPage",name:"verify",route:"/cli/verify"},{kind:"MdxPage",name:"worldgen",route:"/cli/worldgen"}]},{kind:"Folder",name:"config",route:"/config",children:[{kind:"MdxPage",name:"reference",route:"/config/reference"},{kind:"Meta",data:{reference:"Reference"}}]},{kind:"MdxPage",name:"config",route:"/config"},{kind:"MdxPage",name:"contribute",route:"/contribute"},{kind:"Folder",name:"guides",route:"/guides",children:[{kind:"Meta",data:{"hello-world":"Hello World","extending-a-world":"Extending a World","adding-delegation":"Adding Delegation",modules:"Writing MUD Modules",emojimon:"Emojimon",testing:"Testing","replicating-onchain-state":"Replicating onchain state"}},{kind:"MdxPage",name:"adding-delegation",route:"/guides/adding-delegation"},{kind:"Folder",name:"emojimon",route:"/guides/emojimon",children:[{kind:"MdxPage",name:"1-preface-the-ecs-model",route:"/guides/emojimon/1-preface-the-ecs-model"},{kind:"MdxPage",name:"2-getting-started",route:"/guides/emojimon/2-getting-started"},{kind:"MdxPage",name:"3-players-and-movement",route:"/guides/emojimon/3-players-and-movement"},{kind:"MdxPage",name:"4-map-and-terrain",route:"/guides/emojimon/4-map-and-terrain"},{kind:"MdxPage",name:"5-a-wild-emojimon-appears",route:"/guides/emojimon/5-a-wild-emojimon-appears"},{kind:"MdxPage",name:"6-advanced",route:"/guides/emojimon/6-advanced"},{kind:"Meta",data:{"1-preface-the-ecs-model":"Preface: the ECS model","2-getting-started":"Getting started","3-players-and-movement":"Players and movement","4-map-and-terrain":"Map and terrain","5-a-wild-emojimon-appears":"A wild Emojimon appears","6-advanced":"Advanced features"}}]},{kind:"MdxPage",name:"emojimon",route:"/guides/emojimon"},{kind:"Folder",name:"extending-a-world",route:"/guides/extending-a-world",children:[{kind:"Meta",data:{index:"Extending a World Permissionlessly"}},{kind:"MdxPage",name:"index",route:"/guides/extending-a-world"}]},{kind:"Folder",name:"hello-world",route:"/guides/hello-world",children:[{kind:"Meta",data:{"add-table":"Add a table","filter-sync":"Filter data synchronization","add-system":"Add a system",deploy:"Deploy to a blockchain","add-chain-client":"Add chains to the client"}},{kind:"MdxPage",name:"add-chain-client",route:"/guides/hello-world/add-chain-client"},{kind:"MdxPage",name:"add-system",route:"/guides/hello-world/add-system"},{kind:"MdxPage",name:"add-table",route:"/guides/hello-world/add-table"},{kind:"MdxPage",name:"deploy",route:"/guides/hello-world/deploy"},{kind:"MdxPage",name:"filter-sync",route:"/guides/hello-world/filter-sync"}]},{kind:"MdxPage",name:"hello-world",route:"/guides/hello-world"},{kind:"MdxPage",name:"modules",route:"/guides/modules"},{kind:"MdxPage",name:"replicating-onchain-state",route:"/guides/replicating-onchain-state"},{kind:"MdxPage",name:"testing",route:"/guides/testing"}]},{kind:"Folder",name:"indexer",route:"/indexer",children:[{kind:"Meta",data:{using:"Using the Indexer",sqlite:"SQLite Indexer","postgres-event-only":"PostgreSQL for events","postgres-decoded":"PostgreSQL for data (and events)",sql:"SQL API (Experimental)"}},{kind:"MdxPage",name:"postgres-decoded",route:"/indexer/postgres-decoded"},{kind:"MdxPage",name:"postgres-event-only",route:"/indexer/postgres-event-only"},{kind:"MdxPage",name:"sql",route:"/indexer/sql"},{kind:"MdxPage",name:"sqlite",route:"/indexer/sqlite"},{kind:"MdxPage",name:"using",route:"/indexer/using"}]},{kind:"MdxPage",name:"indexer",route:"/indexer"},{kind:"MdxPage",name:"introduction",route:"/introduction"},{kind:"MdxPage",name:"quickstart",route:"/quickstart"},{kind:"Folder",name:"retrospectives",route:"/retrospectives",children:[{kind:"MdxPage",name:"2023-09-12-register-system-vulnerability",route:"/retrospectives/2023-09-12-register-system-vulnerability"},{kind:"MdxPage",name:"2024-04-17-storeread-getdynamicfieldlength-bug",route:"/retrospectives/2024-04-17-storeread-getdynamicfieldlength-bug"},{kind:"Meta",data:{"2024-04-17-storeread-getdynamicfieldlength-bug":"2024-04-17 StoreRead.getDynamicFieldLength bug","2023-09-12-register-system-vulnerability":"2023-09-12 registerSystem vulnerability"}}]},{kind:"Folder",name:"state-query",route:"/state-query",children:[{kind:"Meta",data:{typescript:"TypeScript"}},{kind:"Folder",name:"typescript",route:"/state-query/typescript",children:[{kind:"Meta",data:{recs:"RECS",zustand:"Zustand"}},{kind:"MdxPage",name:"recs",route:"/state-query/typescript/recs"},{kind:"MdxPage",name:"zustand",route:"/state-query/typescript/zustand"}]}]},{kind:"Folder",name:"store",route:"/store",children:[{kind:"Meta",data:{introduction:"Introduction","data-model":"Data model",tables:"Tables","table-libraries":"Table libraries",encoding:"Encoding","store-hooks":"Store hooks",reference:"Reference"}},{kind:"MdxPage",name:"data-model",route:"/store/data-model"},{kind:"MdxPage",name:"encoding",route:"/store/encoding"},{kind:"MdxPage",name:"introduction",route:"/store/introduction"},{kind:"Folder",name:"reference",route:"/store/reference",children:[{kind:"Meta",data:{"store-core":"StoreCore (internal)",store:"IStore (external)","store-hook":"StoreHook",misc:"Miscellaneous"}},{kind:"MdxPage",name:"misc",route:"/store/reference/misc"},{kind:"MdxPage",name:"store-core",route:"/store/reference/store-core"},{kind:"MdxPage",name:"store-hook",route:"/store/reference/store-hook"},{kind:"MdxPage",name:"store",route:"/store/reference/store"}]},{kind:"MdxPage",name:"store-hooks",route:"/store/store-hooks"},{kind:"MdxPage",name:"table-libraries",route:"/store/table-libraries"},{kind:"MdxPage",name:"tables",route:"/store/tables"}]},{kind:"Folder",name:"templates",route:"/templates",children:[{kind:"Meta",data:{typescript:"TypeScript",godot:"Godot",pwa:"Progressive Web App (for mobile)",swift:"Swift",svelte:"Svelte",unity:"Unity",nethereum:"Nethereum"}},{kind:"MdxPage",name:"godot",route:"/templates/godot"},{kind:"MdxPage",name:"nethereum",route:"/templates/nethereum"},{kind:"MdxPage",name:"pwa",route:"/templates/pwa"},{kind:"MdxPage",name:"svelte",route:"/templates/svelte"},{kind:"MdxPage",name:"swift",route:"/templates/swift"},{kind:"Folder",name:"typescript",route:"/templates/typescript",children:[{kind:"Meta",data:{contracts:"Contracts",vanilla:"Vanilla","react-ecs":"React-ECS",threejs:"Three.js",vue:"Vue"}},{kind:"MdxPage",name:"contracts",route:"/templates/typescript/contracts"},{kind:"MdxPage",name:"react-ecs",route:"/templates/typescript/react-ecs"},{kind:"MdxPage",name:"threejs",route:"/templates/typescript/threejs"},{kind:"MdxPage",name:"vanilla",route:"/templates/typescript/vanilla"},{kind:"MdxPage",name:"vue",route:"/templates/typescript/vue"}]},{kind:"MdxPage",name:"unity",route:"/templates/unity"}]},{kind:"MdxPage",name:"templates",route:"/templates"},{kind:"Folder",name:"world",route:"/world",children:[{kind:"Meta",data:{introduction:"Introduction","resource-ids":"Resource Identifiers","namespaces-access-control":"Namespaces & Access Control",tables:"Tables",systems:"Systems","system-hooks":"System Hooks","function-selectors":"Function Selectors",balance:"Balance","account-delegation":"Account Delegation","batch-calls":"Batch Calls",upgrades:"Upgrading",modules:"Modules",reference:"Reference"}},{kind:"MdxPage",name:"account-delegation",route:"/world/account-delegation"},{kind:"MdxPage",name:"balance",route:"/world/balance"},{kind:"MdxPage",name:"batch-calls",route:"/world/batch-calls"},{kind:"MdxPage",name:"function-selectors",route:"/world/function-selectors"},{kind:"MdxPage",name:"introduction",route:"/world/introduction"},{kind:"Folder",name:"modules",route:"/world/modules",children:[{kind:"Meta",data:{keyswithvalue:"Keys with Value",keysintable:"Keys in Table",erc20:"ERC-20 tokens",erc721:"ERC-721 (NFT)"}},{kind:"MdxPage",name:"erc20",route:"/world/modules/erc20"},{kind:"MdxPage",name:"erc721",route:"/world/modules/erc721"},{kind:"MdxPage",name:"keysintable",route:"/world/modules/keysintable"},{kind:"MdxPage",name:"keyswithvalue",route:"/world/modules/keyswithvalue"}]},{kind:"MdxPage",name:"modules",route:"/world/modules"},{kind:"MdxPage",name:"namespaces-access-control",route:"/world/namespaces-access-control"},{kind:"Folder",name:"reference",route:"/world/reference",children:[{kind:"Meta",data:{"delegation-external":"Delegation (interface)",module:"Modules","module-external":"Modules (interface)",system:"Systems","system-external":"Systems (interface)",world:"World","world-external":"World (interfaces)","world-context":"World context","world-context-external":"World context (interface)","resource-ids":"Resource IDs",misc:"Miscellaneous",internal:"Internals"}},{kind:"MdxPage",name:"delegation-external",route:"/world/reference/delegation-external"},{kind:"Folder",name:"internal",route:"/world/reference/internal",children:[{kind:"Meta",data:{"access-control":"Access Control",create:"Create2",delegation:"Delegation",erc165:"ERC165","erc165-external":"ERC165 (interface)","init-module":"Init Module","init-module-implementation":"Init Module Implementation",systemcall:"SystemCall"}},{kind:"MdxPage",name:"access-control",route:"/world/reference/internal/access-control"},{kind:"MdxPage",name:"create",route:"/world/reference/internal/create"},{kind:"MdxPage",name:"delegation",route:"/world/reference/internal/delegation"},{kind:"MdxPage",name:"erc165-external",route:"/world/reference/internal/erc165-external"},{kind:"MdxPage",name:"erc165",route:"/world/reference/internal/erc165"},{kind:"MdxPage",name:"init-module-implementation",route:"/world/reference/internal/init-module-implementation"},{kind:"MdxPage",name:"init-module",route:"/world/reference/internal/init-module"},{kind:"MdxPage",name:"systemcall",route:"/world/reference/internal/systemcall"}]},{kind:"MdxPage",name:"misc",route:"/world/reference/misc"},{kind:"MdxPage",name:"module-external",route:"/world/reference/module-external"},{kind:"MdxPage",name:"module",route:"/world/reference/module"},{kind:"MdxPage",name:"resource-ids",route:"/world/reference/resource-ids"},{kind:"MdxPage",name:"system-external",route:"/world/reference/system-external"},{kind:"MdxPage",name:"system",route:"/world/reference/system"},{kind:"MdxPage",name:"world-context-external",route:"/world/reference/world-context-external"},{kind:"MdxPage",name:"world-context",route:"/world/reference/world-context"},{kind:"MdxPage",name:"world-external",route:"/world/reference/world-external"},{kind:"MdxPage",name:"world",route:"/world/reference/world"}]},{kind:"MdxPage",name:"resource-ids",route:"/world/resource-ids"},{kind:"MdxPage",name:"system-hooks",route:"/world/system-hooks"},{kind:"MdxPage",name:"systems",route:"/world/systems"},{kind:"MdxPage",name:"tables",route:"/world/tables"},{kind:"MdxPage",name:"upgrades",route:"/world/upgrades"}]},{kind:"MdxPage",name:"world-explorer",route:"/world-explorer"}],flexsearch:{codeblocks:!0},title:"Dividing Code into Systems"},pageNextRoute:"/best-practices/dividing-into-systems",nextraLayout:o.ZP,themeConfig:r.Z};function p(e){let t=Object.assign({h1:"h1",code:"code",p:"p",h2:"h2",h3:"h3",a:"a",ul:"ul",li:"li",em:"em",h4:"h4",details:"details",summary:"summary",ol:"ol"},(0,d.ah)(),e.components);return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(t.h1,{children:["Dividing Code into ",(0,i.jsx)(t.code,{children:"System"}),"s"]}),"\n",(0,i.jsxs)(t.p,{children:["This page discusses situations in which either you need to divide your code into multiple ",(0,i.jsx)(t.code,{children:"System"}),"s, or it seems like that would be a good solution."]}),"\n",(0,i.jsx)(t.h2,{id:"good-reasons",children:"Good reasons"}),"\n",(0,i.jsxs)(t.p,{children:["There are several reasons to divide the code in a namespace into multiple ",(0,i.jsx)(t.code,{children:"System"}),"s."]}),"\n",(0,i.jsx)(t.h3,{id:"modularity",children:"Modularity"}),"\n",(0,i.jsxs)(t.p,{children:["It is easier to write and maintain code that is ",(0,i.jsx)(t.a,{href:"https://en.wikipedia.org/wiki/Modularity",children:"modular"}),".\nIf two parts are logically distinct, with a limited interface between them, it might make sense to create them as two different ",(0,i.jsx)(t.code,{children:"System"}),"s.\nSuch a division can simplify QA and upgrades."]}),"\n",(0,i.jsx)(t.h3,{id:"access-control-considerations",children:"Access control considerations"}),"\n",(0,i.jsxs)(t.p,{children:["Each ",(0,i.jsx)(t.code,{children:"System"})," is either publicly accessible (can be called by anybody) or accessible only from authorized addresses.\nThese addresses can be:"]}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsx)(t.li,{children:(0,i.jsx)(t.a,{href:"https://ethereum.org/en/developers/docs/accounts/#types-of-account",children:"Externally owned accounts"})}),"\n",(0,i.jsxs)(t.li,{children:["Contracts outside of the ",(0,i.jsx)(t.code,{children:"World"})]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.code,{children:"System"}),"s that are ",(0,i.jsx)(t.em,{children:"not"})," in the root namespace.\n",(0,i.jsxs)(t.a,{href:"/world/systems#root-systems",children:["Root namespace ",(0,i.jsx)(t.code,{children:"System"}),"s"]})," ",(0,i.jsx)(t.em,{children:"can"})," ",(0,i.jsxs)(t.a,{href:"/world/systems#calling-from-a-root-system",children:["call other ",(0,i.jsx)(t.code,{children:"System"}),"s"]}),", but they can also bypass access control."]}),"\n"]}),"\n",(0,i.jsxs)(t.p,{children:["If access to some functions needs to be restricted to specific addresses, those functions belong in a separate ",(0,i.jsx)(t.code,{children:"System"})," from the rest of the namespace."]}),"\n",(0,i.jsx)(x.UW,{type:"warning",emoji:"⚠️",children:(0,i.jsxs)(t.p,{children:["Access to a private ",(0,i.jsx)(t.code,{children:"System"})," in a namespace is ",(0,i.jsxs)(t.a,{href:"/world/namespaces-access-control#modifying-access-control",children:["granted to the namespace owner, as well as all ",(0,i.jsx)(t.code,{children:"System"}),"s within that\nnamespace"]}),". If you need to disallow access from a separate\n",(0,i.jsx)(t.code,{children:"System"}),", put the private ",(0,i.jsx)(t.code,{children:"System"})," in a different namespace."]})}),"\n",(0,i.jsxs)(t.p,{children:["Another consideration is that code should be given only those permissions necessary to perform its tasks (",(0,i.jsx)(t.a,{href:"https://en.wikipedia.org/wiki/Principle_of_least_privilege",children:"the Principle of Least Privilege"}),").\nIf only some of the functions of a ",(0,i.jsx)(t.code,{children:"System"})," need to have certain privileges, it might make sense to put those functions in a separate ",(0,i.jsx)(t.code,{children:"System"}),"."]}),"\n",(0,i.jsx)(t.h4,{id:"access-to-the-root-namespace",children:"Access to the root namespace"}),"\n",(0,i.jsxs)(t.p,{children:["This is a particularly extreme example of least privilege.\nThe root namespace is ",(0,i.jsx)(t.a,{href:"/guides/best-practices/system-best-practices#avoid-the-root-namespace-if-possible",children:"extremely privileged"}),".\nSo the code that has to run the root namespace should be a separate ",(0,i.jsx)(t.code,{children:"System"})," from the code that can be in a different namespace."]}),"\n",(0,i.jsx)(t.h2,{id:"bad-reasons",children:"Bad reasons"}),"\n",(0,i.jsxs)(t.p,{children:["There are problems that could be solved by dividing your logic into multiple ",(0,i.jsx)(t.code,{children:"System"}),"s, but that are better handled by other solutions."]}),"\n",(0,i.jsx)(t.h3,{id:"shared-logic",children:"Shared logic"}),"\n",(0,i.jsxs)(t.p,{children:["If some logic is shared between two different ",(0,i.jsx)(t.code,{children:"System"}),"s, it is tempting to write a third ",(0,i.jsx)(t.code,{children:"System"})," that implements it and call it from both of them.\nHowever, a simpler solution is to use a ",(0,i.jsx)(t.a,{href:"https://solidity-by-example.org/library/",children:"Solidity library"})," to implement the shared logic."]}),"\n",(0,i.jsx)(t.h3,{id:"contract-size-limit",children:"Contract size limit"}),"\n",(0,i.jsxs)(t.p,{children:["Ethereum contracts are limited in size, but you can always use ",(0,i.jsx)(t.a,{href:"/guides/best-practices/system-best-practices#use-libraries-to-bypass-the-contract-size-limit",children:"a public library"})," to work around that limit."]}),"\n",(0,i.jsxs)(t.h2,{id:"calling-multiple-systems",children:["Calling multiple ",(0,i.jsx)(t.code,{children:"System"}),"s"]}),"\n",(0,i.jsxs)(t.p,{children:["It is pretty common to already have two different ",(0,i.jsx)(t.code,{children:"System"}),"s, and then need to call them together.\nFor example, imagine you have a ",(0,i.jsx)(t.code,{children:"System"})," that manages the player's position, called ",(0,i.jsx)(t.code,{children:"LocationSystem"}),".\nThe player can call a ",(0,i.jsx)(t.code,{children:"move"})," function.\nThen you have another ",(0,i.jsx)(t.code,{children:"System"}),", ",(0,i.jsx)(t.code,{children:"EnergySystem"}),".\nThe player can call an ",(0,i.jsx)(t.code,{children:"eat"})," function.\nNow you want a combined action, ",(0,i.jsx)(t.code,{children:"eatAndMove"}),"."]}),"\n",(0,i.jsxs)(t.p,{children:["There are multiple ways to create this combined action, only some of which require the extra complication of a third ",(0,i.jsx)(t.code,{children:"System"}),"."]}),"\n",(0,i.jsx)(t.h3,{id:"use-batch-calls-from-the-client",children:"Use batch calls (from the client)"}),"\n",(0,i.jsx)(t.p,{children:"Under these conditions:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:["You want ",(0,i.jsx)(t.code,{children:"eat"})," and ",(0,i.jsx)(t.code,{children:"move"})," to happen in sequence."]}),"\n",(0,i.jsxs)(t.li,{children:["You want them to happen atomically (so you can't just call ",(0,i.jsx)(t.code,{children:"eat"})," and then ",(0,i.jsx)(t.code,{children:"move"}),")."]}),"\n",(0,i.jsx)(t.li,{children:"You have no additional logic that needs to happen between them."}),"\n"]}),"\n",(0,i.jsxs)(t.p,{children:["You can achieve this by using ",(0,i.jsx)(t.a,{href:"/world/batch-calls",children:"batch calls"}),", without any need for changes in the ",(0,i.jsx)(t.code,{children:"World"}),"."]}),"\n",(0,i.jsxs)(t.details,{children:[(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.summary,{children:"Illustration"}),"\n",(0,i.jsx)(l(),{src:c})]}),(0,i.jsxs)(t.ol,{children:["\n",(0,i.jsxs)(t.li,{children:["The client sends a ",(0,i.jsx)(t.a,{href:"/world/batch-calls",children:(0,i.jsx)(t.code,{children:"batchCall"})})," that includes call to ",(0,i.jsx)(t.code,{children:"eat"})," and ",(0,i.jsx)(t.code,{children:"move"}),"."]}),"\n",(0,i.jsxs)(t.li,{children:["The ",(0,i.jsx)(t.code,{children:"batchCall"})," component inside the ",(0,i.jsx)(t.code,{children:"World"})," calls the first function, ",(0,i.jsx)(t.code,{children:"eat"}),"."]}),"\n",(0,i.jsxs)(t.li,{children:["After the ",(0,i.jsx)(t.code,{children:"eat"})," function returns, the ",(0,i.jsx)(t.code,{children:"batchCall"})," component calls ",(0,i.jsx)(t.code,{children:"move"}),"."]}),"\n"]})]}),"\n",(0,i.jsx)(t.h3,{id:"move-code-into-libraries",children:"Move code into libraries"}),"\n",(0,i.jsx)(t.p,{children:"Under these conditions:"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:["You control the namespace of ",(0,i.jsx)(t.code,{children:"LocationSystem"})," and ",(0,i.jsx)(t.code,{children:"EnergySystem"}),"."]}),"\n",(0,i.jsxs)(t.li,{children:["The permissions required for ",(0,i.jsx)(t.code,{children:"move"})," and ",(0,i.jsx)(t.code,{children:"eat"})," are the same."]}),"\n"]}),"\n",(0,i.jsxs)(t.p,{children:["You can move the code for ",(0,i.jsx)(t.code,{children:"move"})," and ",(0,i.jsx)(t.code,{children:"eat"})," into ",(0,i.jsx)(t.a,{href:"/guides/best-practices/system-best-practices#use-libraries-to-bypass-the-contract-size-limit",children:"public libraries"}),".\nThese libraries can then be called from ",(0,i.jsx)(t.code,{children:"LocationSystem"}),", ",(0,i.jsx)(t.code,{children:"EnergySystem"}),", and ",(0,i.jsx)(t.code,{children:"CombinedActionSystem"}),"."]}),"\n",(0,i.jsx)(t.details,{children:(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.summary,{children:"Illustration"}),"\n",(0,i.jsx)(l(),{src:h})]})}),"\n",(0,i.jsx)(t.h3,{id:"more-complicated-solutions",children:"More complicated solutions"}),"\n",(0,i.jsxs)(t.p,{children:["The above solutions are preferable, but sometimes they don't work.\nFor example, if you need to ensure some code runs between ",(0,i.jsx)(t.code,{children:"eat"})," and ",(0,i.jsx)(t.code,{children:"move"}),", you can't have the client use ",(0,i.jsx)(t.code,{children:"batchCall"}),".\nIf you are writing an extension to a game written by somebody else, you don't have control of the namespaces of the ",(0,i.jsx)(t.code,{children:"System"}),"s, so you can't just move code into public libraries."]}),"\n",(0,i.jsx)(t.h4,{id:"no-trusted-context",children:"No trusted context"}),"\n",(0,i.jsxs)(t.p,{children:["Any call that a ",(0,i.jsx)(t.code,{children:"System"})," receives from the ",(0,i.jsx)(t.code,{children:"World"})," has ",(0,i.jsx)(t.a,{href:"/world/systems#writing-systems",children:"some context information"}),": the identity of the caller and the ETH value transferred by the call.\nIf ",(0,i.jsx)(t.code,{children:"eat"})," and ",(0,i.jsx)(t.code,{children:"move"})," don't rely on this context information you can create a third ",(0,i.jsx)(t.code,{children:"System"})," that called the ",(0,i.jsx)(t.code,{children:"World"})," for ",(0,i.jsx)(t.code,{children:"eat"})," and ",(0,i.jsx)(t.code,{children:"move"}),", ",(0,i.jsx)(t.a,{href:"/world/systems#calling-systems",children:"just as an unrelated contract would"}),".\nThe caller identity will be the address of that ",(0,i.jsx)(t.code,{children:"System"}),", and the value transferred will be zero regardless of the original value, but this is OK for some applications."]}),"\n",(0,i.jsxs)(t.details,{children:[(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.summary,{children:"Illustration"}),"\n",(0,i.jsx)(l(),{src:m})]}),(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.code,{children:"CombinedActionSystem"})," first calls the ",(0,i.jsx)(t.code,{children:"World"})," with the function call ",(0,i.jsx)(t.code,{children:"game__eat"}),".\nThis call is translated by the ",(0,i.jsx)(t.code,{children:"World"})," to ",(0,i.jsx)(t.code,{children:"eat"})," in ",(0,i.jsx)(t.code,{children:"EnergySystem"}),", located in the ",(0,i.jsx)(t.code,{children:"game"})," namespace.\nThis flow is shown in yellow."]}),(0,i.jsxs)(t.p,{children:["Then, ",(0,i.jsx)(t.code,{children:"CombinedActionSystem"})," calls the ",(0,i.jsx)(t.code,{children:"World"})," with the function call ",(0,i.jsx)(t.code,{children:"game__move"}),".\nThis call is translated by the ",(0,i.jsx)(t.code,{children:"World"})," to ",(0,i.jsx)(t.code,{children:"move"})," in ",(0,i.jsx)(t.code,{children:"LocationSystem"}),", which is also located in the ",(0,i.jsx)(t.code,{children:"game"})," namespace.\nThis flow is shown in green."]})]}),"\n",(0,i.jsx)(x.UW,{type:"info",emoji:"⚠️",children:(0,i.jsxs)(t.p,{children:["This applies only to a case where the third ",(0,i.jsx)(t.code,{children:"System"})," is ",(0,i.jsx)(t.em,{children:"not"})," in the root namespace. If the root namespace is\nnecessary, ",(0,i.jsx)(t.a,{href:"#when-root-namespace-is-unavoidable",children:"see below"}),"."]})}),"\n",(0,i.jsx)(t.h4,{id:"calling-with-the-callers-identity",children:"Calling with the caller's identity"}),"\n",(0,i.jsxs)(t.p,{children:["If the functions require the identity of the message sender, you can still call them from a separate ",(0,i.jsx)(t.code,{children:"System"})," (as long as it is ",(0,i.jsx)(t.em,{children:"not"})," running in the root namespace) using ",(0,i.jsx)(t.a,{href:"/world/account-delegation#user-delegation",children:"delegation"}),".\nNon-root ",(0,i.jsx)(t.code,{children:"System"}),"s have their own addresses, so you can ask users to ",(0,i.jsxs)(t.a,{href:"/world/account-delegation#creating-a-user-delegation",children:["call ",(0,i.jsx)(t.code,{children:"registerDelegation"})]})," to allow your ",(0,i.jsx)(t.code,{children:"System"})," to act on their behalf, and then your system can ",(0,i.jsxs)(t.a,{href:"/world/account-delegation#using-a-user-delegation",children:["use ",(0,i.jsx)(t.code,{children:"callFrom"})]})," to send the user's identity when calling ",(0,i.jsx)(t.code,{children:"eat"})," and ",(0,i.jsx)(t.code,{children:"move"}),"."]}),"\n",(0,i.jsxs)(t.p,{children:["Note that this ",(0,i.jsx)(t.em,{children:"only"})," works for ",(0,i.jsx)(t.code,{children:"_msgSender()"})," (the MUD version of ",(0,i.jsx)(t.code,{children:"msg.sender"}),").\nIt does not let you propagate the value for ",(0,i.jsx)(t.code,{children:"_msgValue()"})," (the MUD version of ",(0,i.jsx)(t.code,{children:"msg.value"}),")."]}),"\n",(0,i.jsx)(t.details,{children:(0,i.jsxs)(t.p,{children:[(0,i.jsx)(t.summary,{children:"Illustration"}),"\n",(0,i.jsx)(l(),{src:u})]})}),"\n",(0,i.jsx)(t.h4,{id:"when-root-namespace-is-unavoidable",children:"When root namespace is unavoidable"}),"\n",(0,i.jsxs)(t.p,{children:["There are a few cases that require ",(0,i.jsx)(t.code,{children:"System"})," functions to be called from the root namespace."]}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:["The called ",(0,i.jsx)(t.code,{children:"System"})," needs to know the value sent with the transaction to the caller ",(0,i.jsx)(t.code,{children:"System"}),"."]}),"\n",(0,i.jsxs)(t.li,{children:["You cannot use ",(0,i.jsx)(t.code,{children:"callFrom"})," because users won't sign ",(0,i.jsx)(t.code,{children:"registerDelegation"}),"."]}),"\n",(0,i.jsxs)(t.li,{children:["The code that the calling ",(0,i.jsx)(t.code,{children:"System"})," has to implement needs to be in the root namespace for some other reason (for example, to modify root tables)."]}),"\n"]}),"\n",(0,i.jsxs)(t.p,{children:["In those cases, you can use ",(0,i.jsx)(t.a,{href:"/world/systems#calling-from-a-root-system",children:(0,i.jsx)(t.code,{children:"SystemCall"})})," if the message sender is authorized to call the ",(0,i.jsx)(t.code,{children:"System"})," directly.\nIf the message sender is not normally authorized you can use ",(0,i.jsx)(t.a,{href:"https://github.com/latticexyz/mud/blob/main/packages/world/src/WorldContext.sol#L122-L140",children:(0,i.jsx)(t.code,{children:"WorldContextProviderLib.callWithContext"})}),", a low level function that bypasses access controls."]})]})}var y=(0,s.j)(g)}},function(e){e.O(0,[3720,2888,179],function(){return e(e.s=56845)}),_N_E=e.O()}]);