ETH Price: $2,003.59 (+8.15%)

Transaction Decoder

Block:
24508722 at Feb-22-2026 12:08:11 AM +UTC
Transaction Fee:
0.000021570746850257 ETH $0.04
Gas Used:
341,791 Gas / 0.063110927 Gwei

Emitted Events:

220 0x4f4495243837681061c4743b74b3eedf548d56a5.0x9991faa1f435675159ffae64b66d7ecfdb55c29755869a18db8497b4392347e0( 0x9991faa1f435675159ffae64b66d7ecfdb55c29755869a18db8497b4392347e0, 0x3bb55ec3f284afb1bab7f062855a0e6311c08182812195190cc563c1b38583cd, 0x000000000000000000000000ce16f69375520ab01377ce7b88f5ba8c48f8d666, 0xd3f86ec380012c9f05c3141b2d060c29a88e0c38a743292487aa5c8316a725c6, 00000000000000000000000000000000000000000000000000000000000000c0, 0000000000000000000000000000000000000000000000000000000000000100, 0000000000000000000000000000000000000000000000000000000000000160, 000000000000000000000000000000000000000000000000000000000112e6df, 57284fa896b2bb5b9b3c2595e34147018d3f1fedad44da4137c5a7f5f3e3bc8d, 00000000000000000000000000000000000000000000000000000000004caf05, 0000000000000000000000000000000000000000000000000000000000000007, 6f736d6f73697300000000000000000000000000000000000000000000000000, 000000000000000000000000000000000000000000000000000000000000003f, 6f736d6f316e366e657939747366353565747a396e726d7a7964387761376536, 3471643373303661373466717333306b61387070733663767174737963723600, 0000000000000000000000000000000000000000000000000000000000000004, 5553444300000000000000000000000000000000000000000000000000000000 )
221 0x4f4495243837681061c4743b74b3eedf548d56a5.0xa74c8847d513feba22a0f0cb38d53081abf97562cdb293926ba243689e7c41ca( 0xa74c8847d513feba22a0f0cb38d53081abf97562cdb293926ba243689e7c41ca, 0x3bb55ec3f284afb1bab7f062855a0e6311c08182812195190cc563c1b38583cd )

Account State Difference:

  Address   Before After State Difference Code
0x2102C32A...a185bDa43
(Axelar: Relayer 2)
7.005937478372419691 Eth
Nonce: 46287
7.005915907625569434 Eth
Nonce: 46288
0.000021570746850257
(Titan Builder)
13.073578541847078021 Eth13.073588795577078021 Eth0.00001025373
0x4F449524...f548D56A5
(Axelar: Gateway)

Execution Trace

