craft-nft

A standalone NFT implementation for real-world arts and crafts assets
Log | Files | Refs | README

commit 60b6c89c1451696a575372682f05251cdf54514a
parent 5c2d7031a4479153fffcd425149dab180db429e8
Author: lash <dev@holbrook.no>
Date:   Fri, 16 Dec 2022 20:06:14 +0000

Add ownership, single tokens, transfer

Diffstat:
Mpython/eth_craft_nft/data/CraftNFT.bin | 4++--
Mpython/eth_craft_nft/data/CraftNFT.json | 2+-
Apython/eth_craft_nft/error.py | 6++++++
Mpython/eth_craft_nft/nft.py | 88++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mpython/tests/test_basic.py | 183++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msolidity/CraftNFT.sol | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msolidity/Makefile | 4++--
7 files changed, 393 insertions(+), 36 deletions(-)

diff --git a/python/eth_craft_nft/data/CraftNFT.bin b/python/eth_craft_nft/data/CraftNFT.bin @@ -1 +1 @@ -60806040523480156200001157600080fd5b506040516200185e3803806200185e833981810160405281019062000037919062000236565b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550816006908162000088919062000506565b5080600790816200009a919062000506565b505050620005ed565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6200010c82620000c1565b810181811067ffffffffffffffff821117156200012e576200012d620000d2565b5b80604052505050565b600062000143620000a3565b905062000151828262000101565b919050565b600067ffffffffffffffff821115620001745762000173620000d2565b5b6200017f82620000c1565b9050602081019050919050565b60005b83811015620001ac5780820151818401526020810190506200018f565b60008484015250505050565b6000620001cf620001c98462000156565b62000137565b905082815260208101848484011115620001ee57620001ed620000bc565b5b620001fb8482856200018c565b509392505050565b600082601f8301126200021b576200021a620000b7565b5b81516200022d848260208601620001b8565b91505092915050565b6000806040838503121562000250576200024f620000ad565b5b600083015167ffffffffffffffff811115620002715762000270620000b2565b5b6200027f8582860162000203565b925050602083015167ffffffffffffffff811115620002a357620002a2620000b2565b5b620002b18582860162000203565b9150509250929050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200030e57607f821691505b602082108103620003245762000323620002c6565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026200038e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826200034f565b6200039a86836200034f565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b6000620003e7620003e1620003db84620003b2565b620003bc565b620003b2565b9050919050565b6000819050919050565b6200040383620003c6565b6200041b6200041282620003ee565b8484546200035c565b825550505050565b600090565b6200043262000423565b6200043f818484620003f8565b505050565b5b8181101562000467576200045b60008262000428565b60018101905062000445565b5050565b601f821115620004b65762000480816200032a565b6200048b846200033f565b810160208510156200049b578190505b620004b3620004aa856200033f565b83018262000444565b50505b505050565b600082821c905092915050565b6000620004db60001984600802620004bb565b1980831691505092915050565b6000620004f68383620004c8565b9150826002028217905092915050565b6200051182620002bb565b67ffffffffffffffff8111156200052d576200052c620000d2565b5b620005398254620002f5565b620005468282856200046b565b600060209050601f8311600181146200057e576000841562000569578287015190505b620005758582620004e8565b865550620005e5565b601f1984166200058e866200032a565b60005b82811015620005b85784890151825560018201915060208501945060208101905062000591565b86831015620005d85784890151620005d4601f891682620004c8565b8355505b6001600288020188555050505b505050505050565b61126180620005fd6000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c80637dd56411116100715780637dd56411146101c757806395d89b41146101f7578063a22cb46514610215578063bee2c0b514610231578063e985e9c514610261578063f9613ab214610291576100b4565b806301ffc9a7146100b957806306fdde03146100e9578063081812fc146101075780634d03546a146101375780635b1f1c6d1461016757806370a0823114610197575b600080fd5b6100d360048036038101906100ce9190610c29565b6102c1565b6040516100e09190610c71565b60405180910390f35b6100f16103a5565b6040516100fe9190610d1c565b60405180910390f35b610121600480360381019061011c9190610d74565b610433565b60405161012e9190610de2565b60405180910390f35b610151600480360381019061014c9190610e71565b610470565b60405161015e9190610c71565b60405180910390f35b610181600480360381019061017c9190610edd565b6105b6565b60405161018e9190610f53565b60405180910390f35b6101b160048036038101906101ac9190610f6e565b61067b565b6040516101be9190610faa565b60405180910390f35b6101e160048036038101906101dc9190610fc5565b610682565b6040516101ee9190610de2565b60405180910390f35b6101ff6106a2565b60405161020c9190610d1c565b60405180910390f35b61022f600480360381019061022a919061101e565b610730565b005b61024b6004803603810190610246919061105e565b6109d2565b60405161025891906110ca565b60405180910390f35b61027b600480360381019061027691906110e5565b610aad565b6040516102889190610c71565b60405180910390f35b6102ab60048036038101906102a69190610fc5565b610b45565b6040516102b89190610f53565b60405180910390f35b60006380ac58cd60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036102f957600190506103a0565b635b5e139f60e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361032f57600190506103a0565b63780e9d6360e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361036557600190506103a0565b6301ffc9a760e01b827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361039b57600190506103a0565b600090505b919050565b600680546103b290611154565b80601f01602080910402602001604051908101604052809291908181526020018280546103de90611154565b801561042b5780601f106104005761010080835404028352916020019161042b565b820191906000526020600020905b81548152906001019060200180831161040e57829003601f168201915b505050505081565b60006004600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146104cb57600080fd5b60006002600085815260200190815260200160002080549050111561054d5760006002600085815260200190815260200160002060008154811061051257610511611185565b5b90600052602060002090600591828204019190066006029054906101000a900465ffffffffffff1665ffffffffffff161161054c57600080fd5b5b600260008481526020019081526020016000208290806001815401808255809150506001900390600052602060002090600591828204019190066006029091909190916101000a81548165ffffffffffff021916908365ffffffffffff16021790555092915050565b600080600062ffffff60001b871690507f800000000000000000000000000000000000000000000000000000000000000060001b8117905060c881901b90508360601b6bffffffffffffffffffffffff1916811790507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000060001b871691508460d01b79ffffffffffffffffffffffffffffffffffffffffffffffffffff1916821791508060036000848152602001908152602001600020819055505050949350505050565b6000919050565b6000600360008381526020019081526020016000205460601c9050919050565b600780546106af90611154565b80601f01602080910402602001604051908101604052809291908181526020018280546106db90611154565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b505050505081565b801561085157600073ffffffffffffffffffffffffffffffffffffffff16600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146107ce57600080fd5b81600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610969565b600073ffffffffffffffffffffffffffffffffffffffff16600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16036108e957600080fd5b6000600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b8173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31836040516109c69190610c71565b60405180910390a35050565b6000808290505b6002600086815260200190815260200160002080549050811015610a8157836fffffffffffffffffffffffffffffffff16600260008781526020019081526020016000208281548110610a2f57610a2e611185565b5b90600052602060002090600591828204019190066006029054906101000a900465ffffffffffff1665ffffffffffff161115610a6e5780915050610aa6565b8080610a79906111e3565b9150506109d9565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90505b9392505050565b60008173ffffffffffffffffffffffffffffffffffffffff16600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614905092915050565b600080600360008481526020019081526020016000205490506000801b7f800000000000000000000000000000000000000000000000000000000000000060001b821611610b9257600080fd5b60c881901c90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000060001b83168117905080915050919050565b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b610c0681610bd1565b8114610c1157600080fd5b50565b600081359050610c2381610bfd565b92915050565b600060208284031215610c3f57610c3e610bcc565b5b6000610c4d84828501610c14565b91505092915050565b60008115159050919050565b610c6b81610c56565b82525050565b6000602082019050610c866000830184610c62565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610cc6578082015181840152602081019050610cab565b60008484015250505050565b6000601f19601f8301169050919050565b6000610cee82610c8c565b610cf88185610c97565b9350610d08818560208601610ca8565b610d1181610cd2565b840191505092915050565b60006020820190508181036000830152610d368184610ce3565b905092915050565b6000819050919050565b610d5181610d3e565b8114610d5c57600080fd5b50565b600081359050610d6e81610d48565b92915050565b600060208284031215610d8a57610d89610bcc565b5b6000610d9884828501610d5f565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610dcc82610da1565b9050919050565b610ddc81610dc1565b82525050565b6000602082019050610df76000830184610dd3565b92915050565b6000819050919050565b610e1081610dfd565b8114610e1b57600080fd5b50565b600081359050610e2d81610e07565b92915050565b600065ffffffffffff82169050919050565b610e4e81610e33565b8114610e5957600080fd5b50565b600081359050610e6b81610e45565b92915050565b60008060408385031215610e8857610e87610bcc565b5b6000610e9685828601610e1e565b9250506020610ea785828601610e5c565b9150509250929050565b610eba81610dc1565b8114610ec557600080fd5b50565b600081359050610ed781610eb1565b92915050565b60008060008060808587031215610ef757610ef6610bcc565b5b6000610f0587828801610e1e565b9450506020610f1687828801610d5f565b9350506040610f2787828801610e5c565b9250506060610f3887828801610ec8565b91505092959194509250565b610f4d81610dfd565b82525050565b6000602082019050610f686000830184610f44565b92915050565b600060208284031215610f8457610f83610bcc565b5b6000610f9284828501610ec8565b91505092915050565b610fa481610d3e565b82525050565b6000602082019050610fbf6000830184610f9b565b92915050565b600060208284031215610fdb57610fda610bcc565b5b6000610fe984828501610e1e565b91505092915050565b610ffb81610c56565b811461100657600080fd5b50565b60008135905061101881610ff2565b92915050565b6000806040838503121561103557611034610bcc565b5b600061104385828601610ec8565b925050602061105485828601611009565b9150509250929050565b60008060006060848603121561107757611076610bcc565b5b600061108586828701610e1e565b935050602061109686828701610d5f565b92505060406110a786828701610d5f565b9150509250925092565b6000819050919050565b6110c4816110b1565b82525050565b60006020820190506110df60008301846110bb565b92915050565b600080604083850312156110fc576110fb610bcc565b5b600061110a85828601610ec8565b925050602061111b85828601610ec8565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061116c57607f821691505b60208210810361117f5761117e611125565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006111ee82610d3e565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036112205761121f6111b4565b5b60018201905091905056fea2646970667358221220dc3bc927113728e44891d4d0268b66036150a17745558e7fc1242014e9c6f18464736f6c63430008110033 -\ No newline at end of file +60806040523480156200001157600080fd5b506040516200273338038062002733833981810160405281019062000037919062000236565b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600690816200008891906200050c565b5080600790816200009a91906200050c565b505050620005f3565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6200010c82620000c1565b810181811067ffffffffffffffff821117156200012e576200012d620000d2565b5b80604052505050565b600062000143620000a3565b905062000151828262000101565b919050565b600067ffffffffffffffff821115620001745762000173620000d2565b5b6200017f82620000c1565b9050602081019050919050565b60005b83811015620001ac5780820151818401526020810190506200018f565b60008484015250505050565b6000620001cf620001c98462000156565b62000137565b905082815260208101848484011115620001ee57620001ed620000bc565b5b620001fb8482856200018c565b509392505050565b600082601f8301126200021b576200021a620000b7565b5b81516200022d848260208601620001b8565b91505092915050565b6000806040838503121562000250576200024f620000ad565b5b600083015167ffffffffffffffff811115620002715762000270620000b2565b5b6200027f8582860162000203565b925050602083015167ffffffffffffffff811115620002a357620002a2620000b2565b5b620002b18582860162000203565b9150509250929050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200030e57607f821691505b602082108103620003245762000323620002c6565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b60008160020a8302905092915050565b600060088302620003917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826200034f565b6200039d86836200034f565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b6000620003ea620003e4620003de84620003b5565b620003bf565b620003b5565b9050919050565b6000819050919050565b6200040683620003c9565b6200041e6200041582620003f1565b8484546200035f565b825550505050565b600090565b6200043562000426565b62000442818484620003fb565b505050565b5b818110156200046a576200045e6000826200042b565b60018101905062000448565b5050565b601f821115620004b95762000483816200032a565b6200048e846200033f565b810160208510156200049e578190505b620004b6620004ad856200033f565b83018262000447565b50505b505050565b60008160020a8304905092915050565b6000620004e160001984600802620004be565b1980831691505092915050565b6000620004fc8383620004ce565b9150826002028217905092915050565b6200051782620002bb565b67ffffffffffffffff811115620005335762000532620000d2565b5b6200053f8254620002f5565b6200054c8282856200046e565b600060209050601f8311600181146200058457600084156200056f578287015190505b6200057b8582620004ee565b865550620005eb565b601f19841662000594866200032a565b60005b82811015620005be5784890151825560018201915060208501945060208101905062000597565b86831015620005de5784890151620005da601f891682620004ce565b8355505b6001600288020188555050505b505050505050565b61213080620006036000396000f3fe608060405260043610610147576000357c0100000000000000000000000000000000000000000000000000000000900480636352211e116100c8578063a22cb4651161008c578063a22cb46514610469578063b88d4fde14610492578063b9adc41b146104ae578063bee2c0b5146104eb578063e985e9c514610528578063f9613ab21461056557610147565b80636352211e1461035c57806370a08231146103995780638da5cb5b146103d657806395d89b4114610401578063a06561aa1461042c57610147565b806342842e0e1161010f57806342842e0e1461024a5780634d03546a146102665780634f64b2be146102a3578063559f5dc9146102e057806357cbf6921461031f57610147565b806301ffc9a71461014c57806306fdde0314610189578063081812fc146101b457806323b872dd146101f157806324e0febc1461020d575b600080fd5b34801561015857600080fd5b50610173600480360381019061016e91906117a3565b6105a2565b60405161018091906117eb565b60405180910390f35b34801561019557600080fd5b5061019e6106f6565b6040516101ab9190611896565b60405180910390f35b3480156101c057600080fd5b506101db60048036038101906101d691906118ee565b610784565b6040516101e8919061195c565b60405180910390f35b61020b600480360381019061020691906119a3565b6107c1565b005b34801561021957600080fd5b50610234600480360381019061022f9190611a2c565b610830565b6040516102419190611a68565b60405180910390f35b610264600480360381019061025f91906119a3565b610848565b005b34801561027257600080fd5b5061028d60048036038101906102889190611ac1565b6108b7565b60405161029a91906117eb565b60405180910390f35b3480156102af57600080fd5b506102ca60048036038101906102c591906118ee565b610a69565b6040516102d79190611a68565b60405180910390f35b3480156102ec57600080fd5b5061030760048036038101906103029190611b01565b610a8d565b60405161031693929190611b6c565b60405180910390f35b34801561032b57600080fd5b5061034660048036038101906103419190611ba3565b610b01565b6040516103539190611a68565b60405180910390f35b34801561036857600080fd5b50610383600480360381019061037e91906118ee565b610b8a565b604051610390919061195c565b60405180910390f35b3480156103a557600080fd5b506103c060048036038101906103bb9190611be3565b610bc6565b6040516103cd9190611c1f565b60405180910390f35b3480156103e257600080fd5b506103eb610bcd565b6040516103f8919061195c565b60405180910390f35b34801561040d57600080fd5b50610416610bf1565b6040516104239190611896565b60405180910390f35b34801561043857600080fd5b50610453600480360381019061044e9190611c3a565b610c7f565b6040516104609190611a68565b60405180910390f35b34801561047557600080fd5b50610490600480360381019061048b9190611cb9565b610e85565b005b6104ac60048036038101906104a79190611e2e565b611127565b005b3480156104ba57600080fd5b506104d560048036038101906104d09190611a2c565b6111fe565b6040516104e291906117eb565b60405180910390f35b3480156104f757600080fd5b50610512600480360381019061050d9190611eb1565b611230565b60405161051f9190611f1d565b60405180910390f35b34801561053457600080fd5b5061054f600480360381019061054a9190611f38565b611303565b60405161055c91906117eb565b60405180910390f35b34801561057157600080fd5b5061058c60048036038101906105879190611a2c565b61139b565b6040516105999190611a68565b60405180910390f35b60006380ac58cd7c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036105f657600190506106f1565b635b5e139f7c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361064857600190506106f1565b63780e9d637c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19160361069a57600190506106f1565b6301ffc9a77c010000000000000000000000000000000000000000000000000000000002827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036106ec57600190506106f1565b600090505b919050565b6006805461070390611fa7565b80601f016020809104026020016040519081016040528092919081815260200182805461072f90611fa7565b801561077c5780601f106107515761010080835404028352916020019161077c565b820191906000526020600020905b81548152906001019060200180831161075f57829003601f168201915b505050505081565b60006004600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b60606107cf84848484611408565b818373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a450505050565b60036020528060005260406000206000915090505481565b606061085684848484611408565b818373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a450505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461091257600080fd5b61091a611703565b6000600260008681526020019081526020016000208054905011156109945760006002600086815260200190815260200160002060008154811061096157610960611fd8565b5b9060005260206000200160000160019054906101000a900465ffffffffffff1665ffffffffffff161161099357600080fd5b5b82816020019065ffffffffffff16908165ffffffffffff168152505060026000858152602001908152602001600020819080600181540180825580915050600190039060005260206000200160009091909190915060008201518160000160006101000a81548160ff021916908360ff16021790555060208201518160000160016101000a81548165ffffffffffff021916908365ffffffffffff16021790555060408201518160000160076101000a81548165ffffffffffff021916908365ffffffffffff16021790555050505092915050565b60018181548110610a7957600080fd5b906000526020600020016000915090505481565b60026020528160005260406000208181548110610aa957600080fd5b90600052602060002001600091509150508060000160009054906101000a900460ff16908060000160019054906101000a900465ffffffffffff16908060000160079054906101000a900465ffffffffffff16905083565b6000806000600102600360008681526020019081526020016000205414610b2757600080fd5b8273ffffffffffffffffffffffffffffffffffffffff1690507f8000000000000000000000000000000000000000000000000000000000000000811790508060010260036000868152602001908152602001600020819055508391505092915050565b600080600360008460010281526020019081526020016000205490506060819060020a026c010000000000000000000000009004915050919050565b6000919050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60078054610bfe90611fa7565b80601f0160208091040260200160405190810160405280929190818152602001828054610c2a90611fa7565b8015610c775780601f10610c4c57610100808354040283529160200191610c77565b820191906000526020600020905b815481529060010190602001808311610c5a57829003601f168201915b505050505081565b600080600080600260008881526020019081526020016000208681548110610caa57610ca9611fd8565b5b90600052602060002001905060008160000160019054906101000a900465ffffffffffff1665ffffffffffff16148015610d02575060008160000160019054906101000a900465ffffffffffff1665ffffffffffff16145b15610d1b57610d118786610b01565b9350505050610e7e565b8060000160019054906101000a900465ffffffffffff1665ffffffffffff168160000160079054906101000a900465ffffffffffff1665ffffffffffff1610610d6357600080fd5b65ffffffffffff876001900416915060c8829060020a0291507f8000000000000000000000000000000000000000000000000000000000000000821791508473ffffffffffffffffffffffffffffffffffffffff16821791507fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000087600190041692506028869060020a02831792508060000160079054906101000a900465ffffffffffff1665ffffffffffff168317925081600102600360008560010281526020019081526020016000208190555060018160000160078282829054906101000a900465ffffffffffff16610e589190612036565b92506101000a81548165ffffffffffff021916908365ffffffffffff1602179055505050505b9392505050565b8015610fa657600073ffffffffffffffffffffffffffffffffffffffff16600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610f2357600080fd5b81600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506110be565b600073ffffffffffffffffffffffffffffffffffffffff16600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff160361103e57600080fd5b6000600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b8173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c318360405161111b91906117eb565b60405180910390a35050565b61113384848484611408565b818373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4818373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167f75c9e114f073c346aac7d1d7e9a3c3c14edabcdd27de07d1d9e425f45d318c5e60006001026040516111f09190611a68565b60405180910390a450505050565b6000807f8000000000000000000000000000000000000000000000000000000000000000836001900416119050919050565b6000808290505b60026000868152602001908152602001600020805490508110156112d757836fffffffffffffffffffffffffffffffff1660026000878152602001908152602001600020828154811061128d5761128c611fd8565b5b9060005260206000200160000160019054906101000a900465ffffffffffff1665ffffffffffff1611156112c457809150506112fc565b80806112cf90612070565b915050611237565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90505b9392505050565b60008173ffffffffffffffffffffffffffffffffffffffff16600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614905092915050565b600080600360008481526020019081526020016000205490506113bd816111fe565b6113c657600080fd5b60a081908060020a820491505090507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000060010283168117905080915050919050565b60003073ffffffffffffffffffffffffffffffffffffffff16636352211e846040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040161145f9190611c1f565b602060405180830381865afa15801561147c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114a091906120cd565b90508473ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146114da57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161461160e573373ffffffffffffffffffffffffffffffffffffffff166004600085815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16148061160457503373ffffffffffffffffffffffffffffffffffffffff16600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b61160d57600080fd5b5b60006004600085815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061166b8385611672565b5050505050565b6000808360010290506003600082815260200190815260200160002054600190049150600082036116a257600080fd5b7fffffffffffffffffffffffff0000000000000000000000000000000000000000821691508273ffffffffffffffffffffffffffffffffffffffff168217915081600102600360008381526020019081526020016000208190555050505050565b6040518060600160405280600060ff168152602001600065ffffffffffff168152602001600065ffffffffffff1681525090565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6117808161174b565b811461178b57600080fd5b50565b60008135905061179d81611777565b92915050565b6000602082840312156117b9576117b8611741565b5b60006117c78482850161178e565b91505092915050565b60008115159050919050565b6117e5816117d0565b82525050565b600060208201905061180060008301846117dc565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015611840578082015181840152602081019050611825565b60008484015250505050565b6000601f19601f8301169050919050565b600061186882611806565b6118728185611811565b9350611882818560208601611822565b61188b8161184c565b840191505092915050565b600060208201905081810360008301526118b0818461185d565b905092915050565b6000819050919050565b6118cb816118b8565b81146118d657600080fd5b50565b6000813590506118e8816118c2565b92915050565b60006020828403121561190457611903611741565b5b6000611912848285016118d9565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006119468261191b565b9050919050565b6119568161193b565b82525050565b6000602082019050611971600083018461194d565b92915050565b6119808161193b565b811461198b57600080fd5b50565b60008135905061199d81611977565b92915050565b6000806000606084860312156119bc576119bb611741565b5b60006119ca8682870161198e565b93505060206119db8682870161198e565b92505060406119ec868287016118d9565b9150509250925092565b6000819050919050565b611a09816119f6565b8114611a1457600080fd5b50565b600081359050611a2681611a00565b92915050565b600060208284031215611a4257611a41611741565b5b6000611a5084828501611a17565b91505092915050565b611a62816119f6565b82525050565b6000602082019050611a7d6000830184611a59565b92915050565b600065ffffffffffff82169050919050565b611a9e81611a83565b8114611aa957600080fd5b50565b600081359050611abb81611a95565b92915050565b60008060408385031215611ad857611ad7611741565b5b6000611ae685828601611a17565b9250506020611af785828601611aac565b9150509250929050565b60008060408385031215611b1857611b17611741565b5b6000611b2685828601611a17565b9250506020611b37858286016118d9565b9150509250929050565b600060ff82169050919050565b611b5781611b41565b82525050565b611b6681611a83565b82525050565b6000606082019050611b816000830186611b4e565b611b8e6020830185611b5d565b611b9b6040830184611b5d565b949350505050565b60008060408385031215611bba57611bb9611741565b5b6000611bc885828601611a17565b9250506020611bd98582860161198e565b9150509250929050565b600060208284031215611bf957611bf8611741565b5b6000611c078482850161198e565b91505092915050565b611c19816118b8565b82525050565b6000602082019050611c346000830184611c10565b92915050565b600080600060608486031215611c5357611c52611741565b5b6000611c6186828701611a17565b9350506020611c72868287016118d9565b9250506040611c838682870161198e565b9150509250925092565b611c96816117d0565b8114611ca157600080fd5b50565b600081359050611cb381611c8d565b92915050565b60008060408385031215611cd057611ccf611741565b5b6000611cde8582860161198e565b9250506020611cef85828601611ca4565b9150509250929050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b611d3b8261184c565b810181811067ffffffffffffffff82111715611d5a57611d59611d03565b5b80604052505050565b6000611d6d611737565b9050611d798282611d32565b919050565b600067ffffffffffffffff821115611d9957611d98611d03565b5b611da28261184c565b9050602081019050919050565b82818337600083830152505050565b6000611dd1611dcc84611d7e565b611d63565b905082815260208101848484011115611ded57611dec611cfe565b5b611df8848285611daf565b509392505050565b600082601f830112611e1557611e14611cf9565b5b8135611e25848260208601611dbe565b91505092915050565b60008060008060808587031215611e4857611e47611741565b5b6000611e568782880161198e565b9450506020611e678782880161198e565b9350506040611e78878288016118d9565b925050606085013567ffffffffffffffff811115611e9957611e98611746565b5b611ea587828801611e00565b91505092959194509250565b600080600060608486031215611eca57611ec9611741565b5b6000611ed886828701611a17565b9350506020611ee9868287016118d9565b9250506040611efa868287016118d9565b9150509250925092565b6000819050919050565b611f1781611f04565b82525050565b6000602082019050611f326000830184611f0e565b92915050565b60008060408385031215611f4f57611f4e611741565b5b6000611f5d8582860161198e565b9250506020611f6e8582860161198e565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680611fbf57607f821691505b602082108103611fd257611fd1611f78565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061204182611a83565b915061204c83611a83565b9250828201905065ffffffffffff81111561206a57612069612007565b5b92915050565b600061207b826118b8565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036120ad576120ac612007565b5b600182019050919050565b6000815190506120c781611977565b92915050565b6000602082840312156120e3576120e2611741565b5b60006120f1848285016120b8565b9150509291505056fea2646970667358221220ec1ffb70506a7ad118785abe9446feb1fa687f94705e74bb31570293793fca8064736f6c63430008110033 +\ No newline at end of file diff --git a/python/eth_craft_nft/data/CraftNFT.json b/python/eth_craft_nft/data/CraftNFT.json @@ -1 +1 @@ -[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":true,"internalType":"address","name":"_approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":true,"internalType":"address","name":"_operator","type":"address"},{"indexed":false,"internalType":"bool","name":"_approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"bytes32","name":"content","type":"bytes32"},{"internalType":"uint48","name":"count","type":"uint48"}],"name":"allocate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"content","type":"bytes32"},{"internalType":"uint256","name":"superIndex","type":"uint256"},{"internalType":"uint256","name":"startAt","type":"uint256"}],"name":"batchOf","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_truncatedId","type":"bytes32"}],"name":"getDigest","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"content","type":"bytes32"},{"internalType":"uint256","name":"batch","type":"uint256"},{"internalType":"uint48","name":"index","type":"uint48"},{"internalType":"address","name":"recipient","type":"address"}],"name":"mintFromBatchTo","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_tokenId","type":"bytes32"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}] +[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":true,"internalType":"address","name":"_approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":true,"internalType":"address","name":"_operator","type":"address"},{"indexed":false,"internalType":"bool","name":"_approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"_data","type":"bytes32"}],"name":"TransferWithData","type":"event"},{"inputs":[{"internalType":"bytes32","name":"content","type":"bytes32"},{"internalType":"uint48","name":"count","type":"uint48"}],"name":"allocate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_content","type":"bytes32"},{"internalType":"uint256","name":"_superIndex","type":"uint256"},{"internalType":"uint256","name":"_startAt","type":"uint256"}],"name":"batchOf","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_truncatedId","type":"bytes32"}],"name":"getDigest","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_tokenContent","type":"bytes32"}],"name":"isActiveContent","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_content","type":"bytes32"},{"internalType":"uint256","name":"_batch","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"mintFromBatchTo","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_content","type":"bytes32"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"mintTo","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"mintedToken","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"token","outputs":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"uint48","name":"count","type":"uint48"},{"internalType":"uint48","name":"cursor","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokens","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"}] diff --git a/python/eth_craft_nft/error.py b/python/eth_craft_nft/error.py @@ -0,0 +1,6 @@ +class InvalidBatchError(Exception): + pass + + +class SearchBoundError(Exception): + pass diff --git a/python/eth_craft_nft/nft.py b/python/eth_craft_nft/nft.py @@ -4,11 +4,22 @@ import os # external imports from chainlib.eth.tx import TxFormat from eth_erc721 import ERC721 -from hexathon import strip_0x +from hexathon import add_0x +from chainlib.eth.contract import ABIContractEncoder +from chainlib.eth.contract import ABIContractType +from chainlib.eth.contract import abi_decode_single +from chainlib.jsonrpc import JSONRPCRequest +from chainlib.eth.constant import ZERO_ADDRESS + +# local imports +from eth_craft_nft.error import InvalidBatchError moddir = os.path.dirname(__file__) datadir = os.path.join(moddir, 'data') +INVALID_BATCH = (2**256)-1 + + class CraftNFT(ERC721): @@ -48,3 +59,78 @@ class CraftNFT(ERC721): tx = self.set_code(tx, code) return self.finalize(tx, tx_format) + + def allocate(self, contract_address, sender_address, token_id, amount=0, tx_format=TxFormat.JSONRPC): + enc = ABIContractEncoder() + enc.method('allocate') + enc.typ(ABIContractType.BYTES32) + enc.typ(ABIContractType.UINT48) + enc.bytes32(token_id) + enc.uintn(amount, 48) + data = enc.get() + tx = self.template(sender_address, contract_address, use_nonce=True) + tx = self.set_code(tx, data) + tx = self.finalize(tx, tx_format) + return tx + + + def batch_of(self, contract_address, token_id, super_index, start_at=0, max_batches=0, sender_address=ZERO_ADDRESS, id_generator=None): + j = JSONRPCRequest(id_generator) + o = j.template() + o['method'] = 'eth_call' + enc = ABIContractEncoder() + enc.method('batchOf') + enc.typ(ABIContractType.BYTES32) + enc.typ(ABIContractType.UINT256) + enc.typ(ABIContractType.UINT256) + enc.bytes32(token_id) + enc.uint256(super_index) + enc.uint256(start_at) + data = add_0x(enc.get()) + tx = self.template(sender_address, contract_address) + tx = self.set_code(tx, data) + o['params'].append(self.normalize(tx)) + o['params'].append('latest') + o = j.finalize(o) + return o + + + def get_token_raw(self, contract_address, token_id, sender_address=ZERO_ADDRESS, id_generator=None): + j = JSONRPCRequest(id_generator) + o = j.template() + o['method'] = 'eth_call' + enc = ABIContractEncoder() + enc.method('mintedToken') + enc.typ(ABIContractType.BYTES32) + enc.bytes32(token_id) + data = add_0x(enc.get()) + tx = self.template(sender_address, contract_address) + tx = self.set_code(tx, data) + o['params'].append(self.normalize(tx)) + o['params'].append('latest') + o = j.finalize(o) + return o + + + def mint_to(self, contract_address, sender_address, token_id, batch, recipient, tx_format=TxFormat.JSONRPC): + enc = ABIContractEncoder() + enc.method('mintFromBatchTo') + enc.typ(ABIContractType.BYTES32) + enc.typ(ABIContractType.UINT256) + enc.typ(ABIContractType.ADDRESS) + enc.bytes32(token_id) + enc.uint256(batch) + enc.address(recipient) + data = enc.get() + tx = self.template(sender_address, contract_address, use_nonce=True) + tx = self.set_code(tx, data) + tx = self.finalize(tx, tx_format) + return tx + + + @classmethod + def parse_batch_of(self, v): + r = abi_decode_single(ABIContractType.UINT256, v) + if r == INVALID_BATCH: + raise InvalidBatchError() + return r diff --git a/python/tests/test_basic.py b/python/tests/test_basic.py @@ -18,6 +18,7 @@ from chainlib.eth.contract import ( abi_decode_single, ABIContractType, ) +from chainlib.eth.address import is_same_address from chainlib.error import JSONRPCException from chainlib.eth.constant import ZERO_ADDRESS from hexathon import ( @@ -28,12 +29,14 @@ from hexathon import ( # local imports from eth_craft_nft import CraftNFT +from eth_craft_nft.error import InvalidBatchError logging.basicConfig(level=logging.DEBUG) logg = logging.getLogger() testdir = os.path.dirname(__file__) +hash_of_foo = '2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae' class Test(EthTesterCase): @@ -50,8 +53,184 @@ class Test(EthTesterCase): r = self.conn.do(o) self.address = to_checksum_address(r['contract_address']) - def test_basic(self): - pass + def test_allocate(self): + nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) + c = CraftNFT(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) + (tx_hash_hex, o) = c.allocate(self.address, self.accounts[0], hash_of_foo, amount=0) + self.rpc.do(o) + o = receipt(tx_hash_hex) + r = self.conn.do(o) + self.assertEqual(r['status'], 1) + + + def test_allocate_batch(self): + nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) + c = CraftNFT(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) + (tx_hash_hex, o) = c.allocate(self.address, self.accounts[0], hash_of_foo, amount=10) + self.rpc.do(o) + o = receipt(tx_hash_hex) + r = self.conn.do(o) + self.assertEqual(r['status'], 1) + + + def test_batch_of(self): + nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) + c = CraftNFT(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) + (tx_hash_hex, o) = c.allocate(self.address, self.accounts[0], hash_of_foo, amount=10) + self.rpc.do(o) + + (tx_hash_hex, o) = c.allocate(self.address, self.accounts[0], hash_of_foo, amount=20) + self.rpc.do(o) + o = receipt(tx_hash_hex) + r = self.conn.do(o) + self.assertEqual(r['status'], 1) + + o = c.batch_of(self.address, hash_of_foo, 9, sender_address=self.accounts[0]) + r = self.rpc.do(o) + batch = c.parse_batch_of(r) + self.assertEqual(batch, 0) + + o = c.batch_of(self.address, hash_of_foo, 10, sender_address=self.accounts[0]) + r = self.rpc.do(o) + batch = c.parse_batch_of(r) + self.assertEqual(batch, 1) + + o = c.batch_of(self.address, hash_of_foo, 19, sender_address=self.accounts[0]) + r = self.rpc.do(o) + batch = c.parse_batch_of(r) + self.assertEqual(batch, 1) + + o = c.batch_of(self.address, hash_of_foo, 20, sender_address=self.accounts[0]) + r = self.rpc.do(o) + with self.assertRaises(InvalidBatchError): + batch = c.parse_batch_of(r) + + + def test_mint_to(self): + nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) + c = CraftNFT(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) + + (tx_hash_hex, o) = c.mint_to(self.address, self.accounts[0], hash_of_foo, 0, self.accounts[1]) + self.rpc.do(o) + o = receipt(tx_hash_hex) + r = self.conn.do(o) + self.assertEqual(r['status'], 0) + + (tx_hash_hex, o) = c.allocate(self.address, self.accounts[0], hash_of_foo, amount=20) + self.rpc.do(o) + o = receipt(tx_hash_hex) + r = self.conn.do(o) + self.assertEqual(r['status'], 1) + + (tx_hash_hex, o) = c.mint_to(self.address, self.accounts[0], hash_of_foo, 0, self.accounts[1]) + self.rpc.do(o) + o = receipt(tx_hash_hex) + r = self.conn.do(o) + self.assertEqual(r['status'], 1) + + + def test_mint_to_single(self): + nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) + c = CraftNFT(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) + + (tx_hash_hex, o) = c.mint_to(self.address, self.accounts[0], hash_of_foo, 0, self.accounts[1]) + self.rpc.do(o) + o = receipt(tx_hash_hex) + r = self.conn.do(o) + self.assertEqual(r['status'], 0) + + (tx_hash_hex, o) = c.allocate(self.address, self.accounts[0], hash_of_foo, amount=0) + self.rpc.do(o) + o = receipt(tx_hash_hex) + r = self.conn.do(o) + self.assertEqual(r['status'], 1) + + (tx_hash_hex, o) = c.mint_to(self.address, self.accounts[0], hash_of_foo, 0, self.accounts[1]) + self.rpc.do(o) + o = receipt(tx_hash_hex) + r = self.conn.do(o) + self.assertEqual(r['status'], 1) + + (tx_hash_hex, o) = c.mint_to(self.address, self.accounts[0], hash_of_foo, 0, self.accounts[1]) + self.rpc.do(o) + o = receipt(tx_hash_hex) + r = self.conn.do(o) + self.assertEqual(r['status'], 0) + + (tx_hash_hex, o) = c.mint_to(self.address, self.accounts[0], hash_of_foo, 0, self.accounts[2]) + self.rpc.do(o) + o = receipt(tx_hash_hex) + r = self.conn.do(o) + self.assertEqual(r['status'], 0) + + int_of_foo = int(hash_of_foo, 16) + o = c.owner_of(self.address, int_of_foo, sender_address=self.accounts[0]) + r = self.rpc.do(o) + owner = strip_0x(r) + self.assertTrue(is_same_address(owner[24:], self.accounts[1])) + + + + def test_mint_to_batch(self): + nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) + c = CraftNFT(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) + (tx_hash_hex, o) = c.allocate(self.address, self.accounts[0], hash_of_foo, amount=10) + self.rpc.do(o) + + (tx_hash_hex, o) = c.mint_to(self.address, self.accounts[0], hash_of_foo, 0, self.accounts[1]) + self.rpc.do(o) + o = receipt(tx_hash_hex) + r = self.conn.do(o) + self.assertEqual(r['status'], 1) + + expected_id = hash_of_foo[:64-10] + '0000000000' + o = c.get_token_raw(self.address, expected_id, sender_address=self.accounts[0]) + r = self.rpc.do(o) + + o = c.owner_of(self.address, int(expected_id, 16), sender_address=self.accounts[0]) + r = self.rpc.do(o) + owner = strip_0x(r) + self.assertTrue(is_same_address(owner[24:], self.accounts[1])) + + (tx_hash_hex, o) = c.mint_to(self.address, self.accounts[0], hash_of_foo, 0, self.accounts[2]) + self.rpc.do(o) + o = receipt(tx_hash_hex) + r = self.conn.do(o) + self.assertEqual(r['status'], 1) + + expected_id = hash_of_foo[:64-10] + '0000000001' + o = c.get_token_raw(self.address, expected_id, sender_address=self.accounts[0]) + r = self.rpc.do(o) + + o = c.owner_of(self.address, int(expected_id, 16), sender_address=self.accounts[0]) + r = self.rpc.do(o) + owner = strip_0x(r) + self.assertTrue(is_same_address(owner[24:], self.accounts[2])) + + + def test_transfer(self): + nonce_oracle = RPCNonceOracle(self.accounts[0], self.rpc) + c = CraftNFT(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) + + (tx_hash_hex, o) = c.allocate(self.address, self.accounts[0], hash_of_foo, amount=0) + self.rpc.do(o) + + (tx_hash_hex, o) = c.mint_to(self.address, self.accounts[0], hash_of_foo, 0, self.accounts[1]) + self.rpc.do(o) + + int_of_foo = int(hash_of_foo, 16) + nonce_oracle = RPCNonceOracle(self.accounts[1], self.rpc) + c = CraftNFT(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle) + (tx_hash, o) = c.transfer_from(self.address, self.accounts[1], self.accounts[1], self.accounts[2], int_of_foo) + self.rpc.do(o) + o = receipt(tx_hash_hex) + r = self.conn.do(o) + self.assertEqual(r['status'], 1) + + o = c.owner_of(self.address, int_of_foo, sender_address=self.accounts[0]) + r = self.rpc.do(o) + owner = strip_0x(r) + self.assertTrue(is_same_address(owner[24:], self.accounts[2])) if __name__ == '__main__': diff --git a/solidity/CraftNFT.sol b/solidity/CraftNFT.sol @@ -1,15 +1,21 @@ pragma solidity >= 0.8.0; + contract CraftNFT { - address owner; - bytes32[] tokens; - mapping(bytes32 => uint48[]) token; - mapping(bytes32 => bytes32) mintedToken; + struct tokenSpec { + uint8 v; + uint48 count; + uint48 cursor; + } + address public owner; + bytes32[] public tokens; + mapping(bytes32 => tokenSpec[]) public token; + mapping(bytes32 => bytes32) public mintedToken; mapping(uint256 => address) tokenAllowance; // backend for approve mapping(address => address) tokenOperator; // backend for setApprovalForAll - // ERC-721 (Metadata - optional) + // ERC-721 (Metadata - optional) string public name; // ERC-721 (Metadata - optional) @@ -22,6 +28,8 @@ contract CraftNFT { event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); // ERC-721 event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); + // ERC-721 + event TransferWithData(address indexed _from, address indexed _to, uint256 indexed _tokenId, bytes32 _data); constructor(string memory _name, string memory _symbol) { owner = msg.sender; @@ -29,13 +37,17 @@ contract CraftNFT { symbol = _symbol; } + function isActiveContent(bytes32 _tokenContent) public view returns(bool) { + return uint256(_tokenContent) & 0x8000000000000000000000000000000000000000000000000000000000000000 > 0; + } + function getDigest(bytes32 _truncatedId) public view returns (bytes32) { bytes32 digest; digest = mintedToken[_truncatedId]; - require(digest & 0x8000000000000000000000000000000000000000000000000000000000000000 > 0); + require(isActiveContent(digest)); - digest >>= 200; + digest >>= 160; digest |= _truncatedId & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000; return digest; } @@ -43,39 +55,72 @@ contract CraftNFT { // allocate a batch of tokens function allocate(bytes32 content, uint48 count) public returns (bool) { require(msg.sender == owner); + tokenSpec memory _token; + if (token[content].length > 0) { - require(token[content][0] > 0); + require(token[content][0].count > 0); } - token[content].push(count); - } - // ERC-721 - function ownerOf(bytes32 _tokenId) external view returns (address) { - return address(bytes20(mintedToken[_tokenId])); + _token.count = count; + token[content].push(_token); } - function batchOf(bytes32 content, uint256 superIndex, uint256 startAt) public view returns (int256) { - for (uint256 i = startAt; i < token[content].length; i++) { - if (token[content][i] > uint128(superIndex)) { + function batchOf(bytes32 _content, uint256 _superIndex, uint256 _startAt) public view returns(int256) { + for (uint256 i = _startAt; i < token[_content].length; i++) { + if (token[_content][i].count > uint128(_superIndex)) { return int256(i); } } return -1; } - function mintFromBatchTo(bytes32 content, uint256 batch, uint48 index, address recipient) public returns (bytes32) { - bytes32 left; - bytes32 right; + function mintTo(bytes32 _content, address _recipient) public returns (bytes32) { + uint256 right; + require(mintedToken[_content] == bytes32(0x00)); + + right = uint160(_recipient); + right |= (1 << 255); + mintedToken[_content] = bytes32(right); + + return _content; + } + + function setOwner(uint256 _tokenId, address _newOwner) private { + uint256 _data; + bytes32 _k; + + _k = bytes32(_tokenId); + + _data = uint256(mintedToken[_k]); + require(_data != 0); + + _data &= 0xffffffffffffffffffffffff0000000000000000000000000000000000000000; + _data |= uint160(_newOwner); + mintedToken[_k] = bytes32(_data); + } + + function mintFromBatchTo(bytes32 _content, uint256 _batch, address _recipient) public returns (bytes32) { + uint256 left; + uint256 right; + tokenSpec storage spec; + + spec = token[_content][_batch]; + if (spec.count == 0 && spec.count == 0) { + return mintTo(_content, _recipient); + } + require(spec.cursor < spec.count); - right = content & 0x0000000000000000000000000000000000000000000000000000000000ffffff; - right |= 0x8000000000000000000000000000000000000000000000000000000000000000; // "is defined" bit + right = uint256(_content) & ((1 << 48) - 1); right <<= 200; - right |= bytes20(recipient); + right |= (1 << 255); + right |= uint160(_recipient); - left = content & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000; - left |= bytes6(index); + left = uint256(_content) & 0xffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000; + left |= (_batch << 40); + left |= spec.cursor; - mintedToken[left] = right; + mintedToken[bytes32(left)] = bytes32(right); + spec.cursor += 1; } // ERC-721 @@ -106,9 +151,50 @@ contract CraftNFT { } // ERC-721 - //function ownerOf(uint256 _tokenId) external view returns (address) { - // return tokenOwner[_tokenId]; - //} + function ownerOf(uint256 _tokenId) external view returns (address) { + bytes32 _tokenContent; + + _tokenContent = mintedToken[bytes32(_tokenId)]; + return address(bytes20(_tokenContent << 96)); + } + + // shared function for transfer methods + function transferCore(address _from, address _to, uint256 _tokenId, bytes memory _data) internal { + address currentTokenOwner; + + currentTokenOwner = this.ownerOf(_tokenId); + + require(currentTokenOwner == _from); + if (_from != msg.sender) { + require(tokenAllowance[_tokenId] == msg.sender || tokenOperator[currentTokenOwner] == msg.sender); + } + + tokenAllowance[_tokenId] = address(0); + setOwner(_tokenId, _to); + } + + // ERC-721 + function transferFrom(address _from, address _to, uint256 _tokenId) external payable { + bytes memory _data; + + transferCore(_from, _to, _tokenId, _data); + emit Transfer(_from, _to, _tokenId); + } + + // ERC-721 + function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes memory _data) external payable { + transferCore(_from, _to, _tokenId, _data); + emit Transfer(_from, _to, _tokenId); + emit TransferWithData(_from, _to, _tokenId, bytes32(0x00)); //tokenData[_tokenId][tokenData[_tokenId].length-1]); + } + + // ERC-721 + function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable { + bytes memory _data; + + transferCore(_from, _to, _tokenId, _data); + emit Transfer(_from, _to, _tokenId); + } // EIP-165 function supportsInterface(bytes4 interfaceID) external pure returns (bool) { diff --git a/solidity/Makefile b/solidity/Makefile @@ -1,9 +1,9 @@ SOLC = /usr/bin/solc all: - $(SOLC) --bin CraftNFT.sol | awk 'NR>3' > CraftNFT.bin + $(SOLC) --bin CraftNFT.sol --evm-version byzantium | awk 'NR>3' > CraftNFT.bin truncate -s -1 CraftNFT.bin - $(SOLC) --abi CraftNFT.sol | awk 'NR>3' > CraftNFT.json + $(SOLC) --abi CraftNFT.sol --evm-version byzantium | awk 'NR>3' > CraftNFT.json install: all cp -v CraftNFT*{json,bin} ../python/eth_craft_nft/data/