Axelar: Gateway.09c5eabe( )
  • AxelarGateway.execute( input=0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000003E000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000C0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000013BB55EC3F284AFB1BAB7F062855A0E6311C08182812195190CC563C1B38583CD00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001B617070726F7665436F6E747261637443616C6C576974684D696E7400000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001E000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000CE16F69375520AB01377CE7B88F5BA8C48F8D666D3F86EC380012C9F05C3141B2D060C29A88E0C38A743292487AA5C8316A725C600000000000000000000000000000000000000000000000000000000000001A0000000000000000000000000000000000000000000000000000000000112E6DF57284FA896B2BB5B9B3C2595E34147018D3F1FEDAD44DA4137C5A7F5F3E3BC8D00000000000000000000000000000000000000000000000000000000004CAF0500000000000000000000000000000000000000000000000000000000000000076F736D6F73697300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F6F736D6F316E366E657939747366353565747A396E726D7A79643877613765363471643373303661373466717333306B61387070733663767174737963723600000000000000000000000000000000000000000000000000000000000000000455534443000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001DE00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000135CE0000000000000000000000000000000000000000000000000000000000000D800000000000000000000000000000000000000000000000000000000000000033000000000000000000000000021D936762FDE8C622EC526E91408E9CF33B525600000000000000000000000003FE99104A9532F2727DB3AE31FD0CEB1188EFD00000000000000000000000000BF5AE5C4944A0E04D905B9F3BC9773C379EFC76000000000000000000000000123042337808EFC01C1AD7E506265F6F3756DC1900000000000000000000000013C1B3365B323FA2A4A0EAB145F98781A467521700000000000000000000000018E83FBA9969A4365CDE27F0CB30A61C9BBC467300000000000000000000000020B025C80D90C4CBD8F96A4852E8D986946DA60E00000000000000000000000021BDF788ED9A267B80280BEF415CC9C6A77AECFD0000000000000000000000002C2981DAF35371A38580EB685CB8F5137643434C0000000000000000000000002DF880D8CE5CE9CD8794187A822CED334A413B5D000000000000000000000000368E5E728DC48D13594F0D33334D9C283735BFCB0000000000000000000000003743F0BD81E54405C3273112C59DA102F702DAE40000000000000000000000003C549AD7A10887BF6C562512738713E7A96411DD00000000000000000000000045A83A274072E2BC99EAF2E80DA94E6F2C5D7DA6000000000000000000000000470D96B3513D6C63CD72C74F3681CE74B9FC639400000000000000000000000047507803BE195917EF141AB7B3AFA6D623535A32000000000000000000000000491FF43DE09F2B80CA92DF31BDF13855B0F4589C0000000000000000000000005222D090E999BB4DF82930EE233C02A3B8B4EB56000000000000000000000000540C87A42334DD6219C0AC7869F1D7C41BD3275400000000000000000000000055BEB9723BD5BC7226ED2E6D4F69476E65A0F7FA00000000000000000000000061946E5B9B8A231185937688E6AC232773FF8F000000000000000000000000006AF295171A45431325FC303F099782FA9526E0E60000000000000000000000006DD7998D0324D41B56DEE6215D588BD53F81828E000000000000000000000000737BFE757AD5A7A3451ABEBB612C3FE82286CDD3000000000000000000000000761E62677645DF454690F2FF7FBEABCB9C1184110000000000000000000000007B9B3D251E63E6A2937149BB93E7DC5E19C279DD0000000000000000000000007FFE9724BBDECE33E76D93C61A7EEB62AEF93BEF00000000000000000000000082E916A86F9AF6F58A65695D4378D4668AA367E70000000000000000000000008333AD83E30C3B7F969607994FC503E04EAEC615000000000000000000000000846A30460057EB4937369739C7BA5EE53041CDFF0000000000000000000000008CBDEB8E33676AC67222E791512C8E48E32EFED30000000000000000000000008CD3E02A4A3E26FC6416B8AEEBF71DD54FC8DB4200000000000000000000000094A847553D021DCF48A347CE1BBAA07F52C61D880000000000000000000000009539BAE27FC438841FC9239D769C051726B111580000000000000000000000009F27636B753A5FB7E710D28E336D087746C45633000000000000000000000000A08AFBE0249F85EA9EE03FE959155CCECA4C7914000000000000000000000000A6D985FD129440C87237E599D1F3EC4BA4AE51EC000000000000000000000000A8894919703FB09F295B85261FA3F87E02ABB57F000000000000000000000000AC380E34CF1E4AB0828900FFD91C184F8546CCEC000000000000000000000000B51B532603E57B829924F5B8696476153D30C9E8000000000000000000000000B8D60504ABEB077966E81B7936961C00736EB1FE000000000000000000000000C14385B5EA7ED5FE6F2695134D86C9772A520663000000000000000000000000C8998EF7B6D7B078A436F1CE0901520F5DB1464E000000000000000000000000D262A00AE2634FB38BE42378D140BA0A0FBB95C5000000000000000000000000EAB6E4115CE343CCCD6BD86E9CA03A7A2891E4CD000000000000000000000000EFB62752DA4F2D9FEC4E1911AF01B808264052AA000000000000000000000000F023857C179161F7D43AA2F9A3DF88E099B22280000000000000000000000000F04FC428343330869B7C9CC30A27CD494A83B869000000000000000000000000F2043DF655AD6E0291216656E598157025A8A7E9000000000000000000000000F75D8553954C360FA0BEFC9CBFC71E7D7D4BE139000000000000000000000000FC85C30E2381C86772B1A23F9BFB86C3B161683C0000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000090E00000000000000000000000000000000000000000000000000000000000008C7000000000000000000000000000000000000000000000000000000000000003A0000000000000000000000000000000000000000000000000000000000000B520000000000000000000000000000000000000000000000000000000000000AE50000000000000000000000000000000000000000000000000000000000000B13000000000000000000000000000000000000000000000000000000000000099A00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000A7C0000000000000000000000000000000000000000000000000000000000000AEA0000000000000000000000000000000000000000000000000000000000000A490000000000000000000000000000000000000000000000000000000000000C3C00000000000000000000000000000000000000000000000000000000000005850000000000000000000000000000000000000000000000000000000000000F0B0000000000000000000000000000000000000000000000000000000000000BA500000000000000000000000000000000000000000000000000000000000008BC000000000000000000000000000000000000000000000000000000000000034F0000000000000000000000000000000000000000000000000000000000000B170000000000000000000000000000000000000000000000000000000000000B1900000000000000000000000000000000000000000000000000000000000009300000000000000000000000000000000000000000000000000000000000000ADC0000000000000000000000000000000000000000000000000000000000000F7500000000000000000000000000000000000000000000000000000000000009BF0000000000000000000000000000000000000000000000000000000000000AC6000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000008D00000000000000000000000000000000000000000000000000000000000000B740000000000000000000000000000000000000000000000000000000000000B750000000000000000000000000000000000000000000000000000000000000AB2000000000000000000000000000000000000000000000000000000000000091700000000000000000000000000000000000000000000000000000000000008C40000000000000000000000000000000000000000000000000000000000000DBC000000000000000000000000000000000000000000000000000000000000056E0000000000000000000000000000000000000000000000000000000000000DAE0000000000000000000000000000000000000000000000000000000000000B18000000000000000000000000000000000000000000000000000000000000087D0000000000000000000000000000000000000000000000000000000000000B6F0000000000000000000000000000000000000000000000000000000000000B2000000000000000000000000000000000000000000000000000000000000008120000000000000000000000000000000000000000000000000000000000000AB60000000000000000000000000000000000000000000000000000000000000F700000000000000000000000000000000000000000000000000000000000000D1E00000000000000000000000000000000000000000000000000000000000000BF0000000000000000000000000000000000000000000000000000000000000D060000000000000000000000000000000000000000000000000000000000000A580000000000000000000000000000000000000000000000000000000000000B5C0000000000000000000000000000000000000000000000000000000000000AB300000000000000000000000000000000000000000000000000000000000000CF0000000000000000000000000000000000000000000000000000000000000B120000000000000000000000000000000000000000000000000000000000000EBE0000000000000000000000000000000000000000000000000000000000000ABC000000000000000000000000000000000000000000000000000000000000001A000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003C0000000000000000000000000000000000000000000000000000000000000044000000000000000000000000000000000000000000000000000000000000004C0000000000000000000000000000000000000000000000000000000000000054000000000000000000000000000000000000000000000000000000000000005C0000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000006C0000000000000000000000000000000000000000000000000000000000000074000000000000000000000000000000000000000000000000000000000000007C0000000000000000000000000000000000000000000000000000000000000084000000000000000000000000000000000000000000000000000000000000008C0000000000000000000000000000000000000000000000000000000000000094000000000000000000000000000000000000000000000000000000000000009C00000000000000000000000000000000000000000000000000000000000000A400000000000000000000000000000000000000000000000000000000000000AC00000000000000000000000000000000000000000000000000000000000000B400000000000000000000000000000000000000000000000000000000000000BC00000000000000000000000000000000000000000000000000000000000000C400000000000000000000000000000000000000000000000000000000000000CC00000000000000000000000000000000000000000000000000000000000000D400000000000000000000000000000000000000000000000000000000000000DC00000000000000000000000000000000000000000000000000000000000000E400000000000000000000000000000000000000000000000000000000000000EC00000000000000000000000000000000000000000000000000000000000000F400000000000000000000000000000000000000000000000000000000000000FC000000000000000000000000000000000000000000000000000000000000000410CA2FA0B6C6651E0B4665A7EB8C4037D255CF129BAEFF090B056EF5F67D47DD37120A8B311B7096FBE158C93B47194CA09DAB72B6CAC1513A7D490CFEEAE247A1B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041471DAA16525F41EECB9E61AE99223040BA37545A1EA96DDA773E6BB8C5A61B5464DDDB4E20EC3949B998200241DE9C49FB8045723B81BC78CC1FCBA9323ABD3D1C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000419067FB85D0C3E267F6D2FD61BD5085CD8846F38C3D32A5FD0B4C933F7264310208DB54AB2C078302EFABF9FAAA994F50AEC7DCD40F1D3B76205833F9EC89F5C51B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000419DD2D127717002EA2DC3A24DCB453725868BF777DD95EB9D819A82D884A3683A4269DEAE28C59B5486952972816BBD839D5C5A8203981042A45F81B6D4E7AB8D1B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000418CD6BC6C41F0D9A359E5ED006BB882168F46AAE3961EA52BD847DF222563EB6E4CEBCCFF59C368FDDC1B02C7A9FB57357E85309101CEF37B24FD233A9DC2CD951C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041B026E17268496BCD7E0E90DFA353C632830F315F49D71B17EFFE60122FAD8C717205C959BD739898B77BFB7B5F01ACEFF225D571B13CCB7930DDC918DBF8E76A1B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041BDBB56293271E82E2DDF84C9CAA10AE8138CA0DF93CD8FEC9B2A695CC75316C427F562BA3AD768F1FAD579BF399A2E7A026ADE257C4F88E7FC05D7F5D4BAA7271C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041765B7EDAAF3D91CA456A7040EEAB9A122465CD163DE4C555F90CF180F18DC2592C675D07CD38ED07E3957EE2F27A8F0FF590F9D2474C6CBD94D18EB0CBA574531B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041753A3323E4F6CCAA4BB0BAF40281043AC90BE1470AF1FECC90356595592F869203AF7A3F5527E09A0B99E82A19D913EC693E4591BEB204C9E9845339869C50111B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000413D33EB329CE91ECC31FE2C590DA36B08799A3629B253B563259AF136D5B030D1558C5E6B05675BDF7550ADF4021E7C0295AF605F5AE3293FD5199BE55D58E2B61C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041EDB75D628115598F05DC4163064613231DC433637426435783AA1A8F670970337630902AAA174EADC9B3844987BC79C8B10BC6E980417A1FF178B4AA5B2BA74E1C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041A8D6BE332CEE8F49179B1F541AE5736E24CABD52C5BDB2806B140C4C471A797A46D385DB66F31150C2DF589A0D1ED7EDE3FD31BB67EA67F2B2BB8B2F8C28C0261B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041C32AFA4116A29CB779E97F12F49B0822F7EC196902830B87917949C1B1F78034321DA225A22AC27D111B42DB1005A45ABF6FCE0E444356BE90EAE6F51EF8D4981B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041CA79B641C30D9DB1C60DCE0FD9D9BE7E32C90598568CAEA741B906F85DE1098C4B8CEB52784D573B50FA0DB64EAE0CB4DAE3CD71F1403E746AB60F246BAA37571B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000415CA6593BE8E2825708D87465C1258C1D9A30676A0A3FD1E060A516933AEFF8C46B2610B0890A8BE23EFB3D9A3F77D23D40001B71A844E280D9CAC544D587E0621C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041FA663E9713E92A0200A06F85B3F8CB7B5EEDC66D03D26F3B261BF5AE28A0125F6AD1CF590BEE65ACD381FE80175502B96E2ECCEB869285DCAA5D48B918E5DF611C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000415E93E331150D74E4F52D313C2C319D601B40B048CC61D4596DADD25623CA2FAA46BB4B032BB61D27B1327D1BB1BAC1624361005400D8F2D7302D19DA443A4CF71C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000411BE78602E005563C59658F690EBC1B87D82C8E39696848F50F8F60DD9DE67ABF245A6EC483E86631601650045D7A76732DBA5382DA27991850E4539949DE6C321C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041B363631B9DB1CA6F15C50D8DDB5B37B6E8893D5ECA4B1A86DDB5F9C7EA2E52F63952187B8DCABA0AB5EC8AC4C68CBE17AE3F7AD91584C65C27D3CFCD3135D5D91B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041FC55F600C048EFCCC2EA798D260197B1C393456028998CED16CBBFBF1B37F37E46F4E4FC0B5D57BDD41C751364F041FC3E0C1B38BCAF3DAAB28D5EE1DAC207A91B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410D80CEFA91265C781E9D0B2D30CE28150FCB6C2D454A638B240BDBD72BF5E92E3884FC1111AF437A7CE17E458E35686B7EAFD22CB6E7F94C37A3A971F7EA023B1B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000417005430F31A9C252B9A6A1FD529B6686150F1B1F4DB8D8B0E7107EDB83F7FFD278C41924C673EB86F3BC1E1774CAFB2DEAC18C2AE56AFB88E250F302B148669B1C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004175D64F85BB5850DF8F7ECDAADD5FBEFDB2762403EA8C58DB158C591441B50CA515D2ED000B648135C7DAF55C7AEC5670981B872D97252157583594F5848BD6D61B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041961BD26E9C9D015769509B38E7FA347CD4AD60CF1B5EA9864E77DFFC7A0ABC447CDD16C41DF4284D3153798ADB136D519CF4C92D8C3177806BCAA454068535131B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000419E2D6C8D56169E35C4EDF8A0234301AA4F5F2F1B185E23FF54E66F126161385978C8972E19A326CD0298536ABD46323A54B1B4F94202A7C699D58F7C920FE54D1B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000413016B94A10C4368BE9BE782104CB490CEB84F6644F3ADE773661CF465BF72A3B64EEFF82C73F1C0D37A4D0B5C0827C65B2F1769444FED45FE6F4954D302B0B251B00000000000000000000000000000000000000000000000000000000000000 )
    • AxelarAuthWeighted.validateProof( messageHash=81365954DE0E254174365D05139FDC9525D0C73A06C959ACD7E8A5E5EBE83EE4, proof=0x0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000135CE0000000000000000000000000000000000000000000000000000000000000D800000000000000000000000000000000000000000000000000000000000000033000000000000000000000000021D936762FDE8C622EC526E91408E9CF33B525600000000000000000000000003FE99104A9532F2727DB3AE31FD0CEB1188EFD00000000000000000000000000BF5AE5C4944A0E04D905B9F3BC9773C379EFC76000000000000000000000000123042337808EFC01C1AD7E506265F6F3756DC1900000000000000000000000013C1B3365B323FA2A4A0EAB145F98781A467521700000000000000000000000018E83FBA9969A4365CDE27F0CB30A61C9BBC467300000000000000000000000020B025C80D90C4CBD8F96A4852E8D986946DA60E00000000000000000000000021BDF788ED9A267B80280BEF415CC9C6A77AECFD0000000000000000000000002C2981DAF35371A38580EB685CB8F5137643434C0000000000000000000000002DF880D8CE5CE9CD8794187A822CED334A413B5D000000000000000000000000368E5E728DC48D13594F0D33334D9C283735BFCB0000000000000000000000003743F0BD81E54405C3273112C59DA102F702DAE40000000000000000000000003C549AD7A10887BF6C562512738713E7A96411DD00000000000000000000000045A83A274072E2BC99EAF2E80DA94E6F2C5D7DA6000000000000000000000000470D96B3513D6C63CD72C74F3681CE74B9FC639400000000000000000000000047507803BE195917EF141AB7B3AFA6D623535A32000000000000000000000000491FF43DE09F2B80CA92DF31BDF13855B0F4589C0000000000000000000000005222D090E999BB4DF82930EE233C02A3B8B4EB56000000000000000000000000540C87A42334DD6219C0AC7869F1D7C41BD3275400000000000000000000000055BEB9723BD5BC7226ED2E6D4F69476E65A0F7FA00000000000000000000000061946E5B9B8A231185937688E6AC232773FF8F000000000000000000000000006AF295171A45431325FC303F099782FA9526E0E60000000000000000000000006DD7998D0324D41B56DEE6215D588BD53F81828E000000000000000000000000737BFE757AD5A7A3451ABEBB612C3FE82286CDD3000000000000000000000000761E62677645DF454690F2FF7FBEABCB9C1184110000000000000000000000007B9B3D251E63E6A2937149BB93E7DC5E19C279DD0000000000000000000000007FFE9724BBDECE33E76D93C61A7EEB62AEF93BEF00000000000000000000000082E916A86F9AF6F58A65695D4378D4668AA367E70000000000000000000000008333AD83E30C3B7F969607994FC503E04EAEC615000000000000000000000000846A30460057EB4937369739C7BA5EE53041CDFF0000000000000000000000008CBDEB8E33676AC67222E791512C8E48E32EFED30000000000000000000000008CD3E02A4A3E26FC6416B8AEEBF71DD54FC8DB4200000000000000000000000094A847553D021DCF48A347CE1BBAA07F52C61D880000000000000000000000009539BAE27FC438841FC9239D769C051726B111580000000000000000000000009F27636B753A5FB7E710D28E336D087746C45633000000000000000000000000A08AFBE0249F85EA9EE03FE959155CCECA4C7914000000000000000000000000A6D985FD129440C87237E599D1F3EC4BA4AE51EC000000000000000000000000A8894919703FB09F295B85261FA3F87E02ABB57F000000000000000000000000AC380E34CF1E4AB0828900FFD91C184F8546CCEC000000000000000000000000B51B532603E57B829924F5B8696476153D30C9E8000000000000000000000000B8D60504ABEB077966E81B7936961C00736EB1FE000000000000000000000000C14385B5EA7ED5FE6F2695134D86C9772A520663000000000000000000000000C8998EF7B6D7B078A436F1CE0901520F5DB1464E000000000000000000000000D262A00AE2634FB38BE42378D140BA0A0FBB95C5000000000000000000000000EAB6E4115CE343CCCD6BD86E9CA03A7A2891E4CD000000000000000000000000EFB62752DA4F2D9FEC4E1911AF01B808264052AA000000000000000000000000F023857C179161F7D43AA2F9A3DF88E099B22280000000000000000000000000F04FC428343330869B7C9CC30A27CD494A83B869000000000000000000000000F2043DF655AD6E0291216656E598157025A8A7E9000000000000000000000000F75D8553954C360FA0BEFC9CBFC71E7D7D4BE139000000000000000000000000FC85C30E2381C86772B1A23F9BFB86C3B161683C0000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000090E00000000000000000000000000000000000000000000000000000000000008C7000000000000000000000000000000000000000000000000000000000000003A0000000000000000000000000000000000000000000000000000000000000B520000000000000000000000000000000000000000000000000000000000000AE50000000000000000000000000000000000000000000000000000000000000B13000000000000000000000000000000000000000000000000000000000000099A00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000A7C0000000000000000000000000000000000000000000000000000000000000AEA0000000000000000000000000000000000000000000000000000000000000A490000000000000000000000000000000000000000000000000000000000000C3C00000000000000000000000000000000000000000000000000000000000005850000000000000000000000000000000000000000000000000000000000000F0B0000000000000000000000000000000000000000000000000000000000000BA500000000000000000000000000000000000000000000000000000000000008BC000000000000000000000000000000000000000000000000000000000000034F0000000000000000000000000000000000000000000000000000000000000B170000000000000000000000000000000000000000000000000000000000000B1900000000000000000000000000000000000000000000000000000000000009300000000000000000000000000000000000000000000000000000000000000ADC0000000000000000000000000000000000000000000000000000000000000F7500000000000000000000000000000000000000000000000000000000000009BF0000000000000000000000000000000000000000000000000000000000000AC6000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000008D00000000000000000000000000000000000000000000000000000000000000B740000000000000000000000000000000000000000000000000000000000000B750000000000000000000000000000000000000000000000000000000000000AB2000000000000000000000000000000000000000000000000000000000000091700000000000000000000000000000000000000000000000000000000000008C40000000000000000000000000000000000000000000000000000000000000DBC000000000000000000000000000000000000000000000000000000000000056E0000000000000000000000000000000000000000000000000000000000000DAE0000000000000000000000000000000000000000000000000000000000000B18000000000000000000000000000000000000000000000000000000000000087D0000000000000000000000000000000000000000000000000000000000000B6F0000000000000000000000000000000000000000000000000000000000000B2000000000000000000000000000000000000000000000000000000000000008120000000000000000000000000000000000000000000000000000000000000AB60000000000000000000000000000000000000000000000000000000000000F700000000000000000000000000000000000000000000000000000000000000D1E00000000000000000000000000000000000000000000000000000000000000BF0000000000000000000000000000000000000000000000000000000000000D060000000000000000000000000000000000000000000000000000000000000A580000000000000000000000000000000000000000000000000000000000000B5C0000000000000000000000000000000000000000000000000000000000000AB300000000000000000000000000000000000000000000000000000000000000CF0000000000000000000000000000000000000000000000000000000000000B120000000000000000000000000000000000000000000000000000000000000EBE0000000000000000000000000000000000000000000000000000000000000ABC000000000000000000000000000000000000000000000000000000000000001A000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003C0000000000000000000000000000000000000000000000000000000000000044000000000000000000000000000000000000000000000000000000000000004C0000000000000000000000000000000000000000000000000000000000000054000000000000000000000000000000000000000000000000000000000000005C0000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000006C0000000000000000000000000000000000000000000000000000000000000074000000000000000000000000000000000000000000000000000000000000007C0000000000000000000000000000000000000000000000000000000000000084000000000000000000000000000000000000000000000000000000000000008C0000000000000000000000000000000000000000000000000000000000000094000000000000000000000000000000000000000000000000000000000000009C00000000000000000000000000000000000000000000000000000000000000A400000000000000000000000000000000000000000000000000000000000000AC00000000000000000000000000000000000000000000000000000000000000B400000000000000000000000000000000000000000000000000000000000000BC00000000000000000000000000000000000000000000000000000000000000C400000000000000000000000000000000000000000000000000000000000000CC00000000000000000000000000000000000000000000000000000000000000D400000000000000000000000000000000000000000000000000000000000000DC00000000000000000000000000000000000000000000000000000000000000E400000000000000000000000000000000000000000000000000000000000000EC00000000000000000000000000000000000000000000000000000000000000F400000000000000000000000000000000000000000000000000000000000000FC000000000000000000000000000000000000000000000000000000000000000410CA2FA0B6C6651E0B4665A7EB8C4037D255CF129BAEFF090B056EF5F67D47DD37120A8B311B7096FBE158C93B47194CA09DAB72B6CAC1513A7D490CFEEAE247A1B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041471DAA16525F41EECB9E61AE99223040BA37545A1EA96DDA773E6BB8C5A61B5464DDDB4E20EC3949B998200241DE9C49FB8045723B81BC78CC1FCBA9323ABD3D1C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000419067FB85D0C3E267F6D2FD61BD5085CD8846F38C3D32A5FD0B4C933F7264310208DB54AB2C078302EFABF9FAAA994F50AEC7DCD40F1D3B76205833F9EC89F5C51B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000419DD2D127717002EA2DC3A24DCB453725868BF777DD95EB9D819A82D884A3683A4269DEAE28C59B5486952972816BBD839D5C5A8203981042A45F81B6D4E7AB8D1B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000418CD6BC6C41F0D9A359E5ED006BB882168F46AAE3961EA52BD847DF222563EB6E4CEBCCFF59C368FDDC1B02C7A9FB57357E85309101CEF37B24FD233A9DC2CD951C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041B026E17268496BCD7E0E90DFA353C632830F315F49D71B17EFFE60122FAD8C717205C959BD739898B77BFB7B5F01ACEFF225D571B13CCB7930DDC918DBF8E76A1B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041BDBB56293271E82E2DDF84C9CAA10AE8138CA0DF93CD8FEC9B2A695CC75316C427F562BA3AD768F1FAD579BF399A2E7A026ADE257C4F88E7FC05D7F5D4BAA7271C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041765B7EDAAF3D91CA456A7040EEAB9A122465CD163DE4C555F90CF180F18DC2592C675D07CD38ED07E3957EE2F27A8F0FF590F9D2474C6CBD94D18EB0CBA574531B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041753A3323E4F6CCAA4BB0BAF40281043AC90BE1470AF1FECC90356595592F869203AF7A3F5527E09A0B99E82A19D913EC693E4591BEB204C9E9845339869C50111B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000413D33EB329CE91ECC31FE2C590DA36B08799A3629B253B563259AF136D5B030D1558C5E6B05675BDF7550ADF4021E7C0295AF605F5AE3293FD5199BE55D58E2B61C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041EDB75D628115598F05DC4163064613231DC433637426435783AA1A8F670970337630902AAA174EADC9B3844987BC79C8B10BC6E980417A1FF178B4AA5B2BA74E1C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041A8D6BE332CEE8F49179B1F541AE5736E24CABD52C5BDB2806B140C4C471A797A46D385DB66F31150C2DF589A0D1ED7EDE3FD31BB67EA67F2B2BB8B2F8C28C0261B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041C32AFA4116A29CB779E97F12F49B0822F7EC196902830B87917949C1B1F78034321DA225A22AC27D111B42DB1005A45ABF6FCE0E444356BE90EAE6F51EF8D4981B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041CA79B641C30D9DB1C60DCE0FD9D9BE7E32C90598568CAEA741B906F85DE1098C4B8CEB52784D573B50FA0DB64EAE0CB4DAE3CD71F1403E746AB60F246BAA37571B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000415CA6593BE8E2825708D87465C1258C1D9A30676A0A3FD1E060A516933AEFF8C46B2610B0890A8BE23EFB3D9A3F77D23D40001B71A844E280D9CAC544D587E0621C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041FA663E9713E92A0200A06F85B3F8CB7B5EEDC66D03D26F3B261BF5AE28A0125F6AD1CF590BEE65ACD381FE80175502B96E2ECCEB869285DCAA5D48B918E5DF611C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000415E93E331150D74E4F52D313C2C319D601B40B048CC61D4596DADD25623CA2FAA46BB4B032BB61D27B1327D1BB1BAC1624361005400D8F2D7302D19DA443A4CF71C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000411BE78602E005563C59658F690EBC1B87D82C8E39696848F50F8F60DD9DE67ABF245A6EC483E86631601650045D7A76732DBA5382DA27991850E4539949DE6C321C000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041B363631B9DB1CA6F15C50D8DDB5B37B6E8893D5ECA4B1A86DDB5F9C7EA2E52F63952187B8DCABA0AB5EC8AC4C68CBE17AE3F7AD91584C65C27D3CFCD3135D5D91B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041FC55F600C048EFCCC2EA798D260197B1C393456028998CED16CBBFBF1B37F37E46F4E4FC0B5D57BDD41C751364F041FC3E0C1B38BCAF3DAAB28D5EE1DAC207A91B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410D80CEFA91265C781E9D0B2D30CE28150FCB6C2D454A638B240BDBD72BF5E92E3884FC1111AF437A7CE17E458E35686B7EAFD22CB6E7F94C37A3A971F7EA023B1B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000417005430F31A9C252B9A6A1FD529B6686150F1B1F4DB8D8B0E7107EDB83F7FFD278C41924C673EB86F3BC1E1774CAFB2DEAC18C2AE56AFB88E250F302B148669B1C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004175D64F85BB5850DF8F7ECDAADD5FBEFDB2762403EA8C58DB158C591441B50CA515D2ED000B648135C7DAF55C7AEC5670981B872D97252157583594F5848BD6D61B000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041961BD26E9C9D015769509B38E7FA347CD4AD60CF1B5EA9864E77DFFC7A0ABC447CDD16C41DF4284D3153798ADB136D519CF4C92D8C3177806BCAA454068535131B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000419E2D6C8D56169E35C4EDF8A0234301AA4F5F2F1B185E23FF54E66F126161385978C8972E19A326CD0298536ABD46323A54B1B4F94202A7C699D58F7C920FE54D1B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000413016B94A10C4368BE9BE782104CB490CEB84F6644F3ADE773661CF465BF72A3B64EEFF82C73F1C0D37A4D0B5C0827C65B2F1769444FED45FE6F4954D302B0B251B00000000000000000000000000000000000000000000000000000000000000 ) => ( True )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Null: 0x000...001.81365954( )
      • Axelar: Gateway.585a9fd4( )
        • AxelarGateway.approveContractCallWithMint( params=0x00000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000CE16F69375520AB01377CE7B88F5BA8C48F8D666D3F86EC380012C9F05C3141B2D060C29A88E0C38A743292487AA5C8316A725C600000000000000000000000000000000000000000000000000000000000001A0000000000000000000000000000000000000000000000000000000000112E6DF57284FA896B2BB5B9B3C2595E34147018D3F1FEDAD44DA4137C5A7F5F3E3BC8D00000000000000000000000000000000000000000000000000000000004CAF0500000000000000000000000000000000000000000000000000000000000000076F736D6F73697300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003F6F736D6F316E366E657939747366353565747A396E726D7A79643877613765363471643373303661373466717333306B6138707073366376717473796372360000000000000000000000000000000000000000000000000000000000000000045553444300000000000000000000000000000000000000000000000000000000, commandId=3BB55EC3F284AFB1BAB7F062855A0E6311C08182812195190CC563C1B38583CD )
          File 1 of 2: AxelarGateway
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          import { IGovernable } from './IGovernable.sol';
          import { IImplementation } from './IImplementation.sol';
          interface IAxelarGateway is IImplementation, IGovernable {
              /**********\\
              |* Errors *|
              \\**********/
              error NotSelf();
              error InvalidCodeHash();
              error SetupFailed();
              error InvalidAuthModule();
              error InvalidTokenDeployer();
              error InvalidAmount();
              error InvalidChainId();
              error InvalidCommands();
              error TokenDoesNotExist(string symbol);
              error TokenAlreadyExists(string symbol);
              error TokenDeployFailed(string symbol);
              error TokenContractDoesNotExist(address token);
              error BurnFailed(string symbol);
              error MintFailed(string symbol);
              error InvalidSetMintLimitsParams();
              error ExceedMintLimit(string symbol);
              /**********\\
              |* Events *|
              \\**********/
              event TokenSent(
                  address indexed sender,
                  string destinationChain,
                  string destinationAddress,
                  string symbol,
                  uint256 amount
              );
              event ContractCall(
                  address indexed sender,
                  string destinationChain,
                  string destinationContractAddress,
                  bytes32 indexed payloadHash,
                  bytes payload
              );
              event ContractCallWithToken(
                  address indexed sender,
                  string destinationChain,
                  string destinationContractAddress,
                  bytes32 indexed payloadHash,
                  bytes payload,
                  string symbol,
                  uint256 amount
              );
              event Executed(bytes32 indexed commandId);
              event TokenDeployed(string symbol, address tokenAddresses);
              event ContractCallApproved(
                  bytes32 indexed commandId,
                  string sourceChain,
                  string sourceAddress,
                  address indexed contractAddress,
                  bytes32 indexed payloadHash,
                  bytes32 sourceTxHash,
                  uint256 sourceEventIndex
              );
              event ContractCallApprovedWithMint(
                  bytes32 indexed commandId,
                  string sourceChain,
                  string sourceAddress,
                  address indexed contractAddress,
                  bytes32 indexed payloadHash,
                  string symbol,
                  uint256 amount,
                  bytes32 sourceTxHash,
                  uint256 sourceEventIndex
              );
              event ContractCallExecuted(bytes32 indexed commandId);
              event TokenMintLimitUpdated(string symbol, uint256 limit);
              event OperatorshipTransferred(bytes newOperatorsData);
              event Upgraded(address indexed implementation);
              /********************\\
              |* Public Functions *|
              \\********************/
              function sendToken(
                  string calldata destinationChain,
                  string calldata destinationAddress,
                  string calldata symbol,
                  uint256 amount
              ) external;
              function callContract(
                  string calldata destinationChain,
                  string calldata contractAddress,
                  bytes calldata payload
              ) external;
              function callContractWithToken(
                  string calldata destinationChain,
                  string calldata contractAddress,
                  bytes calldata payload,
                  string calldata symbol,
                  uint256 amount
              ) external;
              function isContractCallApproved(
                  bytes32 commandId,
                  string calldata sourceChain,
                  string calldata sourceAddress,
                  address contractAddress,
                  bytes32 payloadHash
              ) external view returns (bool);
              function isContractCallAndMintApproved(
                  bytes32 commandId,
                  string calldata sourceChain,
                  string calldata sourceAddress,
                  address contractAddress,
                  bytes32 payloadHash,
                  string calldata symbol,
                  uint256 amount
              ) external view returns (bool);
              function validateContractCall(
                  bytes32 commandId,
                  string calldata sourceChain,
                  string calldata sourceAddress,
                  bytes32 payloadHash
              ) external returns (bool);
              function validateContractCallAndMint(
                  bytes32 commandId,
                  string calldata sourceChain,
                  string calldata sourceAddress,
                  bytes32 payloadHash,
                  string calldata symbol,
                  uint256 amount
              ) external returns (bool);
              /***********\\
              |* Getters *|
              \\***********/
              function authModule() external view returns (address);
              function tokenDeployer() external view returns (address);
              function tokenMintLimit(string memory symbol) external view returns (uint256);
              function tokenMintAmount(string memory symbol) external view returns (uint256);
              function allTokensFrozen() external view returns (bool);
              function implementation() external view returns (address);
              function tokenAddresses(string memory symbol) external view returns (address);
              function tokenFrozen(string memory symbol) external view returns (bool);
              function isCommandExecuted(bytes32 commandId) external view returns (bool);
              /************************\\
              |* Governance Functions *|
              \\************************/
              function setTokenMintLimits(string[] calldata symbols, uint256[] calldata limits) external;
              function upgrade(
                  address newImplementation,
                  bytes32 newImplementationCodeHash,
                  bytes calldata setupParams
              ) external;
              /**********************\\
              |* External Functions *|
              \\**********************/
              function execute(bytes calldata input) external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          // General interface for upgradable contracts
          interface IContractIdentifier {
              /**
               * @notice Returns the contract ID. It can be used as a check during upgrades.
               * @dev Meant to be overridden in derived contracts.
               * @return bytes32 The contract ID
               */
              function contractId() external pure returns (bytes32);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /**
           * @dev Interface of the ERC20 standard as defined in the EIP.
           */
          interface IERC20 {
              error InvalidAccount();
              /**
               * @dev Returns the amount of tokens in existence.
               */
              function totalSupply() external view returns (uint256);
              /**
               * @dev Returns the amount of tokens owned by `account`.
               */
              function balanceOf(address account) external view returns (uint256);
              /**
               * @dev Moves `amount` tokens from the caller's account to `recipient`.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * Emits a {Transfer} event.
               */
              function transfer(address recipient, uint256 amount) external returns (bool);
              /**
               * @dev Returns the remaining number of tokens that `spender` will be
               * allowed to spend on behalf of `owner` through {transferFrom}. This is
               * zero by default.
               *
               * This value changes when {approve} or {transferFrom} are called.
               */
              function allowance(address owner, address spender) external view returns (uint256);
              /**
               * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * IMPORTANT: Beware that changing an allowance with this method brings the risk
               * that someone may use both the old and the new allowance by unfortunate
               * transaction ordering. One possible solution to mitigate this race
               * condition is to first reduce the spender's allowance to 0 and set the
               * desired value afterwards:
               * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
               *
               * Emits an {Approval} event.
               */
              function approve(address spender, uint256 amount) external returns (bool);
              /**
               * @dev Moves `amount` tokens from `sender` to `recipient` using the
               * allowance mechanism. `amount` is then deducted from the caller's
               * allowance.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * Emits a {Transfer} event.
               */
              function transferFrom(
                  address sender,
                  address recipient,
                  uint256 amount
              ) external returns (bool);
              /**
               * @dev Emitted when `value` tokens are moved from one account (`from`) to
               * another (`to`).
               *
               * Note that `value` may be zero.
               */
              event Transfer(address indexed from, address indexed to, uint256 value);
              /**
               * @dev Emitted when the allowance of a `spender` for an `owner` is set by
               * a call to {approve}. `value` is the new allowance.
               */
              event Approval(address indexed owner, address indexed spender, uint256 value);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /**
           * @title IGovernable Interface
           * @notice This is an interface used by the AxelarGateway contract to manage governance and mint limiter roles.
           */
          interface IGovernable {
              error NotGovernance();
              error NotMintLimiter();
              error InvalidGovernance();
              error InvalidMintLimiter();
              event GovernanceTransferred(address indexed previousGovernance, address indexed newGovernance);
              event MintLimiterTransferred(address indexed previousGovernance, address indexed newGovernance);
              /**
               * @notice Returns the governance address.
               * @return address of the governance
               */
              function governance() external view returns (address);
              /**
               * @notice Returns the mint limiter address.
               * @return address of the mint limiter
               */
              function mintLimiter() external view returns (address);
              /**
               * @notice Transfer the governance role to another address.
               * @param newGovernance The new governance address
               */
              function transferGovernance(address newGovernance) external;
              /**
               * @notice Transfer the mint limiter role to another address.
               * @param newGovernance The new mint limiter address
               */
              function transferMintLimiter(address newGovernance) external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          import { IContractIdentifier } from './IContractIdentifier.sol';
          interface IImplementation is IContractIdentifier {
              error NotProxy();
              function setup(bytes calldata data) external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /**
           * @title IOwnable Interface
           * @notice IOwnable is an interface that abstracts the implementation of a
           * contract with ownership control features. It's commonly used in upgradable
           * contracts and includes the functionality to get current owner, transfer
           * ownership, and propose and accept ownership.
           */
          interface IOwnable {
              error NotOwner();
              error InvalidOwner();
              error InvalidOwnerAddress();
              event OwnershipTransferStarted(address indexed newOwner);
              event OwnershipTransferred(address indexed newOwner);
              /**
               * @notice Returns the current owner of the contract.
               * @return address The address of the current owner
               */
              function owner() external view returns (address);
              /**
               * @notice Returns the address of the pending owner of the contract.
               * @return address The address of the pending owner
               */
              function pendingOwner() external view returns (address);
              /**
               * @notice Transfers ownership of the contract to a new address
               * @param newOwner The address to transfer ownership to
               */
              function transferOwnership(address newOwner) external;
              /**
               * @notice Proposes to transfer the contract's ownership to a new address.
               * The new owner needs to accept the ownership explicitly.
               * @param newOwner The address to transfer ownership to
               */
              function proposeOwnership(address newOwner) external;
              /**
               * @notice Transfers ownership to the pending owner.
               * @dev Can only be called by the pending owner
               */
              function acceptOwnership() external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          library ContractAddress {
              function isContract(address contractAddress) internal view returns (bool) {
                  bytes32 existingCodeHash = contractAddress.codehash;
                  // https://eips.ethereum.org/EIPS/eip-1052
                  // keccak256('') == 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
                  return
                      existingCodeHash != bytes32(0) &&
                      existingCodeHash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          import { IERC20 } from '../interfaces/IERC20.sol';
          error TokenTransferFailed();
          /*
           * @title SafeTokenCall
           * @dev This library is used for performing safe token transfers.
           */
          library SafeTokenCall {
              /*
               * @notice Make a safe call to a token contract.
               * @param token The token contract to interact with.
               * @param callData The function call data.
               * @throws TokenTransferFailed error if transfer of token is not successful.
               */
              function safeCall(IERC20 token, bytes memory callData) internal {
                  (bool success, bytes memory returnData) = address(token).call(callData);
                  bool transferred = success && (returnData.length == uint256(0) || abi.decode(returnData, (bool)));
                  if (!transferred || address(token).code.length == 0) revert TokenTransferFailed();
              }
          }
          /*
           * @title SafeTokenTransfer
           * @dev This library safely transfers tokens from the contract to a recipient.
           */
          library SafeTokenTransfer {
              /*
               * @notice Transfer tokens to a recipient.
               * @param token The token contract.
               * @param receiver The recipient of the tokens.
               * @param amount The amount of tokens to transfer.
               */
              function safeTransfer(
                  IERC20 token,
                  address receiver,
                  uint256 amount
              ) internal {
                  SafeTokenCall.safeCall(token, abi.encodeWithSelector(IERC20.transfer.selector, receiver, amount));
              }
          }
          /*
           * @title SafeTokenTransferFrom
           * @dev This library helps to safely transfer tokens on behalf of a token holder.
           */
          library SafeTokenTransferFrom {
              /*
               * @notice Transfer tokens on behalf of a token holder.
               * @param token The token contract.
               * @param from The address of the token holder.
               * @param to The address the tokens are to be sent to.
               * @param amount The amount of tokens to be transferred.
               */
              function safeTransferFrom(
                  IERC20 token,
                  address from,
                  address to,
                  uint256 amount
              ) internal {
                  SafeTokenCall.safeCall(token, abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, amount));
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          import { IImplementation } from '../interfaces/IImplementation.sol';
          /**
           * @title Implementation
           * @notice This contract serves as a base for other contracts and enforces a proxy-first access restriction.
           * @dev Derived contracts must implement the setup function.
           */
          abstract contract Implementation is IImplementation {
              address private immutable implementationAddress;
              /**
               * @dev Contract constructor that sets the implementation address to the address of this contract.
               */
              constructor() {
                  implementationAddress = address(this);
              }
              /**
               * @dev Modifier to require the caller to be the proxy contract.
               * Reverts if the caller is the current contract (i.e., the implementation contract itself).
               */
              modifier onlyProxy() {
                  if (implementationAddress == address(this)) revert NotProxy();
                  _;
              }
              /**
               * @notice Initializes contract parameters.
               * This function is intended to be overridden by derived contracts.
               * The overriding function must have the onlyProxy modifier.
               * @param params The parameters to be used for initialization
               */
              function setup(bytes calldata params) external virtual;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol';
          import { IImplementation } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IImplementation.sol';
          import { IContractIdentifier } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IContractIdentifier.sol';
          import { IAxelarGateway } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol';
          import { SafeTokenCall, SafeTokenTransfer, SafeTokenTransferFrom } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/SafeTransfer.sol';
          import { ContractAddress } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/ContractAddress.sol';
          import { Implementation } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/upgradable/Implementation.sol';
          import { IAxelarAuth } from './interfaces/IAxelarAuth.sol';
          import { IBurnableMintableCappedERC20 } from './interfaces/IBurnableMintableCappedERC20.sol';
          import { ITokenDeployer } from './interfaces/ITokenDeployer.sol';
          import { ECDSA } from './ECDSA.sol';
          import { DepositHandler } from './DepositHandler.sol';
          import { EternalStorage } from './EternalStorage.sol';
          /**
           * @title AxelarGateway Contract
           * @notice This contract serves as the gateway for cross-chain contract calls,
           * and token transfers within the Axelar network.
           * It includes functions for sending tokens, calling contracts, and validating contract calls.
           * The contract is managed via the decentralized governance mechanism on the Axelar network.
           * @dev EternalStorage is used to simplify storage for upgradability, and InterchainGovernance module is used for governance.
           */
          contract AxelarGateway is IAxelarGateway, Implementation, EternalStorage {
              using SafeTokenCall for IERC20;
              using SafeTokenTransfer for IERC20;
              using SafeTokenTransferFrom for IERC20;
              using ContractAddress for address;
              error InvalidImplementation();
              enum TokenType {
                  InternalBurnable,
                  InternalBurnableFrom,
                  External
              }
              /**
               * @dev Deprecated slots. Should not be reused.
               */
              // bytes32 internal constant KEY_ALL_TOKENS_FROZEN = keccak256('all-tokens-frozen');
              // bytes32 internal constant PREFIX_TOKEN_FROZEN = keccak256('token-frozen');
              /**
               * @dev Storage slot with the address of the current implementation. `keccak256('eip1967.proxy.implementation') - 1`.
               */
              bytes32 internal constant KEY_IMPLEMENTATION = bytes32(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc);
              /**
               * @dev Storage slot with the address of the current governance. keccak256('governance')) - 1
               */
              bytes32 internal constant KEY_GOVERNANCE = bytes32(0xabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f909);
              /**
               * @dev Storage slot with the address of the current mint limiter. keccak256('mint-limiter')) - 1
               */
              bytes32 internal constant KEY_MINT_LIMITER = bytes32(0x627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d92);
              bytes32 internal constant PREFIX_COMMAND_EXECUTED = keccak256('command-executed');
              bytes32 internal constant PREFIX_TOKEN_ADDRESS = keccak256('token-address');
              bytes32 internal constant PREFIX_TOKEN_TYPE = keccak256('token-type');
              bytes32 internal constant PREFIX_CONTRACT_CALL_APPROVED = keccak256('contract-call-approved');
              bytes32 internal constant PREFIX_CONTRACT_CALL_APPROVED_WITH_MINT = keccak256('contract-call-approved-with-mint');
              bytes32 internal constant PREFIX_TOKEN_MINT_LIMIT = keccak256('token-mint-limit');
              bytes32 internal constant PREFIX_TOKEN_MINT_AMOUNT = keccak256('token-mint-amount');
              bytes32 internal constant SELECTOR_BURN_TOKEN = keccak256('burnToken');
              bytes32 internal constant SELECTOR_DEPLOY_TOKEN = keccak256('deployToken');
              bytes32 internal constant SELECTOR_MINT_TOKEN = keccak256('mintToken');
              bytes32 internal constant SELECTOR_APPROVE_CONTRACT_CALL = keccak256('approveContractCall');
              bytes32 internal constant SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT = keccak256('approveContractCallWithMint');
              bytes32 internal constant SELECTOR_TRANSFER_OPERATORSHIP = keccak256('transferOperatorship');
              address public immutable authModule;
              address public immutable tokenDeployer;
              /**
               * @notice Constructs the AxelarGateway contract.
               * @param authModule_ The address of the authentication module
               * @param tokenDeployer_ The address of the token deployer
               */
              constructor(address authModule_, address tokenDeployer_) {
                  if (authModule_.code.length == 0) revert InvalidAuthModule();
                  if (tokenDeployer_.code.length == 0) revert InvalidTokenDeployer();
                  authModule = authModule_;
                  tokenDeployer = tokenDeployer_;
              }
              /**
               * @notice Ensures that the caller of the function is the gateway contract itself.
               */
              modifier onlySelf() {
                  if (msg.sender != address(this)) revert NotSelf();
                  _;
              }
              /**
               * @notice Ensures that the caller of the function is the governance address.
               */
              modifier onlyGovernance() {
                  if (msg.sender != getAddress(KEY_GOVERNANCE)) revert NotGovernance();
                  _;
              }
              /**
               * @notice Ensures that the caller of the function is either the mint limiter or governance.
               */
              modifier onlyMintLimiter() {
                  if (msg.sender != getAddress(KEY_MINT_LIMITER) && msg.sender != getAddress(KEY_GOVERNANCE)) revert NotMintLimiter();
                  _;
              }
              /******************\\
              |* Public Methods *|
              \\******************/
              /**
               * @notice Send the specified token to the destination chain and address.
               * @param destinationChain The chain to send tokens to. A registered chain name on Axelar must be used here
               * @param destinationAddress The address on the destination chain to send tokens to
               * @param symbol The symbol of the token to send
               * @param amount The amount of tokens to send
               */
              function sendToken(
                  string calldata destinationChain,
                  string calldata destinationAddress,
                  string calldata symbol,
                  uint256 amount
              ) external {
                  _burnTokenFrom(msg.sender, symbol, amount);
                  emit TokenSent(msg.sender, destinationChain, destinationAddress, symbol, amount);
              }
              /**
               * @notice Calls a contract on the specified destination chain with a given payload.
               * This function is the entry point for general message passing between chains.
               * @param destinationChain The chain where the destination contract exists. A registered chain name on Axelar must be used here
               * @param destinationContractAddress The address of the contract to call on the destination chain
               * @param payload The payload to be sent to the destination contract, usually representing an encoded function call with arguments
               */
              function callContract(
                  string calldata destinationChain,
                  string calldata destinationContractAddress,
                  bytes calldata payload
              ) external {
                  emit ContractCall(msg.sender, destinationChain, destinationContractAddress, keccak256(payload), payload);
              }
              /**
               * @notice Calls a contract on the specified destination chain with a given payload and token amount.
               * This function is the entry point for general message passing with token transfer between chains.
               * @param destinationChain The chain where the destination contract exists. A registered chain name on Axelar must be used here
               * @param destinationContractAddress The address of the contract to call with tokens on the destination chain
               * @param payload The payload to be sent to the destination contract, usually representing an encoded function call with arguments
               * @param symbol The symbol of the token to be sent with the call
               * @param amount The amount of tokens to be sent with the call
               */
              function callContractWithToken(
                  string calldata destinationChain,
                  string calldata destinationContractAddress,
                  bytes calldata payload,
                  string calldata symbol,
                  uint256 amount
              ) external {
                  _burnTokenFrom(msg.sender, symbol, amount);
                  emit ContractCallWithToken(msg.sender, destinationChain, destinationContractAddress, keccak256(payload), payload, symbol, amount);
              }
              /**
               * @notice Checks whether a contract call has been approved by the gateway.
               * @param commandId The gateway command ID
               * @param sourceChain The source chain of the contract call
               * @param sourceAddress The source address of the contract call
               * @param contractAddress The contract address that will be called
               * @param payloadHash The hash of the payload for that will be sent with the call
               * @return bool A boolean value indicating whether the contract call has been approved by the gateway.
               */
              function isContractCallApproved(
                  bytes32 commandId,
                  string calldata sourceChain,
                  string calldata sourceAddress,
                  address contractAddress,
                  bytes32 payloadHash
              ) external view override returns (bool) {
                  return getBool(_getIsContractCallApprovedKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash));
              }
              /**
               * @notice Checks whether a contract call with token has been approved by the gateway.
               * @param commandId The gateway command ID
               * @param sourceChain The source chain of the contract call
               * @param sourceAddress The source address of the contract call
               * @param contractAddress The contract address that will be called, and where tokens will be sent
               * @param payloadHash The hash of the payload for that will be sent with the call
               * @param symbol The symbol of the token to be sent with the call
               * @param amount The amount of tokens to be sent with the call
               * @return bool A boolean value indicating whether the contract call with token has been approved by the gateway.
               */
              function isContractCallAndMintApproved(
                  bytes32 commandId,
                  string calldata sourceChain,
                  string calldata sourceAddress,
                  address contractAddress,
                  bytes32 payloadHash,
                  string calldata symbol,
                  uint256 amount
              ) external view override returns (bool) {
                  return
                      getBool(
                          _getIsContractCallApprovedWithMintKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, symbol, amount)
                      );
              }
              /**
               * @notice Called on the destination chain gateway by the recipient of the cross-chain contract call to validate it and only allow execution
               * if this function returns true.
               * @dev Once validated, the gateway marks the message as executed so the contract call is not executed twice.
               * @param commandId The gateway command ID
               * @param sourceChain The source chain of the contract call
               * @param sourceAddress The source address of the contract call
               * @param payloadHash The hash of the payload for that will be sent with the call
               * @return valid True if the contract call is approved, false otherwise
               */
              function validateContractCall(
                  bytes32 commandId,
                  string calldata sourceChain,
                  string calldata sourceAddress,
                  bytes32 payloadHash
              ) external override returns (bool valid) {
                  bytes32 key = _getIsContractCallApprovedKey(commandId, sourceChain, sourceAddress, msg.sender, payloadHash);
                  valid = getBool(key);
                  if (valid) {
                      _setBool(key, false);
                      emit ContractCallExecuted(commandId);
                  }
              }
              /**
               * @notice Called on the destination chain gateway to validate the approval of a contract call with token transfer and only
               * allow execution if this function returns true.
               * @dev Once validated, the gateway marks the message as executed so the contract call with token is not executed twice.
               * @param commandId The gateway command ID
               * @param sourceChain The source chain of the contract call
               * @param sourceAddress The source address of the contract call
               * @param payloadHash The hash of the payload for that will be sent with the call
               * @param symbol The symbol of the token to be sent with the call
               * @param amount The amount of tokens to be sent with the call
               * @return valid True if the contract call with token is approved, false otherwise
               */
              function validateContractCallAndMint(
                  bytes32 commandId,
                  string calldata sourceChain,
                  string calldata sourceAddress,
                  bytes32 payloadHash,
                  string calldata symbol,
                  uint256 amount
              ) external override returns (bool valid) {
                  bytes32 key = _getIsContractCallApprovedWithMintKey(commandId, sourceChain, sourceAddress, msg.sender, payloadHash, symbol, amount);
                  valid = getBool(key);
                  if (valid) {
                      // Prevent re-entrancy
                      _setBool(key, false);
                      emit ContractCallExecuted(commandId);
                      _mintToken(symbol, msg.sender, amount);
                  }
              }
              /***********\\
              |* Getters *|
              \\***********/
              /**
               * @notice Gets the address of governance, should be the address of InterchainGovernance.
               * @return address The address of governance.
               */
              function governance() public view override returns (address) {
                  return getAddress(KEY_GOVERNANCE);
              }
              /**
               * @notice Gets the address of the mint limiter, should be the address of Multisig.
               * @return address The address of the mint limiter.
               */
              function mintLimiter() public view override returns (address) {
                  return getAddress(KEY_MINT_LIMITER);
              }
              /**
               * @notice Gets the transfer limit for a specific token symbol within the configured epoch.
               * @param symbol The symbol of the token
               * @return uint The transfer limit for the given token.
               */
              function tokenMintLimit(string memory symbol) public view override returns (uint256) {
                  return getUint(_getTokenMintLimitKey(symbol));
              }
              /**
               * @notice Gets the transfer amount for a specific token symbol within the configured epoch.
               * @param symbol The symbol of the token
               * @return uint The transfer amount for the given token.
               */
              function tokenMintAmount(string memory symbol) public view override returns (uint256) {
                  return getUint(_getTokenMintAmountKey(symbol, block.timestamp / 6 hours));
              }
              /**
               * @dev This function is kept around to keep things working for internal
               * tokens that were deployed before the token freeze functionality was removed
               */
              function allTokensFrozen() external pure override returns (bool) {
                  return false;
              }
              /**
               * @notice Gets the address of the gateway implementation contract.
               * @return address The address of the gateway implementation.
               */
              function implementation() public view override returns (address) {
                  return getAddress(KEY_IMPLEMENTATION);
              }
              /**
               * @notice Gets the address of a specific token using its symbol.
               * @param symbol The symbol of the token
               * @return address The address of the token associated with the given symbol.
               */
              function tokenAddresses(string memory symbol) public view override returns (address) {
                  return getAddress(_getTokenAddressKey(symbol));
              }
              /**
               * @dev Deprecated. This function is kept around to keep things working for internal tokens that were deployed before the token freeze functionality was removed
               */
              function tokenFrozen(string memory) external pure override returns (bool) {
                  return false;
              }
              /**
               * @notice Checks whether a command with a given command ID has been executed.
               * @param commandId The command ID to check
               * @return bool True if the command has been executed, false otherwise
               */
              function isCommandExecuted(bytes32 commandId) public view override returns (bool) {
                  return getBool(_getIsCommandExecutedKey(commandId));
              }
              /**
               * @notice Gets the contract ID of the Axelar Gateway.
               * @return bytes32 The keccak256 hash of the string 'axelar-gateway'
               */
              function contractId() public pure returns (bytes32) {
                  return keccak256('axelar-gateway');
              }
              /************************\\
              |* Governance Functions *|
              \\************************/
              /**
               * @notice Transfers the governance role to a new address.
               * @param newGovernance The address to transfer the governance role to.
               * @dev Only the current governance entity can call this function.
               */
              function transferGovernance(address newGovernance) external override onlyGovernance {
                  if (newGovernance == address(0)) revert InvalidGovernance();
                  _transferGovernance(newGovernance);
              }
              /**
               * @notice Transfers the mint limiter role to a new address.
               * @param newMintLimiter The address to transfer the mint limiter role to.
               * @dev Only the current mint limiter or the governance address can call this function.
               */
              function transferMintLimiter(address newMintLimiter) external override onlyMintLimiter {
                  if (newMintLimiter == address(0)) revert InvalidMintLimiter();
                  _transferMintLimiter(newMintLimiter);
              }
              /**
               * @notice Sets the transfer limits for an array of tokens.
               * @param symbols The array of token symbols to set the transfer limits for
               * @param limits The array of transfer limits corresponding to the symbols
               * @dev Only the mint limiter or the governance address can call this function.
               */
              function setTokenMintLimits(string[] calldata symbols, uint256[] calldata limits) external override onlyMintLimiter {
                  uint256 length = symbols.length;
                  if (length != limits.length) revert InvalidSetMintLimitsParams();
                  for (uint256 i; i < length; ++i) {
                      string memory symbol = symbols[i];
                      uint256 limit = limits[i];
                      if (tokenAddresses(symbol) == address(0)) revert TokenDoesNotExist(symbol);
                      _setTokenMintLimit(symbol, limit);
                  }
              }
              /**
               * @notice Upgrades the contract to a new implementation.
               * @param newImplementation The address of the new implementation
               * @param newImplementationCodeHash The code hash of the new implementation
               * @param setupParams Optional setup params for the new implementation
               * @dev Only the governance address can call this function.
               */
              function upgrade(
                  address newImplementation,
                  bytes32 newImplementationCodeHash,
                  bytes calldata setupParams
              ) external override onlyGovernance {
                  if (newImplementationCodeHash != newImplementation.codehash) revert InvalidCodeHash();
                  if (contractId() != IContractIdentifier(newImplementation).contractId()) revert InvalidImplementation();
                  emit Upgraded(newImplementation);
                  _setImplementation(newImplementation);
                  if (setupParams.length != 0) {
                      // slither-disable-next-line controlled-delegatecall
                      (bool success, ) = newImplementation.delegatecall(abi.encodeWithSelector(IImplementation.setup.selector, setupParams));
                      if (!success) revert SetupFailed();
                  }
              }
              /**********************\\
              |* External Functions *|
              \\**********************/
              /**
               * @notice Sets up the governance and mint limiter roles, and transfers operatorship if necessary.
               * This function is called by the proxy during initial deployment, and optionally called during gateway upgrades.
               * @param params The encoded parameters containing the governance and mint limiter addresses, as well as the new operator data.
               * @dev Not publicly accessible as it's overshadowed in the proxy.
               */
              function setup(bytes calldata params) external override(IImplementation, Implementation) onlyProxy {
                  (address governance_, address mintLimiter_, bytes memory newOperatorsData) = abi.decode(params, (address, address, bytes));
                  if (governance_ != address(0)) _transferGovernance(governance_);
                  if (mintLimiter_ != address(0)) _transferMintLimiter(mintLimiter_);
                  if (newOperatorsData.length != 0) {
                      emit OperatorshipTransferred(newOperatorsData);
                      IAxelarAuth(authModule).transferOperatorship(newOperatorsData);
                  }
              }
              /**
               * @notice Executes a batch of commands signed by the Axelar network. There are a finite set of command types that can be executed.
               * @param input The encoded input containing the data for the batch of commands, as well as the proof that verifies the integrity of the data.
               * @dev Each command has a corresponding commandID that is guaranteed to be unique from the Axelar network.
               * @dev This function allows retrying a commandID if the command initially failed to be processed.
               * @dev Ignores unknown commands or duplicate commandIDs.
               * @dev Emits an Executed event for successfully executed commands.
               */
              // slither-disable-next-line cyclomatic-complexity
              function execute(bytes calldata input) external override {
                  (bytes memory data, bytes memory proof) = abi.decode(input, (bytes, bytes));
                  bytes32 messageHash = ECDSA.toEthSignedMessageHash(keccak256(data));
                  // returns true for current operators
                  // slither-disable-next-line reentrancy-no-eth
                  bool allowOperatorshipTransfer = IAxelarAuth(authModule).validateProof(messageHash, proof);
                  uint256 chainId;
                  bytes32[] memory commandIds;
                  string[] memory commands;
                  bytes[] memory params;
                  (chainId, commandIds, commands, params) = abi.decode(data, (uint256, bytes32[], string[], bytes[]));
                  if (chainId != block.chainid) revert InvalidChainId();
                  uint256 commandsLength = commandIds.length;
                  if (commandsLength != commands.length || commandsLength != params.length) revert InvalidCommands();
                  for (uint256 i; i < commandsLength; ++i) {
                      bytes32 commandId = commandIds[i];
                      // Ignore if duplicate commandId received
                      if (isCommandExecuted(commandId)) continue;
                      bytes4 commandSelector;
                      bytes32 commandHash = keccak256(abi.encodePacked(commands[i]));
                      if (commandHash == SELECTOR_DEPLOY_TOKEN) {
                          commandSelector = AxelarGateway.deployToken.selector;
                      } else if (commandHash == SELECTOR_MINT_TOKEN) {
                          commandSelector = AxelarGateway.mintToken.selector;
                      } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL) {
                          commandSelector = AxelarGateway.approveContractCall.selector;
                      } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT) {
                          commandSelector = AxelarGateway.approveContractCallWithMint.selector;
                      } else if (commandHash == SELECTOR_BURN_TOKEN) {
                          commandSelector = AxelarGateway.burnToken.selector;
                      } else if (commandHash == SELECTOR_TRANSFER_OPERATORSHIP) {
                          if (!allowOperatorshipTransfer) continue;
                          allowOperatorshipTransfer = false;
                          commandSelector = AxelarGateway.transferOperatorship.selector;
                      } else {
                          // Ignore unknown commands
                          continue;
                      }
                      // Prevent a re-entrancy from executing this command before it can be marked as successful.
                      _setCommandExecuted(commandId, true);
                      // slither-disable-next-line calls-loop,reentrancy-no-eth
                      (bool success, ) = address(this).call(abi.encodeWithSelector(commandSelector, params[i], commandId));
                      // slither-disable-next-line reentrancy-events
                      if (success) emit Executed(commandId);
                      else _setCommandExecuted(commandId, false);
                  }
              }
              /******************\\
              |* Self Functions *|
              \\******************/
              /**
               * @notice Deploys a new token or registers an existing token in the gateway contract itself.
               * @param params Encoded parameters including the token name, symbol, decimals, cap, token address, and mint limit
               * @dev If the token address is not specified, a new token is deployed and registed as InternalBurnableFrom
               * @dev If the token address is specified, the token is marked as External.
               * @dev Emits a TokenDeployed event with the symbol and token address.
               */
              function deployToken(bytes calldata params, bytes32) external onlySelf {
                  (string memory name, string memory symbol, uint8 decimals, uint256 cap, address tokenAddress, uint256 mintLimit) = abi.decode(
                      params,
                      (string, string, uint8, uint256, address, uint256)
                  );
                  // Ensure that this symbol has not been taken.
                  if (tokenAddresses(symbol) != address(0)) revert TokenAlreadyExists(symbol);
                  _setTokenMintLimit(symbol, mintLimit);
                  if (tokenAddress == address(0)) {
                      // If token address is not specified, it indicates a request to deploy one.
                      bytes32 salt = keccak256(abi.encodePacked(symbol));
                      _setTokenType(symbol, TokenType.InternalBurnableFrom);
                      // slither-disable-next-line reentrancy-no-eth,controlled-delegatecall
                      (bool success, bytes memory data) = tokenDeployer.delegatecall(
                          abi.encodeWithSelector(ITokenDeployer.deployToken.selector, name, symbol, decimals, cap, salt)
                      );
                      if (!success) revert TokenDeployFailed(symbol);
                      tokenAddress = abi.decode(data, (address));
                  } else {
                      // If token address is specified, ensure that there is a contact at the specified address.
                      if (tokenAddress.code.length == uint256(0)) revert TokenContractDoesNotExist(tokenAddress);
                      // Mark that this symbol is an external token, which is needed to differentiate between operations on mint and burn.
                      _setTokenType(symbol, TokenType.External);
                  }
                  // slither-disable-next-line reentrancy-events
                  emit TokenDeployed(symbol, tokenAddress);
                  _setTokenAddress(symbol, tokenAddress);
              }
              /**
               * @notice Transfers a specific amount of tokens to an account, based on the provided symbol.
               * @param params Encoded parameters including the token symbol, recipient address, and amount to mint.
               * @dev This function will revert if the token is not registered with the gatewaty.
               * @dev If the token type is External, a safe transfer is performed to the recipient account.
               * @dev If the token type is Internal (InternalBurnable or InternalBurnableFrom), the mint function is called on the token address.
               */
              function mintToken(bytes calldata params, bytes32) external onlySelf {
                  (string memory symbol, address account, uint256 amount) = abi.decode(params, (string, address, uint256));
                  _mintToken(symbol, account, amount);
              }
              /**
               * @notice Burns tokens of a given symbol, either through an external deposit handler or a token defined burn method.
               * @param params Encoded parameters including the token symbol and a salt value for the deposit handler
               */
              function burnToken(bytes calldata params, bytes32) external onlySelf {
                  (string memory symbol, bytes32 salt) = abi.decode(params, (string, bytes32));
                  address tokenAddress = tokenAddresses(symbol);
                  if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol);
                  if (_getTokenType(symbol) == TokenType.External) {
                      address depositHandlerAddress = _getCreate2Address(salt, keccak256(abi.encodePacked(type(DepositHandler).creationCode)));
                      if (depositHandlerAddress.isContract()) return;
                      DepositHandler depositHandler = new DepositHandler{ salt: salt }();
                      (bool success, bytes memory returnData) = depositHandler.execute(
                          tokenAddress,
                          abi.encodeWithSelector(IERC20.transfer.selector, address(this), IERC20(tokenAddress).balanceOf(address(depositHandler)))
                      );
                      if (!success || (returnData.length != uint256(0) && !abi.decode(returnData, (bool)))) revert BurnFailed(symbol);
                      // NOTE: `depositHandler` must always be destroyed in the same runtime context that it is deployed.
                      depositHandler.destroy(address(this));
                  } else {
                      IBurnableMintableCappedERC20(tokenAddress).burn(salt);
                  }
              }
              /**
               * @notice Approves a contract call.
               * @param params Encoded parameters including the source chain, source address, contract address, payload hash, transaction hash, and event index
               * @param commandId to associate with the approval
               */
              function approveContractCall(bytes calldata params, bytes32 commandId) external onlySelf {
                  (
                      string memory sourceChain,
                      string memory sourceAddress,
                      address contractAddress,
                      bytes32 payloadHash,
                      bytes32 sourceTxHash,
                      uint256 sourceEventIndex
                  ) = abi.decode(params, (string, string, address, bytes32, bytes32, uint256));
                  _setContractCallApproved(commandId, sourceChain, sourceAddress, contractAddress, payloadHash);
                  emit ContractCallApproved(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, sourceTxHash, sourceEventIndex);
              }
              /**
               * @notice Approves a contract call with token transfer.
               * @param params Encoded parameters including the source chain, source address, contract address, payload hash, token symbol,
               * token amount, transaction hash, and event index.
               * @param commandId to associate with the approval
               */
              function approveContractCallWithMint(bytes calldata params, bytes32 commandId) external onlySelf {
                  (
                      string memory sourceChain,
                      string memory sourceAddress,
                      address contractAddress,
                      bytes32 payloadHash,
                      string memory symbol,
                      uint256 amount,
                      bytes32 sourceTxHash,
                      uint256 sourceEventIndex
                  ) = abi.decode(params, (string, string, address, bytes32, string, uint256, bytes32, uint256));
                  _setContractCallApprovedWithMint(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, symbol, amount);
                  emit ContractCallApprovedWithMint(
                      commandId,
                      sourceChain,
                      sourceAddress,
                      contractAddress,
                      payloadHash,
                      symbol,
                      amount,
                      sourceTxHash,
                      sourceEventIndex
                  );
              }
              /**
               * @notice Transfers operatorship with the provided data by calling the transferOperatorship function on the auth module.
               * @param newOperatorsData Encoded data for the new operators
               */
              function transferOperatorship(bytes calldata newOperatorsData, bytes32) external onlySelf {
                  emit OperatorshipTransferred(newOperatorsData);
                  IAxelarAuth(authModule).transferOperatorship(newOperatorsData);
              }
              /********************\\
              |* Internal Methods *|
              \\********************/
              function _mintToken(
                  string memory symbol,
                  address account,
                  uint256 amount
              ) internal {
                  address tokenAddress = tokenAddresses(symbol);
                  if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol);
                  _setTokenMintAmount(symbol, tokenMintAmount(symbol) + amount);
                  if (_getTokenType(symbol) == TokenType.External) {
                      IERC20(tokenAddress).safeTransfer(account, amount);
                  } else {
                      IBurnableMintableCappedERC20(tokenAddress).mint(account, amount);
                  }
              }
              /**
               * @notice Burns or locks a specific amount of tokens from a sender's account based on the provided symbol.
               * @param sender Address of the account from which to burn the tokens
               * @param symbol Symbol of the token to burn
               * @param amount Amount of tokens to burn
               * @dev Depending on the token type (External, InternalBurnableFrom, or InternalBurnable), the function either
               * transfers the tokens to gateway contract itself or calls a burn function on the token contract.
               */
              function _burnTokenFrom(
                  address sender,
                  string memory symbol,
                  uint256 amount
              ) internal {
                  address tokenAddress = tokenAddresses(symbol);
                  if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol);
                  if (amount == 0) revert InvalidAmount();
                  TokenType tokenType = _getTokenType(symbol);
                  if (tokenType == TokenType.External) {
                      IERC20(tokenAddress).safeTransferFrom(sender, address(this), amount);
                  } else if (tokenType == TokenType.InternalBurnableFrom) {
                      IERC20(tokenAddress).safeCall(abi.encodeWithSelector(IBurnableMintableCappedERC20.burnFrom.selector, sender, amount));
                  } else {
                      IERC20(tokenAddress).safeTransferFrom(sender, IBurnableMintableCappedERC20(tokenAddress).depositAddress(bytes32(0)), amount);
                      IBurnableMintableCappedERC20(tokenAddress).burn(bytes32(0));
                  }
              }
              /********************\\
              |* Pure Key Getters *|
              \\********************/
              function _getTokenMintLimitKey(string memory symbol) internal pure returns (bytes32) {
                  return keccak256(abi.encodePacked(PREFIX_TOKEN_MINT_LIMIT, symbol));
              }
              function _getTokenMintAmountKey(string memory symbol, uint256 day) internal pure returns (bytes32) {
                  return keccak256(abi.encode(PREFIX_TOKEN_MINT_AMOUNT, symbol, day));
              }
              function _getTokenTypeKey(string memory symbol) internal pure returns (bytes32) {
                  return keccak256(abi.encodePacked(PREFIX_TOKEN_TYPE, symbol));
              }
              function _getTokenAddressKey(string memory symbol) internal pure returns (bytes32) {
                  return keccak256(abi.encodePacked(PREFIX_TOKEN_ADDRESS, symbol));
              }
              function _getIsCommandExecutedKey(bytes32 commandId) internal pure returns (bytes32) {
                  return keccak256(abi.encodePacked(PREFIX_COMMAND_EXECUTED, commandId));
              }
              function _getIsContractCallApprovedKey(
                  bytes32 commandId,
                  string memory sourceChain,
                  string memory sourceAddress,
                  address contractAddress,
                  bytes32 payloadHash
              ) internal pure returns (bytes32) {
                  return keccak256(abi.encode(PREFIX_CONTRACT_CALL_APPROVED, commandId, sourceChain, sourceAddress, contractAddress, payloadHash));
              }
              function _getIsContractCallApprovedWithMintKey(
                  bytes32 commandId,
                  string memory sourceChain,
                  string memory sourceAddress,
                  address contractAddress,
                  bytes32 payloadHash,
                  string memory symbol,
                  uint256 amount
              ) internal pure returns (bytes32) {
                  return
                      keccak256(
                          abi.encode(
                              PREFIX_CONTRACT_CALL_APPROVED_WITH_MINT,
                              commandId,
                              sourceChain,
                              sourceAddress,
                              contractAddress,
                              payloadHash,
                              symbol,
                              amount
                          )
                      );
              }
              /********************\\
              |* Internal Getters *|
              \\********************/
              function _getCreate2Address(bytes32 salt, bytes32 codeHash) internal view returns (address) {
                  return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, codeHash)))));
              }
              function _getTokenType(string memory symbol) internal view returns (TokenType) {
                  return TokenType(getUint(_getTokenTypeKey(symbol)));
              }
              /********************\\
              |* Internal Setters *|
              \\********************/
              function _setTokenMintLimit(string memory symbol, uint256 limit) internal {
                  emit TokenMintLimitUpdated(symbol, limit);
                  _setUint(_getTokenMintLimitKey(symbol), limit);
              }
              function _setTokenMintAmount(string memory symbol, uint256 amount) internal {
                  uint256 limit = tokenMintLimit(symbol);
                  if (limit > 0 && amount > limit) revert ExceedMintLimit(symbol);
                  _setUint(_getTokenMintAmountKey(symbol, block.timestamp / 6 hours), amount);
              }
              function _setTokenType(string memory symbol, TokenType tokenType) internal {
                  _setUint(_getTokenTypeKey(symbol), uint256(tokenType));
              }
              function _setTokenAddress(string memory symbol, address tokenAddress) internal {
                  _setAddress(_getTokenAddressKey(symbol), tokenAddress);
              }
              function _setCommandExecuted(bytes32 commandId, bool executed) internal {
                  _setBool(_getIsCommandExecutedKey(commandId), executed);
              }
              function _setContractCallApproved(
                  bytes32 commandId,
                  string memory sourceChain,
                  string memory sourceAddress,
                  address contractAddress,
                  bytes32 payloadHash
              ) internal {
                  _setBool(_getIsContractCallApprovedKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash), true);
              }
              function _setContractCallApprovedWithMint(
                  bytes32 commandId,
                  string memory sourceChain,
                  string memory sourceAddress,
                  address contractAddress,
                  bytes32 payloadHash,
                  string memory symbol,
                  uint256 amount
              ) internal {
                  _setBool(
                      _getIsContractCallApprovedWithMintKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, symbol, amount),
                      true
                  );
              }
              function _setImplementation(address newImplementation) internal {
                  _setAddress(KEY_IMPLEMENTATION, newImplementation);
              }
              function _transferGovernance(address newGovernance) internal {
                  emit GovernanceTransferred(getAddress(KEY_GOVERNANCE), newGovernance);
                  _setAddress(KEY_GOVERNANCE, newGovernance);
              }
              function _transferMintLimiter(address newMintLimiter) internal {
                  emit MintLimiterTransferred(getAddress(KEY_MINT_LIMITER), newMintLimiter);
                  _setAddress(KEY_MINT_LIMITER, newMintLimiter);
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.8.9;
          contract DepositHandler {
              error IsLocked();
              error NotContract();
              uint256 internal constant IS_NOT_LOCKED = uint256(1);
              uint256 internal constant IS_LOCKED = uint256(2);
              uint256 internal _lockedStatus = IS_NOT_LOCKED;
              modifier noReenter() {
                  if (_lockedStatus == IS_LOCKED) revert IsLocked();
                  _lockedStatus = IS_LOCKED;
                  _;
                  _lockedStatus = IS_NOT_LOCKED;
              }
              function execute(address callee, bytes calldata data) external noReenter returns (bool success, bytes memory returnData) {
                  if (callee.code.length == 0) revert NotContract();
                  (success, returnData) = callee.call(data);
              }
              // NOTE: The gateway should always destroy the `DepositHandler` in the same runtime context that deploys it.
              function destroy(address etherDestination) external noReenter {
                  selfdestruct(payable(etherDestination));
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.8.9;
          /**
           * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
           *
           * These functions can be used to verify that a message was signed by the holder
           * of the private keys of a given address.
           */
          library ECDSA {
              error InvalidSignatureLength();
              error InvalidS();
              error InvalidV();
              error InvalidSignature();
              /**
               * @dev Returns the address that signed a hashed message (`hash`) with
               * `signature`. This address can then be used for verification purposes.
               *
               * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
               * this function rejects them by requiring the `s` value to be in the lower
               * half order, and the `v` value to be either 27 or 28.
               *
               * IMPORTANT: `hash` _must_ be the result of a hash operation for the
               * verification to be secure: it is possible to craft signatures that
               * recover to arbitrary addresses for non-hashed data. A safe way to ensure
               * this is by receiving a hash of the original message (which may otherwise
               * be too long), and then calling {toEthSignedMessageHash} on it.
               */
              function recover(bytes32 hash, bytes memory signature) internal pure returns (address signer) {
                  // Check the signature length
                  if (signature.length != 65) revert InvalidSignatureLength();
                  // Divide the signature in r, s and v variables
                  bytes32 r;
                  bytes32 s;
                  uint8 v;
                  // ecrecover takes the signature parameters, and the only way to get them
                  // currently is to use assembly.
                  // solhint-disable-next-line no-inline-assembly
                  assembly {
                      r := mload(add(signature, 0x20))
                      s := mload(add(signature, 0x40))
                      v := byte(0, mload(add(signature, 0x60)))
                  }
                  // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
                  // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
                  // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most
                  // signatures from current libraries generate a unique signature with an s-value in the lower half order.
                  //
                  // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
                  // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
                  // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
                  // these malleable signatures as well.
                  if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) revert InvalidS();
                  if (v != 27 && v != 28) revert InvalidV();
                  // If the signature is valid (and not malleable), return the signer address
                  if ((signer = ecrecover(hash, v, r, s)) == address(0)) revert InvalidSignature();
              }
              /**
               * @dev Returns an Ethereum Signed Message, created from a `hash`. This
               * replicates the behavior of the
               * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`]
               * JSON-RPC method.
               *
               * See {recover}.
               */
              function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
                  // 32 is the length in bytes of hash,
                  // enforced by the type signature above
                  return keccak256(abi.encodePacked('\\x19Ethereum Signed Message:\
          32', hash));
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.8.9;
          /**
           * @title EternalStorage
           * @dev This contract holds all the necessary state variables to carry out the storage of any contract.
           */
          contract EternalStorage {
              mapping(bytes32 => uint256) private _uintStorage;
              mapping(bytes32 => string) private _stringStorage;
              mapping(bytes32 => address) private _addressStorage;
              mapping(bytes32 => bytes) private _bytesStorage;
              mapping(bytes32 => bool) private _boolStorage;
              mapping(bytes32 => int256) private _intStorage;
              // *** Getter Methods ***
              function getUint(bytes32 key) public view returns (uint256) {
                  return _uintStorage[key];
              }
              function getString(bytes32 key) public view returns (string memory) {
                  return _stringStorage[key];
              }
              function getAddress(bytes32 key) public view returns (address) {
                  return _addressStorage[key];
              }
              function getBytes(bytes32 key) public view returns (bytes memory) {
                  return _bytesStorage[key];
              }
              function getBool(bytes32 key) public view returns (bool) {
                  return _boolStorage[key];
              }
              function getInt(bytes32 key) public view returns (int256) {
                  return _intStorage[key];
              }
              // *** Setter Methods ***
              function _setUint(bytes32 key, uint256 value) internal {
                  _uintStorage[key] = value;
              }
              function _setString(bytes32 key, string memory value) internal {
                  _stringStorage[key] = value;
              }
              function _setAddress(bytes32 key, address value) internal {
                  _addressStorage[key] = value;
              }
              function _setBytes(bytes32 key, bytes memory value) internal {
                  _bytesStorage[key] = value;
              }
              function _setBool(bytes32 key, bool value) internal {
                  _boolStorage[key] = value;
              }
              function _setInt(bytes32 key, int256 value) internal {
                  _intStorage[key] = value;
              }
              // *** Delete Methods ***
              function _deleteUint(bytes32 key) internal {
                  delete _uintStorage[key];
              }
              function _deleteString(bytes32 key) internal {
                  delete _stringStorage[key];
              }
              function _deleteAddress(bytes32 key) internal {
                  delete _addressStorage[key];
              }
              function _deleteBytes(bytes32 key) internal {
                  delete _bytesStorage[key];
              }
              function _deleteBool(bytes32 key) internal {
                  delete _boolStorage[key];
              }
              function _deleteInt(bytes32 key) internal {
                  delete _intStorage[key];
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          import { IOwnable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IOwnable.sol';
          interface IAxelarAuth is IOwnable {
              function validateProof(bytes32 messageHash, bytes calldata proof) external returns (bool currentOperators);
              function transferOperatorship(bytes calldata params) external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.9;
          import { IERC20Burn } from './IERC20Burn.sol';
          import { IERC20BurnFrom } from './IERC20BurnFrom.sol';
          import { IMintableCappedERC20 } from './IMintableCappedERC20.sol';
          interface IBurnableMintableCappedERC20 is IERC20Burn, IERC20BurnFrom, IMintableCappedERC20 {
              function depositAddress(bytes32 salt) external view returns (address);
              function burn(bytes32 salt) external;
              function burnFrom(address account, uint256 amount) external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.9;
          /**
           * @dev Interface of the ERC20 standard as defined in the EIP.
           */
          interface IERC20 {
              error InvalidAccount();
              /**
               * @dev Returns the amount of tokens in existence.
               */
              function totalSupply() external view returns (uint256);
              /**
               * @dev Returns the amount of tokens owned by `account`.
               */
              function balanceOf(address account) external view returns (uint256);
              /**
               * @dev Moves `amount` tokens from the caller's account to `recipient`.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * Emits a {Transfer} event.
               */
              function transfer(address recipient, uint256 amount) external returns (bool);
              /**
               * @dev Returns the remaining number of tokens that `spender` will be
               * allowed to spend on behalf of `owner` through {transferFrom}. This is
               * zero by default.
               *
               * This value changes when {approve} or {transferFrom} are called.
               */
              function allowance(address owner, address spender) external view returns (uint256);
              /**
               * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * IMPORTANT: Beware that changing an allowance with this method brings the risk
               * that someone may use both the old and the new allowance by unfortunate
               * transaction ordering. One possible solution to mitigate this race
               * condition is to first reduce the spender's allowance to 0 and set the
               * desired value afterwards:
               * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
               *
               * Emits an {Approval} event.
               */
              function approve(address spender, uint256 amount) external returns (bool);
              /**
               * @dev Moves `amount` tokens from `sender` to `recipient` using the
               * allowance mechanism. `amount` is then deducted from the caller's
               * allowance.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * Emits a {Transfer} event.
               */
              function transferFrom(
                  address sender,
                  address recipient,
                  uint256 amount
              ) external returns (bool);
              /**
               * @dev Emitted when `value` tokens are moved from one account (`from`) to
               * another (`to`).
               *
               * Note that `value` may be zero.
               */
              event Transfer(address indexed from, address indexed to, uint256 value);
              /**
               * @dev Emitted when the allowance of a `spender` for an `owner` is set by
               * a call to {approve}. `value` is the new allowance.
               */
              event Approval(address indexed owner, address indexed spender, uint256 value);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.9;
          interface IERC20Burn {
              function burn(bytes32 salt) external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.9;
          interface IERC20BurnFrom {
              function burnFrom(address account, uint256 amount) external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.9;
          interface IERC20Permit {
              function DOMAIN_SEPARATOR() external view returns (bytes32);
              function nonces(address account) external view returns (uint256);
              function permit(
                  address issuer,
                  address spender,
                  uint256 value,
                  uint256 deadline,
                  uint8 v,
                  bytes32 r,
                  bytes32 s
              ) external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.9;
          import { IERC20 } from './IERC20.sol';
          import { IERC20Permit } from './IERC20Permit.sol';
          import { IOwnable } from './IOwnable.sol';
          interface IMintableCappedERC20 is IERC20, IERC20Permit, IOwnable {
              error CapExceeded();
              function cap() external view returns (uint256);
              function mint(address account, uint256 amount) external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.9;
          interface IOwnable {
              error NotOwner();
              error InvalidOwner();
              event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
              function owner() external view returns (address);
              function transferOwnership(address newOwner) external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          interface ITokenDeployer {
              function deployToken(
                  string calldata name,
                  string calldata symbol,
                  uint8 decimals,
                  uint256 cap,
                  bytes32 salt
              ) external returns (address tokenAddress);
          }
          

          File 2 of 2: AxelarAuthWeighted
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          /**
           * @title IOwnable Interface
           * @notice IOwnable is an interface that abstracts the implementation of a
           * contract with ownership control features. It's commonly used in upgradable
           * contracts and includes the functionality to get current owner, transfer
           * ownership, and propose and accept ownership.
           */
          interface IOwnable {
              error NotOwner();
              error InvalidOwner();
              error InvalidOwnerAddress();
              event OwnershipTransferStarted(address indexed newOwner);
              event OwnershipTransferred(address indexed newOwner);
              /**
               * @notice Returns the current owner of the contract.
               * @return address The address of the current owner
               */
              function owner() external view returns (address);
              /**
               * @notice Returns the address of the pending owner of the contract.
               * @return address The address of the pending owner
               */
              function pendingOwner() external view returns (address);
              /**
               * @notice Transfers ownership of the contract to a new address
               * @param newOwner The address to transfer ownership to
               */
              function transferOwnership(address newOwner) external;
              /**
               * @notice Proposes to transfer the contract's ownership to a new address.
               * The new owner needs to accept the ownership explicitly.
               * @param newOwner The address to transfer ownership to
               */
              function proposeOwnership(address newOwner) external;
              /**
               * @notice Transfers ownership to the pending owner.
               * @dev Can only be called by the pending owner
               */
              function acceptOwnership() external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          import { IOwnable } from '../interfaces/IOwnable.sol';
          /**
           * @title Ownable
           * @notice A contract module which provides a basic access control mechanism, where
           * there is an account (an owner) that can be granted exclusive access to
           * specific functions.
           *
           * The owner account is set through ownership transfer. This module makes
           * it possible to transfer the ownership of the contract to a new account in one
           * step, as well as to an interim pending owner. In the second flow the ownership does not
           * change until the pending owner accepts the ownership transfer.
           */
          abstract contract Ownable is IOwnable {
              // keccak256('owner')
              bytes32 internal constant _OWNER_SLOT = 0x02016836a56b71f0d02689e69e326f4f4c1b9057164ef592671cf0d37c8040c0;
              // keccak256('ownership-transfer')
              bytes32 internal constant _OWNERSHIP_TRANSFER_SLOT =
                  0x9855384122b55936fbfb8ca5120e63c6537a1ac40caf6ae33502b3c5da8c87d1;
              /**
               * @notice Initializes the contract by transferring ownership to the owner parameter.
               * @param _owner Address to set as the initial owner of the contract
               */
              constructor(address _owner) {
                  _transferOwnership(_owner);
              }
              /**
               * @notice Modifier that throws an error if called by any account other than the owner.
               */
              modifier onlyOwner() {
                  if (owner() != msg.sender) revert NotOwner();
                  _;
              }
              /**
               * @notice Returns the current owner of the contract.
               * @return owner_ The current owner of the contract
               */
              function owner() public view returns (address owner_) {
                  assembly {
                      owner_ := sload(_OWNER_SLOT)
                  }
              }
              /**
               * @notice Returns the pending owner of the contract.
               * @return owner_ The pending owner of the contract
               */
              function pendingOwner() public view returns (address owner_) {
                  assembly {
                      owner_ := sload(_OWNERSHIP_TRANSFER_SLOT)
                  }
              }
              /**
               * @notice Transfers ownership of the contract to a new account `newOwner`.
               * @dev Can only be called by the current owner.
               * @param newOwner The address to transfer ownership to
               */
              function transferOwnership(address newOwner) external virtual onlyOwner {
                  _transferOwnership(newOwner);
              }
              /**
               * @notice Propose to transfer ownership of the contract to a new account `newOwner`.
               * @dev Can only be called by the current owner. The ownership does not change
               * until the new owner accepts the ownership transfer.
               * @param newOwner The address to transfer ownership to
               */
              function proposeOwnership(address newOwner) external virtual onlyOwner {
                  if (newOwner == address(0)) revert InvalidOwnerAddress();
                  emit OwnershipTransferStarted(newOwner);
                  assembly {
                      sstore(_OWNERSHIP_TRANSFER_SLOT, newOwner)
                  }
              }
              /**
               * @notice Accepts ownership of the contract.
               * @dev Can only be called by the pending owner
               */
              function acceptOwnership() external virtual {
                  address newOwner = pendingOwner();
                  if (newOwner != msg.sender) revert InvalidOwner();
                  _transferOwnership(newOwner);
              }
              /**
               * @notice Internal function to transfer ownership of the contract to a new account `newOwner`.
               * @dev Called in the constructor to set the initial owner.
               * @param newOwner The address to transfer ownership to
               */
              function _transferOwnership(address newOwner) internal virtual {
                  if (newOwner == address(0)) revert InvalidOwnerAddress();
                  emit OwnershipTransferred(newOwner);
                  assembly {
                      sstore(_OWNER_SLOT, newOwner)
                      sstore(_OWNERSHIP_TRANSFER_SLOT, 0)
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          import { IAxelarAuthWeighted } from '../interfaces/IAxelarAuthWeighted.sol';
          import { ECDSA } from '../ECDSA.sol';
          import { Ownable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/utils/Ownable.sol';
          contract AxelarAuthWeighted is Ownable, IAxelarAuthWeighted {
              uint256 public currentEpoch;
              mapping(uint256 => bytes32) public hashForEpoch;
              mapping(bytes32 => uint256) public epochForHash;
              uint256 internal constant OLD_KEY_RETENTION = 16;
              constructor(bytes[] memory recentOperators) Ownable(msg.sender) {
                  uint256 length = recentOperators.length;
                  for (uint256 i; i < length; ++i) {
                      _transferOperatorship(recentOperators[i]);
                  }
              }
              /**************************\\
              |* External Functionality *|
              \\**************************/
              /// @dev This function takes messageHash and proof data and reverts if proof is invalid
              /// @return True if provided operators are the current ones
              function validateProof(bytes32 messageHash, bytes calldata proof) external view returns (bool) {
                  (address[] memory operators, uint256[] memory weights, uint256 threshold, bytes[] memory signatures) = abi.decode(
                      proof,
                      (address[], uint256[], uint256, bytes[])
                  );
                  bytes32 operatorsHash = keccak256(abi.encode(operators, weights, threshold));
                  uint256 operatorsEpoch = epochForHash[operatorsHash];
                  uint256 epoch = currentEpoch;
                  if (operatorsEpoch == 0 || epoch - operatorsEpoch >= OLD_KEY_RETENTION) revert InvalidOperators();
                  _validateSignatures(messageHash, operators, weights, threshold, signatures);
                  return operatorsEpoch == epoch;
              }
              /***********************\\
              |* Owner Functionality *|
              \\***********************/
              function transferOperatorship(bytes calldata params) external onlyOwner {
                  _transferOperatorship(params);
              }
              /**************************\\
              |* Internal Functionality *|
              \\**************************/
              function _transferOperatorship(bytes memory params) internal {
                  (address[] memory newOperators, uint256[] memory newWeights, uint256 newThreshold) = abi.decode(
                      params,
                      (address[], uint256[], uint256)
                  );
                  uint256 operatorsLength = newOperators.length;
                  uint256 weightsLength = newWeights.length;
                  // operators must be sorted binary or alphabetically in lower case
                  if (operatorsLength == 0 || !_isSortedAscAndContainsNoDuplicate(newOperators)) revert InvalidOperators();
                  if (weightsLength != operatorsLength) revert InvalidWeights();
                  uint256 totalWeight;
                  for (uint256 i; i < weightsLength; ++i) {
                      totalWeight = totalWeight + newWeights[i];
                  }
                  if (newThreshold == 0 || totalWeight < newThreshold) revert InvalidThreshold();
                  bytes32 newOperatorsHash = keccak256(params);
                  if (epochForHash[newOperatorsHash] != 0) revert DuplicateOperators();
                  uint256 epoch = currentEpoch + 1;
                  // slither-disable-next-line costly-loop
                  currentEpoch = epoch;
                  hashForEpoch[epoch] = newOperatorsHash;
                  epochForHash[newOperatorsHash] = epoch;
                  emit OperatorshipTransferred(newOperators, newWeights, newThreshold);
              }
              function _validateSignatures(
                  bytes32 messageHash,
                  address[] memory operators,
                  uint256[] memory weights,
                  uint256 threshold,
                  bytes[] memory signatures
              ) internal pure {
                  uint256 operatorsLength = operators.length;
                  uint256 signaturesLength = signatures.length;
                  uint256 operatorIndex;
                  uint256 weight;
                  // looking for signers within operators
                  // assuming that both operators and signatures are sorted
                  for (uint256 i; i < signaturesLength; ++i) {
                      address signer = ECDSA.recover(messageHash, signatures[i]);
                      // looping through remaining operators to find a match
                      for (; operatorIndex < operatorsLength && signer != operators[operatorIndex]; ++operatorIndex) {}
                      // checking if we are out of operators
                      if (operatorIndex == operatorsLength) revert MalformedSigners();
                      // accumulating signatures weight
                      weight = weight + weights[operatorIndex];
                      // weight needs to reach or surpass threshold
                      if (weight >= threshold) return;
                      // increasing operators index if match was found
                      ++operatorIndex;
                  }
                  // if weight sum below threshold
                  revert LowSignaturesWeight();
              }
              function _isSortedAscAndContainsNoDuplicate(address[] memory accounts) internal pure returns (bool) {
                  uint256 accountsLength = accounts.length;
                  address prevAccount = accounts[0];
                  if (prevAccount == address(0)) return false;
                  for (uint256 i = 1; i < accountsLength; ++i) {
                      address currAccount = accounts[i];
                      if (prevAccount >= currAccount) {
                          return false;
                      }
                      prevAccount = currAccount;
                  }
                  return true;
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.8.9;
          /**
           * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
           *
           * These functions can be used to verify that a message was signed by the holder
           * of the private keys of a given address.
           */
          library ECDSA {
              error InvalidSignatureLength();
              error InvalidS();
              error InvalidV();
              error InvalidSignature();
              /**
               * @dev Returns the address that signed a hashed message (`hash`) with
               * `signature`. This address can then be used for verification purposes.
               *
               * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
               * this function rejects them by requiring the `s` value to be in the lower
               * half order, and the `v` value to be either 27 or 28.
               *
               * IMPORTANT: `hash` _must_ be the result of a hash operation for the
               * verification to be secure: it is possible to craft signatures that
               * recover to arbitrary addresses for non-hashed data. A safe way to ensure
               * this is by receiving a hash of the original message (which may otherwise
               * be too long), and then calling {toEthSignedMessageHash} on it.
               */
              function recover(bytes32 hash, bytes memory signature) internal pure returns (address signer) {
                  // Check the signature length
                  if (signature.length != 65) revert InvalidSignatureLength();
                  // Divide the signature in r, s and v variables
                  bytes32 r;
                  bytes32 s;
                  uint8 v;
                  // ecrecover takes the signature parameters, and the only way to get them
                  // currently is to use assembly.
                  // solhint-disable-next-line no-inline-assembly
                  assembly {
                      r := mload(add(signature, 0x20))
                      s := mload(add(signature, 0x40))
                      v := byte(0, mload(add(signature, 0x60)))
                  }
                  // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
                  // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
                  // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most
                  // signatures from current libraries generate a unique signature with an s-value in the lower half order.
                  //
                  // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
                  // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
                  // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
                  // these malleable signatures as well.
                  if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) revert InvalidS();
                  if (v != 27 && v != 28) revert InvalidV();
                  // If the signature is valid (and not malleable), return the signer address
                  if ((signer = ecrecover(hash, v, r, s)) == address(0)) revert InvalidSignature();
              }
              /**
               * @dev Returns an Ethereum Signed Message, created from a `hash`. This
               * replicates the behavior of the
               * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`]
               * JSON-RPC method.
               *
               * See {recover}.
               */
              function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
                  // 32 is the length in bytes of hash,
                  // enforced by the type signature above
                  return keccak256(abi.encodePacked('\\x19Ethereum Signed Message:\
          32', hash));
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          import { IOwnable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IOwnable.sol';
          interface IAxelarAuth is IOwnable {
              function validateProof(bytes32 messageHash, bytes calldata proof) external returns (bool currentOperators);
              function transferOperatorship(bytes calldata params) external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.8.0;
          import { IAxelarAuth } from './IAxelarAuth.sol';
          interface IAxelarAuthWeighted is IAxelarAuth {
              error InvalidOperators();
              error InvalidThreshold();
              error DuplicateOperators();
              error MalformedSigners();
              error LowSignaturesWeight();
              error InvalidWeights();
              event OperatorshipTransferred(address[] newOperators, uint256[] newWeights, uint256 newThreshold);
              function currentEpoch() external view returns (uint256);
              function hashForEpoch(uint256 epoch) external view returns (bytes32);
              function epochForHash(bytes32 hash) external view returns (uint256);
          }